Compare commits

...
Author SHA1 Message Date
frank 9a9ad0ccea feat!:enable sync fallback 2024-08-01 17:10:23 +08:00
Parvesh Monu a8a08c82b0 fix styling and navigation 2024-07-25 16:05:05 +05:30
Parvesh Monu aa28678188 lint and status-go update
https://github.com/status-im/status-go/compare/4a43b2b2...c39d9dc2
2024-07-25 15:11:58 +05:30
Parvesh Monu 67aa733736 Implement seed phrase fallback flow 2024-07-25 14:35:38 +05:30
Lungu Cristian cee21241d4 WalletConnect no internet edge-cases (#20826)
* feat: only initialize wc if internet online

* feat: no internet toast for session establishment

* feat: no internet banner on session requests

* feat: reloading walletconnect on connection change

* fix: re-initialize only when previously failed to

* fix: removed legacy net-info ns

* ref: renamed :network-status to :network/status

* ref: moved network subs to own "category"

* fix: device network fx args

* fix: tests & showing persisted dapps when offline

* fix: addressed review comments

* fix: rebase issues

* fix: linting

* fix: usage of web3-wallet (#20864)

* fix: moved networks to contextx and renaming

* ref: moved building supported namespaces into fx
2024-07-25 11:21:31 +03:00
Icaro Motta 60ad7c8a29 chore(tests): New match-strict? cljs.test directive (#20825)
Equality checks in tests using = give a bad experience by default on test
failures containing nested data structures. We use the cljs.test directive
match? from matcher-combinators library to help compare nested structures. The
problem with match? is that its default matcher for maps (embeds) can be too
permissive, and this causes surprises.

Here we upgrade matcher-combinators to latest, where a new matcher called
nested-equals is available. This matcher won't allow extra keys in maps. This
matcher eliminates the need for manually adding nested equals matchers as we
have to do currently.

- Upgrades matcher-combinators from 3.8.8 to 3.9.1 (latest as of 2024-07-19)

What changes?

When asserting in tests, we now have the option to use match-strict? or match?.
Both directives are available by integrating with cljs.test. The code
implementing the new match-strict? directive was 100% copied from the library
matcher-combinators because we need to wrap the expected value ourselves with
matcher-combinators.matchers/nested-equals. It's ugly code, but it's how we can
integrate with cljs.test/assert-expr.
2024-07-24 23:06:41 -03:00
Mohamed Javid 4989c92780 fix_: Adding own address as saved addresses (#20839)
This commit:

- prevents the user from saving their wallet address as the saved address
- fixes button not capturing taps when the keyboard is open in saved address flows

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-07-24 19:46:59 +05:30
41 changed files with 697 additions and 355 deletions
+2 -1
View File
@@ -74,7 +74,8 @@
;; https://github.com/borkdude/clj-kondo/issues/867 ;; https://github.com/borkdude/clj-kondo/issues/867
:unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY :unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY
number number
legacy.status-im.test-helpers/restore-app-db]} legacy.status-im.test-helpers/restore-app-db
(cljs.test/is [match-strict?])]}
:unresolved-var {:level :error} :unresolved-var {:level :error}
:unsorted-required-namespaces {:level :error} :unsorted-required-namespaces {:level :error}
:unused-alias {:level :warning} :unused-alias {:level :warning}
+3 -3
View File
@@ -711,11 +711,11 @@
}, },
{ {
"path": "nubank/matcher-combinators/3.8.8/matcher-combinators-3.8.8", "path": "nubank/matcher-combinators/3.9.1/matcher-combinators-3.9.1",
"host": "https://repo.clojars.org", "host": "https://repo.clojars.org",
"jar": { "jar": {
"sha1": "4c94bd510f0c18a20191e46dd6becedebc640bbd", "sha1": "f0830a112cae8ee931a90d9f39214a0ed4d44150",
"sha256": "0wpla2hx0s4mda58ndyd8938zmnz1gyhgfr6pzfphy27xfbvsssl" "sha256": "1rjcgqhms84xmnhs7sqcd3b2dpa37mmzgz2yz33yz2rdb9skl96g"
} }
}, },
+1 -1
View File
@@ -77,7 +77,7 @@ net/cgrand/macrovich/0.2.1/macrovich-0.2.1.jar
net/java/dev/jna/jna/5.12.1/jna-5.12.1.jar net/java/dev/jna/jna/5.12.1/jna-5.12.1.jar
nrepl/bencode/1.1.0/bencode-1.1.0.jar nrepl/bencode/1.1.0/bencode-1.1.0.jar
nrepl/nrepl/1.0.0/nrepl-1.0.0.jar nrepl/nrepl/1.0.0/nrepl-1.0.0.jar
nubank/matcher-combinators/3.8.8/matcher-combinators-3.8.8.jar nubank/matcher-combinators/3.9.1/matcher-combinators-3.9.1.jar
org/apache/ant/ant/1.10.11/ant-1.10.11.jar org/apache/ant/ant/1.10.11/ant-1.10.11.jar
org/apache/ant/ant-launcher/1.10.11/ant-launcher-1.10.11.jar org/apache/ant/ant-launcher/1.10.11/ant-launcher-1.10.11.jar
org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar
+1 -1
View File
@@ -19,7 +19,7 @@
[cider/piggieback "0.4.1"] [cider/piggieback "0.4.1"]
[org.slf4j/slf4j-nop "2.0.9"] [org.slf4j/slf4j-nop "2.0.9"]
[re-frisk-remote "1.6.0"] [re-frisk-remote "1.6.0"]
[nubank/matcher-combinators "3.8.8"] [nubank/matcher-combinators "3.9.1"]
;; Use the same version specified in the Nix dependency. ;; Use the same version specified in the Nix dependency.
[clj-kondo/clj-kondo "2024.03.13"] [clj-kondo/clj-kondo "2024.03.13"]
-1
View File
@@ -18,7 +18,6 @@
legacy.status-im.multiaccounts.logout.core legacy.status-im.multiaccounts.logout.core
[legacy.status-im.multiaccounts.model :as multiaccounts.model] [legacy.status-im.multiaccounts.model :as multiaccounts.model]
legacy.status-im.multiaccounts.update.core legacy.status-im.multiaccounts.update.core
legacy.status-im.network.net-info
legacy.status-im.pairing.core legacy.status-im.pairing.core
legacy.status-im.profile.core legacy.status-im.profile.core
legacy.status-im.search.core legacy.status-im.search.core
@@ -1,56 +0,0 @@
(ns legacy.status-im.network.net-info
(:require
["@react-native-community/netinfo" :default net-info]
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(rf/defn change-network-status
[{:keys [db] :as cofx} is-connected?]
(rf/merge cofx
{:db (assoc db :network-status (if is-connected? :online :offline))}))
(rf/defn change-network-type
[{:keys [db] :as cofx} network-type expensive?]
(rf/merge cofx
{:db (assoc db :network/type network-type)
:network/notify-status-go [network-type expensive?]
:dispatch [:mobile-network/on-network-status-change]}))
(rf/defn handle-network-info-change
{:events [::network-info-changed]}
[{:keys [db] :as cofx} {:keys [isConnected type details] :as state}]
(let [old-network-status (:network-status db)
old-network-type (:network/type db)
connectivity-status (if isConnected :online :offline)
status-changed? (= connectivity-status old-network-status)
type-changed? (= type old-network-type)]
(log/debug "[net-info]"
"old-network-status" old-network-status
"old-network-type" old-network-type
"connectivity-status" connectivity-status
"type" type
"details" details)
(rf/merge cofx
(when-not status-changed?
(change-network-status isConnected))
(when-not type-changed?
(change-network-type type (:is-connection-expensive details))))))
(defn add-net-info-listener
[]
(when net-info
(.addEventListener ^js net-info
#(re-frame/dispatch [::network-info-changed
(js->clj % :keywordize-keys true)]))))
(re-frame/reg-fx
:network/listen-to-network-info
(fn []
(add-net-info-listener)))
(re-frame/reg-fx
:network/notify-status-go
(fn [[network-type expensive?]]
(native-module/connection-change network-type expensive?)))
+29 -1
View File
@@ -4,6 +4,7 @@
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
[react-native.platform :as utils.platform] [react-native.platform :as utils.platform]
[status-im.common.json-rpc.events :as json-rpc] [status-im.common.json-rpc.events :as json-rpc]
[status-im.common.new-device-sheet.view :as new-device-sheet]
[status-im.config :as config] [status-im.config :as config]
[status-im.navigation.events :as navigation] [status-im.navigation.events :as navigation]
[taoensso.timbre :as log] [taoensso.timbre :as log]
@@ -220,6 +221,12 @@
:name (:name metadata) :name (:name metadata)
:device-type (:deviceType metadata))}) :device-type (:deviceType metadata))})
(defn should-show-syncing-pop-up?
[db installations]
(and (:syncing/pairing-process-initiated? db)
(first (filter #(not (get-in db [:pairing/installations (:id %)])) installations))))
(rf/defn handle-installations (rf/defn handle-installations
[{:keys [db]} installations] [{:keys [db]} installations]
{:db (update db {:db (update db
@@ -228,7 +235,10 @@
(fn [acc {:keys [id] :as i}] (fn [acc {:keys [id] :as i}]
(update acc id merge (installation<-rpc i))) (update acc id merge (installation<-rpc i)))
% %
installations))}) installations))
:fx [(when-let [new-installation (should-show-syncing-pop-up? db installations)]
[:dispatch
[:show-bottom-sheet {:content (fn [] [new-device-sheet/view (:id new-installation)])}]])]})
(rf/defn load-installations (rf/defn load-installations
{:events [:pairing.callback/get-our-installations-success]} {:events [:pairing.callback/get-our-installations-success]}
@@ -243,6 +253,24 @@
{} {}
installations))}) installations))})
(rf/defn finish-seed-phrase-fallback-syncing
{:events [:pairing/finish-seed-phrase-fallback-syncing]}
[{:keys [db]}]
{:fx [[:dispatch [:show-bottom-sheet {:content (fn [] [new-device-sheet/view-2])}]]
[:json-rpc/call
[{:method "wakuext_finishPairingThroughSeedPhraseProcess"
:params [{:installationId (:syncing/installation-id db)}]
:js-response true
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])}]]]})
(rf/defn pair-and-sync
{:events [:pairing/pair-and-sync]}
[cofx installation-id]
{:fx [[:json-rpc/call
[{:method "wakuext_enableAndSyncInstallation"
:params [{:installationId installation-id}]
:on-success #(log/debug "successfully synced devices")}]]]})
(rf/defn enable-installation-success (rf/defn enable-installation-success
{:events [:pairing.callback/enable-installation-success]} {:events [:pairing.callback/enable-installation-success]}
[cofx installation-id] [cofx installation-id]
-2
View File
@@ -15,8 +15,6 @@
(reg-root-key-sub :visibility-status-updates :visibility-status-updates) (reg-root-key-sub :visibility-status-updates :visibility-status-updates)
(reg-root-key-sub :fleets/custom-fleets :custom-fleets) (reg-root-key-sub :fleets/custom-fleets :custom-fleets)
(reg-root-key-sub :ui/search :ui/search) (reg-root-key-sub :ui/search :ui/search)
(reg-root-key-sub :network/type :network/type)
(reg-root-key-sub :network-status :network-status)
(reg-root-key-sub :peer-stats/count :peer-stats/count) (reg-root-key-sub :peer-stats/count :peer-stats/count)
(reg-root-key-sub :peers-summary :peers-summary) (reg-root-key-sub :peers-summary :peers-summary)
(reg-root-key-sub :web3-node-version :web3-node-version) (reg-root-key-sub :web3-node-version :web3-node-version)
+1 -1
View File
@@ -127,7 +127,7 @@
[:app-state [:app-state
:current-chat-id :current-chat-id
:network :network
:network-status :network/status
:peers-summary :peers-summary
:sync-state :sync-state
:view-id :view-id
+1 -1
View File
@@ -171,7 +171,7 @@
#js #js
{:getEnforcing {}}) {:getEnforcing {}})
(def net-info #js {}) (def net-info #js {:addEventListener identity})
(def react-native-biometrics #js {:default {}}) (def react-native-biometrics #js {:default {}})
(def react-native-static-safe-area-insets #js {:default {}}) (def react-native-static-safe-area-insets #js {:default {}})
+1 -1
View File
@@ -23,7 +23,7 @@
(oops/ocall wc-utils (oops/ocall wc-utils
"buildApprovedNamespaces" "buildApprovedNamespaces"
(bean/->js {:proposal proposal (bean/->js {:proposal proposal
:supportedNamespaces supported-namespaces}))) :supportedNamespaces (clj->js supported-namespaces)})))
;; Get an error from this list: ;; Get an error from this list:
;; https://github.com/WalletConnect/walletconnect-monorepo/blob/c6e9529418a0c81d4efcc6ac4e61f242a50b56c5/packages/utils/src/errors.ts ;; https://github.com/WalletConnect/walletconnect-monorepo/blob/c6e9529418a0c81d4efcc6ac4e61f242a50b56c5/packages/utils/src/errors.ts
@@ -0,0 +1,24 @@
(ns status-im.common.new-device-sheet.style
(:require [quo.foundations.colors :as colors]))
(def heading
{:padding-left 20
:padding-bottom 8})
(def message
{:padding-horizontal 20
:padding-top 4})
(def warning
{:margin-horizontal 20
:margin-top 10})
(def drawer-container
{:padding-horizontal 13
:padding-top 16})
(def settings-subtext
{:color colors/white-opa-70
:align-self :center
:margin-bottom 12})
@@ -0,0 +1,82 @@
(ns status-im.common.new-device-sheet.view
(:require
[quo.core :as quo]
[status-im.common.new-device-sheet.style :as style]
[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]))
(defn- pair-and-sync
[installation-id]
(rf/dispatch [:pairing/pair-and-sync installation-id])
(hide-bottom-sheet))
(defn view
[installation-id]
(dismiss-keyboard)
[:<>
[quo/text
{:weight :semi-bold
:size :heading-2
:accessibility-label :new-device-sheet-heading
:style style/heading}
(i18n/label :t/pair-new-device-and-sync)]
[quo/text
{:weight :regular
:size :paragraph-1
:accessibility-label :new-device-sheet-message
:style style/message}
(i18n/label :t/new-device-detected)]
[quo/text
{:weight :semi-bold
:size :heading-2
:accessibility-label :new-device-installation-id
:style style/heading}
installation-id]
[quo/bottom-actions
{:actions :two-actions
:blur? true
:container-style {:margin-top 12}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:type :grey
:on-press hide-bottom-sheet}
:button-one-label (i18n/label :t/pair-and-sync)
:button-one-props {:on-press #(pair-and-sync installation-id)}}]])
(defn view-2
[]
(let [installation-id (rf/sub [:profile/installation-id])]
(dismiss-keyboard)
[:<>
[quo/text
{:weight :semi-bold
:size :heading-2
:accessibility-label :new-device-sheet-heading
:style style/heading}
(i18n/label :t/pair-new-device-and-sync)]
[quo/text
{:weight :regular
:size :paragraph-1
:accessibility-label :new-device-sheet-message
:style style/message}
(i18n/label :t/check-new-device)]
[quo/text
{:weight :semi-bold
:size :heading-2
:accessibility-label :new-device-installation-id
:style style/heading}
installation-id]
[quo/bottom-actions
{:actions :one-action
:blur? true
:container-style {:margin-top 12}
:button-one-label (i18n/label :t/close)
:button-one-props {:type :grey
:on-press hide-bottom-sheet}}]]))
@@ -0,0 +1,55 @@
(ns status-im.contexts.networks.events
(:require
["@react-native-community/netinfo" :default net-info]
[native-module.core :as native-module]
[status-im.feature-flags :as ff]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(rf/reg-fx
:effects.network/listen-to-network-info
(fn []
(when net-info
(.addEventListener ^js net-info
#(rf/dispatch [:network/on-state-change
(js->clj % :keywordize-keys true)])))))
(rf/reg-event-fx
:network/on-state-change
(fn [{:keys [db]} [{:keys [isConnected type details]}]]
(let [old-network-status (:network/status db)
old-network-type (:network/type db)
connectivity-status (if isConnected :online :offline)
status-changed? (not= connectivity-status old-network-status)
type-changed? (not= type old-network-type)
is-connection-expensive? (:is-connection-expensive details)]
(log/debug "[net-info]"
"old-network-status" old-network-status
"old-network-type" old-network-type
"connectivity-status" connectivity-status
"type" type
"details" details)
{:fx [(when status-changed?
[:dispatch [:network/on-network-status-change isConnected]])
(when type-changed?
[:dispatch [:network/on-network-type-change type is-connection-expensive?]])]})))
(rf/reg-event-fx
:network/on-network-type-change
(fn [{:keys [db]} [network-type expensive?]]
{:db (assoc db :network/type network-type)
:fx [[:effects.network/notify-status-go network-type expensive?]
[:dispatch [:mobile-network/on-network-status-change]]]}))
(rf/reg-event-fx
:network/on-network-status-change
(fn [{:keys [db]} [is-connected?]]
(let [network-status (if is-connected? :online :offline)]
{:db (assoc db :network/status network-status)
:fx [(when (ff/enabled? ::ff/wallet.wallet-connect)
[:dispatch [:wallet-connect/reload-on-network-change is-connected?]])]})))
(rf/reg-fx
:effects.network/notify-status-go
(fn [network-type expensive?]
(native-module/connection-change network-type expensive?)))
@@ -17,3 +17,17 @@
{:events [:onboarding/overlay-dismiss]} {:events [:onboarding/overlay-dismiss]}
[_] [_]
{:onboarding/overlay-dismiss-fx nil}) {:onboarding/overlay-dismiss-fx nil})
(re-frame/reg-fx
:onboarding/overlay-show-fx
(fn []
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
(blur-show-fn))
(when-let [push-animation-fn @profiles/push-animation-fn-atom]
(push-animation-fn))))
(rf/defn overlay-show
{:events [:onboarding/overlay-show]}
[_]
{:onboarding/overlay-show-fx nil})
@@ -38,7 +38,7 @@
(rf/dispatch [:push-notifications/switch true]) (rf/dispatch [:push-notifications/switch true])
(rf/dispatch [:navigate-to-within-stack (rf/dispatch [:navigate-to-within-stack
[:screen/onboarding.welcome [:screen/onboarding.welcome
:screen/onboarding.generating-keys]])) :screen/onboarding.enable-notifications]]))
:type :primary :type :primary
:icon-left :i/notifications :icon-left :i/notifications
:accessibility-label :enable-notifications-button :accessibility-label :enable-notifications-button
@@ -52,7 +52,7 @@
nil) nil)
(rf/dispatch [:navigate-to-within-stack (rf/dispatch [:navigate-to-within-stack
[:screen/onboarding.welcome [:screen/onboarding.welcome
:screen/onboarding.generating-keys]])) :screen/onboarding.enable-notifications]]))
:accessibility-label :enable-notifications-later-button :accessibility-label :enable-notifications-later-button
:type :grey :type :grey
:background :blur :background :blur
+22 -16
View File
@@ -125,25 +125,31 @@
mnemonic key-uid])) mnemonic key-uid]))
on-error]}) on-error]})
;; TODO: clear syncing data if key-uid does not match
(rf/defn seed-phrase-validated (rf/defn seed-phrase-validated
{:events [:onboarding/seed-phrase-validated]} {:events [:onboarding/seed-phrase-validated]}
[{:keys [db]} seed-phrase key-uid] [{:keys [db]} seed-phrase key-uid]
(if (contains? (:profile/profiles-overview db) key-uid) (let [next-screen (if (and (seq (:syncing/key-uid db))
{:effects.utils/show-confirmation (= (:syncing/key-uid db) key-uid))
{:title (i18n/label :t/multiaccount-exists-title) :screen/onboarding.create-profile-password
:content (i18n/label :t/multiaccount-exists-content) :screen/onboarding.create-profile)]
:confirm-button-text (i18n/label :t/unlock)
:on-accept (fn [] (if (contains? (:profile/profiles-overview db) key-uid)
(re-frame/dispatch [:pop-to-root :screen/profile.profiles]) {:effects.utils/show-confirmation
(re-frame/dispatch {:title (i18n/label :t/multiaccount-exists-title)
[:profile/profile-selected key-uid])) :content (i18n/label :t/multiaccount-exists-content)
:on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}} :confirm-button-text (i18n/label :t/unlock)
{:db (assoc-in db [:onboarding/profile :seed-phrase] seed-phrase) :on-accept (fn []
:dispatch [:navigate-to-within-stack (re-frame/dispatch [:pop-to-root :screen/profile.profiles])
[:screen/onboarding.create-profile (re-frame/dispatch
(get db [:profile/profile-selected key-uid]))
:onboarding/navigated-to-enter-seed-phrase-from-screen :on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}}
:screen/onboarding.new-to-status)]]})) {:db (assoc-in db [:onboarding/profile :seed-phrase] seed-phrase)
:dispatch [:navigate-to-within-stack
[next-screen
(get db
:onboarding/navigated-to-enter-seed-phrase-from-screen
:screen/onboarding.new-to-status)]]})))
(rf/defn navigate-to-create-profile (rf/defn navigate-to-create-profile
{:events [:onboarding/navigate-to-create-profile]} {:events [:onboarding/navigate-to-create-profile]}
@@ -2,6 +2,13 @@
(:require (:require
[quo.foundations.colors :as colors])) [quo.foundations.colors :as colors]))
(def absolute-fill
{:position :absolute
:top 0
:bottom 0
:left 0
:right 0})
(defn page-container (defn page-container
[in-onboarding?] [in-onboarding?]
{:flex 1 {:flex 1
@@ -26,33 +26,62 @@
:title-accessibility-label :progress-screen-title :title-accessibility-label :progress-screen-title
:description-accessibility-label :progress-screen-sub-title}]) :description-accessibility-label :progress-screen-sub-title}])
(defn navigate-to-enter-seed-phrase
[view-id]
(if (= view-id :screen/onboarding.syncing-progress-intro)
(do
(rf/dispatch [:navigate-back-to :screen/onboarding.sync-or-recover-profile])
(debounce/debounce-and-dispatch
[:onboarding/navigate-to-sign-in-by-seed-phrase :screen/onboarding.sync-or-recover-profile]
300))
(do
(rf/dispatch [:navigate-back])
(debounce/debounce-and-dispatch [:onboarding/overlay-show] 100)
(debounce/debounce-and-dispatch [:open-modal :screen/onboarding.new-to-status] 200)
(debounce/debounce-and-dispatch
[:onboarding/navigate-to-sign-in-by-seed-phrase :screen/onboarding.new-to-status]
300))))
(defn try-again-button (defn try-again-button
[profile-color in-onboarding? logged-in?] [profile-color in-onboarding? logged-in? view-id]
[quo/button [rn/view
{:on-press (fn [] (when-not logged-in?
(rf/dispatch [:syncing/clear-states]) [quo/button
(cond {:on-press #(navigate-to-enter-seed-phrase view-id)
logged-in? (rf/dispatch [:navigate-back]) :accessibility-label :try-seed-phrase-button
in-onboarding? (rf/dispatch [:navigate-back-to :customization-color profile-color
:screen/onboarding.sign-in-intro]) :container-style style/try-again-button}
:else (do (i18n/label :t/enter-seed-phrase)])
(rf/dispatch [:navigate-back])
(debounce/throttle-and-dispatch
[:open-modal [quo/button
:screen/onboarding.sign-in] {:on-press (fn []
1000)))) (rf/dispatch [:syncing/clear-states])
:accessibility-label :try-again-later-button (cond
:customization-color profile-color logged-in? (rf/dispatch [:navigate-back])
:container-style style/try-again-button} in-onboarding? (rf/dispatch [:navigate-back-to
(i18n/label :t/try-again)]) :screen/onboarding.sign-in-intro])
:else (do
(rf/dispatch [:navigate-back])
(debounce/throttle-and-dispatch
[:open-modal
:screen/onboarding.sign-in]
1000))))
:accessibility-label :try-again-later-button
:customization-color profile-color
:container-style style/try-again-button}
(i18n/label :t/try-again)]])
(defn view (defn view
[in-onboarding?] [in-onboarding?]
(let [pairing-status (rf/sub [:pairing/pairing-status]) (let [pairing-status (rf/sub [:pairing/pairing-status])
profile-color (:color (rf/sub [:onboarding/profile])) profile-color (:color (rf/sub [:onboarding/profile]))
logged-in? (rf/sub [:multiaccount/logged-in?])] logged-in? (rf/sub [:multiaccount/logged-in?])
view-id (rf/sub [:view-id])]
[rn/view {:style (style/page-container in-onboarding?)} [rn/view {:style (style/page-container in-onboarding?)}
(when-not in-onboarding? [background/view true]) (when-not in-onboarding?
[rn/view {:style style/absolute-fill}
[background/view true]])
[quo/page-nav {:type :no-title :background :blur}] [quo/page-nav {:type :no-title :background :blur}]
[page-title (pairing-progress pairing-status)] [page-title (pairing-progress pairing-status)]
(if config/show-not-implemented-features? (if config/show-not-implemented-features?
@@ -63,7 +92,7 @@
[quo/text "[Error here]"]]) [quo/text "[Error here]"]])
[rn/view {:flex 1}]) [rn/view {:flex 1}])
(when-not (pairing-progress pairing-status) (when-not (pairing-progress pairing-status)
[try-again-button profile-color in-onboarding? logged-in?])])) [try-again-button profile-color in-onboarding? logged-in? view-id])]))
(defn view-onboarding (defn view-onboarding
[] []
@@ -3,6 +3,13 @@
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
[react-native.reanimated :as reanimated])) [react-native.reanimated :as reanimated]))
(def absolute-fill
{:position :absolute
:top 0
:bottom 0
:left 0
:right 0})
(defn page-container (defn page-container
[top] [top]
{:flex 1 {:flex 1
@@ -66,7 +66,8 @@
translate-x (reanimated/use-shared-value 0) translate-x (reanimated/use-shared-value 0)
window-width (:width (rn/get-window))] window-width (:width (rn/get-window))]
[rn/view {:style (style/page-container top)} [rn/view {:style (style/page-container top)}
[background/view true] [rn/view {:style style/absolute-fill}
[background/view true]]
[reanimated/view [reanimated/view
{:style (style/content translate-x)} {:style (style/content translate-x)}
[page-title] [page-title]
@@ -124,6 +124,8 @@
:on-success [:profile.login/node-info-fetched] :on-success [:profile.login/node-info-fetched]
:on-error #(log/error "node-info: failed error" %)}]] :on-error #(log/error "node-info: failed error" %)}]]
[:pairing/get-our-installations] [:pairing/get-our-installations]
(when (:syncing/installation-id db)
[:dispatch [:pairing/finish-seed-phrase-fallback-syncing]])
(when-not new-account? (when-not new-account?
[:dispatch [:universal-links/process-stored-event]])]}))) [:dispatch [:universal-links/process-stored-event]])]})))
@@ -2,6 +2,7 @@
(:require (:require
[native-module.core :as native-module] [native-module.core :as native-module]
[status-im.common.emoji-picker.utils :as emoji-picker.utils] [status-im.common.emoji-picker.utils :as emoji-picker.utils]
[status-im.constants :as constants]
[status-im.contexts.profile.config :as profile.config] [status-im.contexts.profile.config :as profile.config]
status-im.contexts.profile.recover.effects status-im.contexts.profile.recover.effects
[utils.re-frame :as rf] [utils.re-frame :as rf]
@@ -17,11 +18,11 @@
(assoc-in [:syncing :login-sha3-password] login-sha3-password)) (assoc-in [:syncing :login-sha3-password] login-sha3-password))
:effects.profile/restore-and-login :effects.profile/restore-and-login
(merge (profile.config/create) (assoc (profile.config/create)
{:displayName display-name :displayName display-name
:mnemonic (security/safe-unmask-data seed-phrase) :mnemonic (security/safe-unmask-data seed-phrase)
:password login-sha3-password :password login-sha3-password
:imagePath (profile.config/strip-file-prefix image-path) :imagePath (profile.config/strip-file-prefix image-path)
:customizationColor color :customizationColor (or color constants/profile-default-color)
:emoji (emoji-picker.utils/random-emoji) :emoji (emoji-picker.utils/random-emoji)
:fetchBackup true})})) :fetchBackup true)}))
@@ -7,6 +7,7 @@
[react-native.safe-area :as safe-area] [react-native.safe-area :as safe-area]
[status-im.common.floating-button-page.view :as floating-button-page] [status-im.common.floating-button-page.view :as floating-button-page]
[status-im.contexts.settings.wallet.saved-addresses.add-address-to-save.style :as style] [status-im.contexts.settings.wallet.saved-addresses.add-address-to-save.style :as style]
[status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.common.validation :as validation] [status-im.contexts.wallet.common.validation :as validation]
[utils.debounce :as debounce] [utils.debounce :as debounce]
[utils.i18n :as i18n] [utils.i18n :as i18n]
@@ -18,20 +19,21 @@
(defn- validate-input (defn- validate-input
[account-addresses saved-addresses user-input] [account-addresses saved-addresses user-input]
(cond (let [[_ address-without-prefix] (utils/split-prefix-and-address user-input)]
(string/blank? user-input) (cond
nil (string/blank? user-input)
nil
(contains? saved-addresses user-input) (contains? saved-addresses address-without-prefix)
:existing-saved-address :existing-saved-address
(contains? account-addresses user-input) (contains? account-addresses address-without-prefix)
:own-account :own-account
(not (not
(or (validation/eth-address? user-input) (or (validation/eth-address? user-input)
(validation/ens-name? user-input))) (validation/ens-name? user-input)))
:invalid-address-or-ens)) :invalid-address-or-ens)))
(defn- address-input (defn- address-input
[{:keys [input-value on-change-text paste-into-input clear-input]}] [{:keys [input-value on-change-text paste-into-input clear-input]}]
@@ -93,8 +95,9 @@
(defn- existing-saved-address (defn- existing-saved-address
[{:keys [address]}] [{:keys [address]}]
(let [{:keys [name customization-color chain-short-names ens ens?]} (let [[_ address-without-prefix] (utils/split-prefix-and-address address)
(rf/sub [:wallet/saved-address-by-address address])] {:keys [name customization-color chain-short-names ens ens?]}
(rf/sub [:wallet/saved-address-by-address address-without-prefix])]
[rn/view {:style style/existing-saved-address-container} [rn/view {:style style/existing-saved-address-container}
[quo/text [quo/text
{:size :paragraph-1 {:size :paragraph-1
@@ -105,7 +108,7 @@
{:blur? true {:blur? true
:active-state? true :active-state? true
:user-props {:name name :user-props {:name name
:address (str chain-short-names address) :address (str chain-short-names address-without-prefix)
:ens (when ens? ens) :ens (when ens? ens)
:customization-color customization-color :customization-color customization-color
:blur? true} :blur? true}
@@ -168,20 +171,21 @@
(rn/use-mount #(rf/dispatch [:wallet/clear-address-to-save])) (rn/use-mount #(rf/dispatch [:wallet/clear-address-to-save]))
[quo/overlay {:type :shell} [quo/overlay {:type :shell}
[floating-button-page/view [floating-button-page/view
{:footer-container-padding 0 {:footer-container-padding 0
:header [quo/page-nav :keyboard-should-persist-taps :handled
{:type :no-title :header [quo/page-nav
:icon-name :i/close {:type :no-title
:behind-overlay? true :icon-name :i/close
:on-press navigate-back :behind-overlay? true
:margin-top (safe-area/get-top) :on-press navigate-back
:accessibility-label :add-address-to-save-page-nav}] :margin-top (safe-area/get-top)
:footer (when (= view-id :screen/settings.add-address-to-save) :accessibility-label :add-address-to-save-page-nav}]
[quo/button :footer (when (= view-id :screen/settings.add-address-to-save)
{:customization-color profile-color [quo/button
:disabled? button-disabled? {:customization-color profile-color
:on-press on-press-continue} :disabled? button-disabled?
(i18n/label :t/continue)])} :on-press on-press-continue}
(i18n/label :t/continue)])}
[quo/page-top [quo/page-top
{:container-style style/header-container {:container-style style/header-container
:blur? true :blur? true
@@ -105,24 +105,25 @@
[ens ens? open-network-preferences address-text])] [ens ens? open-network-preferences address-text])]
[quo/overlay {:type :shell} [quo/overlay {:type :shell}
[floating-button-page/view [floating-button-page/view
{:footer-container-padding (if edit? (+ (safe-area/get-bottom) 12) 0) {:footer-container-padding (if edit? (+ (safe-area/get-bottom) 12) 0)
:header [quo/page-nav :keyboard-should-persist-taps :handled
{:type :no-title :header [quo/page-nav
:background :blur {:type :no-title
:icon-name (if edit? :i/close :i/arrow-left) :background :blur
:on-press navigate-back :icon-name (if edit? :i/close :i/arrow-left)
:margin-top (when-not edit? (safe-area/get-top)) :on-press navigate-back
:accessibility-label :save-address-page-nav}] :margin-top (when-not edit? (safe-area/get-top))
:footer [quo/button :accessibility-label :save-address-page-nav}]
{:accessibility-label :save-address-button :footer [quo/button
:type :primary {:accessibility-label :save-address-button
:customization-color address-color :type :primary
:disabled? (string/blank? address-label) :customization-color address-color
:on-press on-press-save} :disabled? (string/blank? address-label)
(i18n/label :t/save-address)] :on-press on-press-save}
:customization-color address-color (i18n/label :t/save-address)]
:gradient-cover? true :customization-color address-color
:shell-overlay? true} :gradient-cover? true
:shell-overlay? true}
[quo/wallet-user-avatar [quo/wallet-user-avatar
{:full-name (if (string/blank? address-label) {:full-name (if (string/blank? address-label)
placeholder placeholder
+20 -3
View File
@@ -46,13 +46,29 @@
(log/info "[local-pairing] input-connection-string-for-bootstrapping callback" (log/info "[local-pairing] input-connection-string-for-bootstrapping callback"
{:response res {:response res
:event :syncing/input-connection-string-for-bootstrapping}) :event :syncing/input-connection-string-for-bootstrapping})
(let [error (when (sync-utils/extract-error res) (let [response (transforms/json->clj res)
(str "generic-error: " res))] installation-id (:installationId response)
(when (some? error) key-uid (:keyUID response)
error (:error response)]
(when (seq installation-id)
(rf/dispatch [:syncing/set-syncing-installation-id installation-id key-uid]))
(when (seq error)
(rf/dispatch [:toasts/upsert (rf/dispatch [:toasts/upsert
{:type :negative {:type :negative
:text error}])))) :text error}]))))
(rf/defn initiate-pairing-process
{:events [:syncing/initiate-pairing-process]}
[{:keys [db]}]
{:db (assoc db :syncing/pairing-process-initiated? true)})
(rf/defn set-syncing-installation-id
{:events [:syncing/set-syncing-installation-id]}
[{:keys [db]} installation-id key-uid]
{:db (assoc db
:syncing/key-uid key-uid
:syncing/installation-id installation-id)})
(rf/defn preflight-outbound-check-for-local-pairing (rf/defn preflight-outbound-check-for-local-pairing
{:events [:syncing/preflight-outbound-check]} {:events [:syncing/preflight-outbound-check]}
[_ set-checks-passed] [_ set-checks-passed]
@@ -96,6 +112,7 @@
(when (sync-utils/valid-connection-string? response) (when (sync-utils/valid-connection-string? response)
(on-valid-connection-string response) (on-valid-connection-string response)
(rf/dispatch [:syncing/update-role constants/local-pairing-role-sender]) (rf/dispatch [:syncing/update-role constants/local-pairing-role-sender])
(rf/dispatch [:syncing/initiate-pairing-process])
(rf/dispatch [:hide-bottom-sheet])))] (rf/dispatch [:hide-bottom-sheet])))]
(when-not (and error (string/blank? error)) (when-not (and error (string/blank? error))
(let [key-uid (get-in db [:profile/profile :key-uid]) (let [key-uid (get-in db [:profile/profile :key-uid])
@@ -1,7 +1,6 @@
(ns status-im.contexts.wallet.data-store-test (ns status-im.contexts.wallet.data-store-test
(:require (:require
[cljs.test :refer-macros [deftest is testing]] [cljs.test :refer-macros [deftest is testing]]
[matcher-combinators.matchers :as matchers]
matcher-combinators.test matcher-combinators.test
[status-im.contexts.wallet.data-store :as sut])) [status-im.contexts.wallet.data-store :as sut]))
@@ -162,82 +161,73 @@
(deftest reconcile-keypairs-test (deftest reconcile-keypairs-test
(testing "reconcile-keypairs represents updated key pairs and accounts" (testing "reconcile-keypairs represents updated key pairs and accounts"
(is (is
(match? (match-strict?
(matchers/match-with {:removed-keypair-ids #{}
[set? matchers/set-equals :removed-account-addresses #{}
map? matchers/equals] :updated-accounts-by-address {"1x123" (merge account
{:removed-keypair-ids #{} {:key-uid "0x123"
:removed-account-addresses #{} :address "1x123"})
:updated-accounts-by-address {"1x123" (merge account "1x456" (merge account
{:key-uid "0x123" {:key-uid "0x456"
:address "1x123"}) :address "1x456"
"1x456" (merge account :operable? false
{:key-uid "0x456" :operable :no})}
:address "1x456" :updated-keypairs-by-id {"0x123" {:key-uid "0x123"
:operable? false :type :seed
:operable :no})} :lowest-operability :fully
:updated-keypairs-by-id {"0x123" {:key-uid "0x123" :accounts [(merge account
:type :seed {:key-uid "0x123"
:lowest-operability :fully :address "1x123"})]}
:accounts [(merge account "0x456" {:key-uid "0x456"
{:key-uid "0x123" :type :key
:address "1x123"})]} :lowest-operability :no
"0x456" {:key-uid "0x456" :accounts [(merge account
:type :key {:key-uid "0x456"
:lowest-operability :no :address "1x456"
:accounts [(merge account :operable? false
{:key-uid "0x456" :operable :no})]}}}
:address "1x456"
:operable? false
:operable :no})]}}})
(sut/reconcile-keypairs [raw-keypair-seed-phrase (sut/reconcile-keypairs [raw-keypair-seed-phrase
raw-keypair-private-key])))) raw-keypair-private-key]))))
(testing "reconcile-keypairs represents removed key pairs and accounts" (testing "reconcile-keypairs represents removed key pairs and accounts"
(is (is
(match? (match-strict?
(matchers/match-with {:removed-keypair-ids #{"0x456"}
[set? matchers/set-equals :removed-account-addresses #{"1x456"}
map? matchers/equals] :updated-accounts-by-address {"1x123" (merge account
{:removed-keypair-ids #{"0x456"} {:key-uid "0x123"
:removed-account-addresses #{"1x456"} :address "1x123"})}
:updated-accounts-by-address {"1x123" (merge account :updated-keypairs-by-id {"0x123" {:key-uid "0x123"
{:key-uid "0x123" :type :seed
:address "1x123"})} :lowest-operability :fully
:updated-keypairs-by-id {"0x123" {:key-uid "0x123" :accounts [(merge account
:type :seed {:key-uid "0x123"
:lowest-operability :fully :address "1x123"})]}}}
:accounts [(merge account
{:key-uid "0x123"
:address "1x123"})]}}})
(sut/reconcile-keypairs [raw-keypair-seed-phrase (sut/reconcile-keypairs [raw-keypair-seed-phrase
(assoc raw-keypair-private-key :removed true)])))) (assoc raw-keypair-private-key :removed true)]))))
(testing "reconcile-keypairs ignores chat accounts inside updated accounts" (testing "reconcile-keypairs ignores chat accounts inside updated accounts"
(is (is
(match? (match-strict?
(matchers/match-with {:removed-keypair-ids #{}
[set? matchers/set-equals :removed-account-addresses #{}
map? matchers/equals] :updated-accounts-by-address {"2x000" (merge account
{:removed-keypair-ids #{} {:key-uid "0x000"
:removed-account-addresses #{} :address "2x000"
:updated-accounts-by-address {"2x000" (merge account :chat false
{:key-uid "0x000" :wallet true
:address "2x000" :default-account? true})}
:chat false :updated-keypairs-by-id {"0x000" {:key-uid "0x000"
:wallet true :type :profile
:default-account? true})} :lowest-operability :fully
:updated-keypairs-by-id {"0x000" {:key-uid "0x000" :accounts [(merge account
:type :profile {:key-uid "0x000"
:lowest-operability :fully :address "1x000"
:accounts [(merge account :chat true
{:key-uid "0x000" :wallet false
:address "1x000" :default-account? false})
:chat true (merge account
:wallet false {:key-uid "0x000"
:default-account? false}) :address "2x000"
(merge account :chat false
{:key-uid "0x000" :wallet true
:address "2x000" :default-account? true})]}}}
:chat false
:wallet true
:default-account? true})]}}})
(sut/reconcile-keypairs [raw-keypair-profile]))))) (sut/reconcile-keypairs [raw-keypair-profile])))))
@@ -50,11 +50,15 @@
(rf/reg-fx (rf/reg-fx
:effects.wallet-connect/approve-session :effects.wallet-connect/approve-session
(fn [{:keys [web3-wallet proposal supported-namespaces on-success on-fail]}] (fn [{:keys [web3-wallet proposal networks accounts on-success on-fail]}]
(let [{:keys [params id]} proposal (let [{:keys [params id]} proposal
approved-namespaces (wallet-connect/build-approved-namespaces approved-namespaces (->> {:eip155
params {:chains networks
supported-namespaces)] :accounts accounts
:methods constants/wallet-connect-supported-methods
:events constants/wallet-connect-supported-events}}
(wallet-connect/build-approved-namespaces
params))]
(-> (wallet-connect/approve-session (-> (wallet-connect/approve-session
{:web3-wallet web3-wallet {:web3-wallet web3-wallet
:id id :id id
@@ -13,10 +13,14 @@
(rf/reg-event-fx (rf/reg-event-fx
:wallet-connect/init :wallet-connect/init
(fn [] (fn [{:keys [db]}]
{:fx [[:effects.wallet-connect/init (let [network-status (:network/status db)]
{:on-success #(rf/dispatch [:wallet-connect/on-init-success %]) (if (= network-status :online)
:on-fail #(rf/dispatch [:wallet-connect/on-init-fail %])}]]})) {:fx [[:effects.wallet-connect/init
{:on-success #(rf/dispatch [:wallet-connect/on-init-success %])
:on-fail #(rf/dispatch [:wallet-connect/on-init-fail %])}]]}
;; NOTE: when offline, fetching persistent sessions only
{:fx [[:dispatch [:wallet-connect/fetch-persisted-sessions]]]}))))
(rf/reg-event-fx (rf/reg-event-fx
:wallet-connect/on-init-success :wallet-connect/on-init-success
@@ -25,6 +29,14 @@
:fx [[:dispatch [:wallet-connect/register-event-listeners]] :fx [[:dispatch [:wallet-connect/register-event-listeners]]
[:dispatch [:wallet-connect/fetch-persisted-sessions]]]})) [:dispatch [:wallet-connect/fetch-persisted-sessions]]]}))
(rf/reg-event-fx
:wallet-connect/reload-on-network-change
(fn [{:keys [db]} [is-connected?]]
(let [logged-in? (-> db :profile/profile boolean)
web3-wallet-missing? (-> db :wallet-connect/web3-wallet boolean not)]
(when (and is-connected? logged-in? web3-wallet-missing?)
{:fx [[:dispatch [:wallet-connect/init]]]}))))
(rf/reg-event-fx (rf/reg-event-fx
:wallet-connect/register-event-listeners :wallet-connect/register-event-listeners
(fn [{:keys [db]}] (fn [{:keys [db]}]
@@ -77,12 +89,12 @@
(rf/reg-event-fx (rf/reg-event-fx
:wallet-connect/session-networks-unsupported :wallet-connect/session-networks-unsupported
(fn [_ [proposal]] (fn [{:keys [db]} [proposal]]
(let [{:keys [name]} (wallet-connect-core/get-session-dapp-metadata proposal)] (let [{:keys [name]} (wallet-connect-core/get-session-dapp-metadata proposal)]
{:fx [[:dispatch {:fx [[:dispatch
[:toasts/upsert [:toasts/upsert
{:type :negative {:type :negative
:theme :dark :theme (:theme db)
:text (i18n/label :t/wallet-connect-networks-not-supported {:dapp name})}]]]}))) :text (i18n/label :t/wallet-connect-networks-not-supported {:dapp name})}]]]})))
(rf/reg-event-fx (rf/reg-event-fx
@@ -116,17 +128,20 @@
(rf/reg-event-fx (rf/reg-event-fx
:wallet-connect/disconnect-dapp :wallet-connect/disconnect-dapp
(fn [{:keys [db]} [{:keys [topic on-success on-fail]}]] (fn [{:keys [db]} [{:keys [topic on-success on-fail]}]]
(let [web3-wallet (get db :wallet-connect/web3-wallet)] (let [web3-wallet (get db :wallet-connect/web3-wallet)
{:fx [[:effects.wallet-connect/disconnect network-status (:network/status db)]
{:web3-wallet web3-wallet (if (= network-status :online)
:topic topic {:fx [[:effects.wallet-connect/disconnect
:reason (wallet-connect/get-sdk-error {:web3-wallet web3-wallet
constants/wallet-connect-user-disconnected-reason-key) :topic topic
:on-fail on-fail :reason (wallet-connect/get-sdk-error
:on-success (fn [] constants/wallet-connect-user-disconnected-reason-key)
(rf/dispatch [:wallet-connect/disconnect-session topic]) :on-fail on-fail
(when on-success :on-success (fn []
(on-success)))}]]}))) (rf/dispatch [:wallet-connect/disconnect-session topic])
(when on-success
(on-success)))}]]}
{:fx [[:dispatch [:wallet-connect/no-internet-toast]]]}))))
(rf/reg-event-fx (rf/reg-event-fx
:wallet-connect/pair :wallet-connect/pair
@@ -141,51 +156,57 @@
(rf/reg-event-fx (rf/reg-event-fx
:wallet-connect/approve-session :wallet-connect/approve-session
(fn [{:keys [db]}] (fn [{:keys [db]}]
(let [web3-wallet (get db :wallet-connect/web3-wallet) (let [web3-wallet (get db :wallet-connect/web3-wallet)
current-proposal (get-in db [:wallet-connect/current-proposal :request]) current-proposal (get-in db [:wallet-connect/current-proposal :request])
session-networks (->> (get-in db [:wallet-connect/current-proposal :session-networks]) session-networks (->> (get-in db [:wallet-connect/current-proposal :session-networks])
(map wallet-connect-core/chain-id->eip155) (map wallet-connect-core/chain-id->eip155)
vec) vec)
current-address (get-in db [:wallet-connect/current-proposal :address]) current-address (get-in db [:wallet-connect/current-proposal :address])
accounts (-> (partial wallet-connect-core/format-eip155-address current-address) accounts (-> (partial wallet-connect-core/format-eip155-address current-address)
(map session-networks)) (map session-networks))
supported-namespaces (clj->js {:eip155 network-status (:network/status db)]
{:chains session-networks (if (= network-status :online)
:methods constants/wallet-connect-supported-methods {:fx [[:effects.wallet-connect/approve-session
:events constants/wallet-connect-supported-events {:web3-wallet web3-wallet
:accounts accounts}})] :proposal current-proposal
{:fx [[:effects.wallet-connect/approve-session :networks session-networks
{:web3-wallet web3-wallet :accounts accounts
:proposal current-proposal :on-success (fn [approved-session]
:supported-namespaces supported-namespaces (log/info "Wallet Connect session approved")
:on-success (fn [approved-session] (rf/dispatch [:wallet-connect/reset-current-session-proposal])
(log/info "Wallet Connect session approved") (rf/dispatch [:wallet-connect/persist-session approved-session]))
(rf/dispatch [:wallet-connect/reset-current-session-proposal]) :on-fail (fn [error]
(rf/dispatch [:wallet-connect/persist-session approved-session])) (log/error "Wallet Connect session approval failed"
:on-fail (fn [error] {:error error
(log/error "Wallet Connect session approval failed" :event :wallet-connect/approve-session})
{:error error (rf/dispatch
:event :wallet-connect/approve-session}) [:wallet-connect/reset-current-session-proposal]))}]
(rf/dispatch [:dispatch [:dismiss-modal :screen/wallet.wallet-connect-session-proposal]]]}
[:wallet-connect/reset-current-session-proposal]))}] {:fx [[:dispatch [:wallet-connect/no-internet-toast]]]}))))
[:dispatch [:dismiss-modal :screen/wallet.wallet-connect-session-proposal]]]})))
(rf/reg-event-fx (rf/reg-event-fx
:wallet-connect/on-scan-connection :wallet-connect/on-scan-connection
(fn [_ [scanned-text]] (fn [{:keys [db]} [scanned-text]]
(let [parsed-uri (wallet-connect/parse-uri scanned-text) (let [network-status (:network/status db)
parsed-uri (wallet-connect/parse-uri scanned-text)
version (:version parsed-uri) version (:version parsed-uri)
valid-wc-uri? (wc-utils/valid-wc-uri? parsed-uri) valid-wc-uri? (wc-utils/valid-wc-uri? parsed-uri)
expired? (-> parsed-uri expired? (-> parsed-uri
:expiryTimestamp :expiryTimestamp
wc-utils/timestamp-expired?) wc-utils/timestamp-expired?)
version-supported? (wc-utils/version-supported? version)] version-supported? (wc-utils/version-supported? version)]
(if (or (not valid-wc-uri?) expired? (not version-supported?)) (if (or (not valid-wc-uri?)
(not version-supported?)
(= network-status :offline)
expired?)
{:fx [[:dispatch {:fx [[:dispatch
[:toasts/upsert [:toasts/upsert
{:type :negative {:type :negative
:theme :dark :theme :dark
:text (cond (not valid-wc-uri?) :text (cond (= network-status :offline)
(i18n/label :t/wallet-connect-no-internet-warning)
(not valid-wc-uri?)
(i18n/label :t/wallet-connect-wrong-qr) (i18n/label :t/wallet-connect-wrong-qr)
expired? expired?
@@ -236,16 +257,18 @@
(rf/reg-event-fx (rf/reg-event-fx
:wallet-connect/fetch-persisted-sessions-success :wallet-connect/fetch-persisted-sessions-success
(fn [{:keys [db]} [sessions]] (fn [{:keys [db]} [sessions]]
(let [sessions' (mapv (fn [{:keys [sessionJson] :as session}] (let [network-status (:network/status db)
(assoc session sessions' (mapv (fn [{:keys [sessionJson] :as session}]
:accounts (assoc session
(-> sessionJson :accounts
types/json->clj (-> sessionJson
:namespaces types/json->clj
:eip155 :namespaces
:accounts))) :eip155
sessions)] :accounts)))
{:fx [[:dispatch [:wallet-connect/fetch-active-sessions]]] sessions)]
{:fx [(when (= network-status :online)
[:dispatch [:wallet-connect/fetch-active-sessions]])]
:db (assoc db :wallet-connect/sessions sessions')}))) :db (assoc db :wallet-connect/sessions sessions')})))
(rf/reg-event-fx (rf/reg-event-fx
@@ -256,14 +279,14 @@
(rf/reg-event-fx (rf/reg-event-fx
:wallet-connect/fetch-persisted-sessions :wallet-connect/fetch-persisted-sessions
(fn [_ _] (fn [{:keys [now]} _]
{:fx [[:json-rpc/call (let [current-timestamp (quot now 1000)]
[{:method "wallet_getWalletConnectActiveSessions" {:fx [[:json-rpc/call
;; This is the activeSince timestamp to avoid expired sessions [{:method "wallet_getWalletConnectActiveSessions"
;; 0 means, return everything ;; NOTE: This is the activeSince timestamp to avoid expired sessions
:params [0] :params [current-timestamp]
:on-success [:wallet-connect/fetch-persisted-sessions-success] :on-success [:wallet-connect/fetch-persisted-sessions-success]
:on-error [:wallet-connect/fetch-persisted-sessions-fail]}]]]})) :on-error [:wallet-connect/fetch-persisted-sessions-fail]}]]]})))
(rf/reg-event-fx (rf/reg-event-fx
:wallet-connect/persist-session :wallet-connect/persist-session
@@ -290,3 +313,12 @@
:params [topic] :params [topic]
:on-success #(log/info "Wallet Connect session disconnected") :on-success #(log/info "Wallet Connect session disconnected")
:on-error #(log/info "Wallet Connect session persistence failed" %)}]]]})) :on-error #(log/info "Wallet Connect session persistence failed" %)}]]]}))
(rf/reg-event-fx
:wallet-connect/no-internet-toast
(fn [{:keys [db]}]
{:fx [[:dispatch
[:toasts/upsert
{:type :negative
:theme (:theme db)
:text (i18n/label :t/wallet-connect-no-internet-warning)}]]]}))
@@ -14,26 +14,34 @@
(rf/dispatch [:wallet-connect/respond-current-session password])) (rf/dispatch [:wallet-connect/respond-current-session password]))
(defn view (defn view
[{:keys [warning-label slide-button-text disabled?]} & children] [{:keys [warning-label slide-button-text error-text]} & children]
(let [{:keys [customization-color]} (rf/sub [:wallet-connect/current-request-account-details]) (let [{:keys [customization-color]} (rf/sub [:wallet-connect/current-request-account-details])
offline? (rf/sub [:network/offline?])
theme (quo.theme/use-theme)] theme (quo.theme/use-theme)]
[rn/view {:style style/content-container} [:<>
(into [rn/view (when (or offline? error-text)
{:style style/data-items-container}] [quo/alert-banner
children) {:action? false
[rn/view {:style style/auth-container} :text (if offline?
[standard-authentication/slide-button (i18n/label :t/wallet-connect-no-internet-warning)
{:size :size-48 error-text)}])
:track-text slide-button-text [rn/view {:style style/content-container}
:disabled? disabled? (into [rn/view
:customization-color customization-color {:style style/data-items-container}]
:on-auth-success on-auth-success children)
:auth-button-label (i18n/label :t/confirm)}]] [rn/view {:style style/auth-container}
[rn/view {:style style/warning-container} [standard-authentication/slide-button
[quo/text {:size :size-48
{:size :paragraph-2 :track-text slide-button-text
:style {:color (if (= theme :dark) :disabled? (or offline? (seq error-text))
colors/white-opa-70 :customization-color customization-color
colors/neutral-80-opa-70)} :on-auth-success on-auth-success
:weight :medium} :auth-button-label (i18n/label :t/confirm)}]]
warning-label]]])) [rn/view {:style style/warning-container}
[quo/text
{:size :paragraph-2
:style {:color (if (= theme :dark)
colors/white-opa-70
colors/neutral-80-opa-70)}
:weight :medium}
warning-label]]]]))
@@ -33,19 +33,16 @@
:dapp dapp :dapp dapp
:account account}] :account account}]
[data-block/view]] [data-block/view]]
(when error-state
[quo/alert-banner
{:action? false
:text (i18n/label (condp = error-state
:not-enough-assets-to-pay-gas-fees
:t/not-enough-assets-to-pay-gas-fees
:not-enough-assets
:t/not-enough-assets))}])
[footer/view [footer/view
{:warning-label (i18n/label :t/wallet-connect-sign-warning) {:warning-label (i18n/label :t/wallet-connect-sign-warning)
:slide-button-text (i18n/label :t/slide-to-send) :slide-button-text (i18n/label :t/slide-to-send)
:disabled? error-state} :error-text (when error-state
(i18n/label (condp = error-state
:not-enough-assets-to-pay-gas-fees
:t/not-enough-assets-to-pay-gas-fees
:not-enough-assets
:t/not-enough-assets)))}
[quo/data-item [quo/data-item
{:status :default {:status :default
:card? false :card? false
@@ -32,19 +32,16 @@
:dapp dapp :dapp dapp
:account account}] :account account}]
[data-block/view]] [data-block/view]]
(when error-state
[quo/alert-banner
{:action? false
:text (i18n/label (condp = error-state
:not-enough-assets-to-pay-gas-fees
:t/not-enough-assets-to-pay-gas-fees
:not-enough-assets
:t/not-enough-assets))}])
[footer/view [footer/view
{:warning-label (i18n/label :t/wallet-connect-sign-warning) {:warning-label (i18n/label :t/wallet-connect-sign-warning)
:slide-button-text (i18n/label :t/slide-to-sign) :slide-button-text (i18n/label :t/slide-to-sign)
:disabled? error-state} :error-text (when error-state
(i18n/label (condp = error-state
:not-enough-assets-to-pay-gas-fees
:t/not-enough-assets-to-pay-gas-fees
:not-enough-assets
:t/not-enough-assets)))}
[quo/data-item [quo/data-item
{:status :default {:status :default
:card? false :card? false
+2 -1
View File
@@ -27,6 +27,7 @@
status-im.contexts.contact.blocking.events status-im.contexts.contact.blocking.events
status-im.contexts.keycard.effects status-im.contexts.keycard.effects
status-im.contexts.keycard.events status-im.contexts.keycard.events
status-im.contexts.networks.events
status-im.contexts.onboarding.common.overlay.events status-im.contexts.onboarding.common.overlay.events
status-im.contexts.onboarding.events status-im.contexts.onboarding.events
status-im.contexts.profile.events status-im.contexts.profile.events
@@ -57,7 +58,7 @@
cofx cofx
{:db db/app-db {:db db/app-db
:theme/init-theme nil :theme/init-theme nil
:network/listen-to-network-info nil :effects.network/listen-to-network-info nil
:effects.biometric/get-supported-type nil :effects.biometric/get-supported-type nil
:effects.keycard/register-card-events nil :effects.keycard/register-card-events nil
:effects.keycard/check-nfc-enabled nil :effects.keycard/check-nfc-enabled nil
+6
View File
@@ -151,3 +151,9 @@
:<- [:toasts] :<- [:toasts]
(fn [toasts [_ toast-id & cursor]] (fn [toasts [_ toast-id & cursor]]
(get-in toasts (into [:toasts toast-id] cursor)))) (get-in toasts (into [:toasts toast-id] cursor))))
(re-frame/reg-sub
:network/offline?
:<- [:network/status]
(fn [status]
(= status :offline)))
+5
View File
@@ -251,6 +251,11 @@
(fn [{:keys [preview-privacy?]}] (fn [{:keys [preview-privacy?]}]
(boolean preview-privacy?))) (boolean preview-privacy?)))
(re-frame/reg-sub :profile/installation-id
:<- [:profile/profile]
(fn [{:keys [installation-id]}]
installation-id))
(defn- replace-multiaccount-image-uri (defn- replace-multiaccount-image-uri
[profile ens-names port font-file avatar-opts theme] [profile ens-names port font-file avatar-opts theme]
(let [{:keys [key-uid ens-name? images (let [{:keys [key-uid ens-name? images
+4
View File
@@ -44,6 +44,10 @@
;;push notifications ;;push notifications
(reg-root-key-sub :push-notifications/preferences :push-notifications/preferences) (reg-root-key-sub :push-notifications/preferences :push-notifications/preferences)
;;device
(reg-root-key-sub :network/status :network/status)
(reg-root-key-sub :network/type :network/type)
;;general ;;general
(reg-root-key-sub :messenger/started? :messenger/started?) (reg-root-key-sub :messenger/started? :messenger/started?)
(reg-root-key-sub :animations :animations) (reg-root-key-sub :animations :animations)
+47
View File
@@ -0,0 +1,47 @@
(ns test-helpers.matchers
"Internal use. Don't require it directly."
(:require
[cljs.test :as test]
[matcher-combinators.core :as core]
[matcher-combinators.matchers :as matchers]
[matcher-combinators.parser]
[matcher-combinators.result :as result]))
;; This implementation is identical to `match?`, but wraps the expected value
;; with `nested-equals`. This differs from the default `embeds` matcher on maps,
;; where extra map keys are considered valid.
(defmethod test/assert-expr 'match-strict?
[_ msg form]
`(let [args# (list ~@(rest form))
[matcher# actual#] args#]
(cond
(not (= 2 (count args#)))
(test/do-report
{:type :fail
:message ~msg
:expected (symbol "`match-strict?` expects 2 arguments: a `matcher` and the `actual`")
:actual (symbol (str (count args#) " were provided: " '~form))})
(core/matcher? matcher#)
(let [result# (core/match (matchers/nested-equals matcher#) actual#)]
(test/do-report
(if (core/indicates-match? result#)
{:type :pass
:message ~msg
:expected '~form
:actual (list 'match? matcher# actual#)}
(with-file+line-info
{:type :fail
:message ~msg
:expected '~form
:actual (tagged-for-pretty-printing (list '~'not (list 'match? matcher# actual#))
result#)
:markup (::result/value result#)}))))
:else
(test/do-report
{:type :fail
:message ~msg
:expected (str "The first argument of `match-strict?` "
"needs to be a matcher (implement the match protocol)")
:actual '~form}))))
+24
View File
@@ -0,0 +1,24 @@
(ns test-helpers.matchers
"Some vars in this namespace solely exist to support the matchers.clj file."
(:require-macros test-helpers.matchers)
(:require
[cljs.test :as t]
[matcher-combinators.parser]
[matcher-combinators.printer :as printer]
[matcher-combinators.result :as result]))
(defrecord Mismatch [summary match-result])
(defn tagged-for-pretty-printing
[actual-summary result]
(->Mismatch actual-summary result))
(extend-protocol IPrintWithWriter
Mismatch
(-pr-writer [this writer _]
(-write writer (printer/as-string (-> this :match-result ::result/value)))))
(defn with-file+line-info
[report]
(merge (t/file-and-line (js/Error.) 4)
report))
+4 -2
View File
@@ -6,13 +6,15 @@
prefer to use it for more general purpose concepts, such as the re-frame event prefer to use it for more general purpose concepts, such as the re-frame event
layer." layer."
(:require-macros test-helpers.unit) (:require-macros test-helpers.unit)
(:require (:require ;; We must require this namespace to register the custom cljs.test
;; directive `match-strict?`.
[re-frame.core :as rf] [re-frame.core :as rf]
[re-frame.db :as rf-db] [re-frame.db :as rf-db]
[re-frame.events :as rf-events] [re-frame.events :as rf-events]
[re-frame.registrar :as rf-registrar] [re-frame.registrar :as rf-registrar]
[re-frame.subs :as rf-subs] [re-frame.subs :as rf-subs]
[taoensso.timbre :as log])) [taoensso.timbre :as log] ;; We must require this namespace to register the custom cljs.test
test-helpers.matchers))
(defn db (defn db
"A simple wrapper to get the latest value from the app db." "A simple wrapper to get the latest value from the app db."
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>", "_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im", "owner": "status-im",
"repo": "status-go", "repo": "status-go",
"version": "v0.182.37", "version": "feat/enable_sync_fallback",
"commit-sha1": "4a43b2b2bebe45df2100d1a5c5034105d93e50b8", "commit-sha1": "880152abcac69bb7cf29088ce413d2c4e01be412",
"src-sha256": "0f5mm7lx6s2qcy9xpa9v7piqb60yazi6p677fy105yz7hg731cw6" "src-sha256": "067pj4xx0bph9573sdk57hdhq0xkaaz1zmgkk09d27a5fz2rdm4n"
} }
+5
View File
@@ -357,6 +357,7 @@
"check-before-syncing-doc-checkbox-2": "Make sure you are logged in on the other device", "check-before-syncing-doc-checkbox-2": "Make sure you are logged in on the other device",
"check-before-syncing-doc-checkbox-3": "Disable the firewall and VPN on your devices", "check-before-syncing-doc-checkbox-3": "Disable the firewall and VPN on your devices",
"check-before-syncing-doc-description": "To sync your devices successfully, make sure to check and complete these steps:", "check-before-syncing-doc-description": "To sync your devices successfully, make sure to check and complete these steps:",
"check-new-device": "A new device has been detected. You can see device ID below and on your other device. Only confirm the request if device ID matches.",
"check-on-block-explorer": "Check on block explorer", "check-on-block-explorer": "Check on block explorer",
"check-on-opensea": "Check on opensea", "check-on-opensea": "Check on opensea",
"check-your-account-balance-and-activity": "Check your account balance and activity", "check-your-account-balance-and-activity": "Check your account balance and activity",
@@ -1626,6 +1627,7 @@
"new-community-title": "New community", "new-community-title": "New community",
"new-contact": "New contact", "new-contact": "New contact",
"new-contract": "New Contract", "new-contract": "New Contract",
"new-device-detected": "A new device has been detected. You can see device ID below and on your other device. Only confirm the request if device ID matches.",
"new-favourite": "New favourite", "new-favourite": "New favourite",
"new-group": "New group", "new-group": "New group",
"new-group-chat": "New group chat", "new-group-chat": "New group chat",
@@ -1790,12 +1792,14 @@
"page-camera-request-blocked": "camera requests blocked. To enable camera requests go to Settings", "page-camera-request-blocked": "camera requests blocked. To enable camera requests go to Settings",
"page-would-like-to-use-camera": "would like to use your camera", "page-would-like-to-use-camera": "would like to use your camera",
"pair": "Pair", "pair": "Pair",
"pair-and-sync": "Pair and Sync",
"pair-card": "Pair to this device", "pair-card": "Pair to this device",
"pair-code": "Pair code", "pair-code": "Pair code",
"pair-code-explanation": "Pairs card to a different device (up to 5) to unlock keys and sign transactions with the same Keycard", "pair-code-explanation": "Pairs card to a different device (up to 5) to unlock keys and sign transactions with the same Keycard",
"pair-code-placeholder": "Pair code...", "pair-code-placeholder": "Pair code...",
"pair-device-toast": "Device successfully paired", "pair-device-toast": "Device successfully paired",
"pair-devices": "Pair devices", "pair-devices": "Pair devices",
"pair-new-device-and-sync": "Pair new device and sync profile",
"pair-this-card": "Pair this card", "pair-this-card": "Pair this card",
"pair-this-device": "Advertise device", "pair-this-device": "Advertise device",
"pair-this-device-description": "Pair your devices to sync contacts and chats between them", "pair-this-device-description": "Pair your devices to sync contacts and chats between them",
@@ -2632,6 +2636,7 @@
"wallet-connect-go-back": "Go back to your browser or dapp", "wallet-connect-go-back": "Go back to your browser or dapp",
"wallet-connect-label": "WalletConnect", "wallet-connect-label": "WalletConnect",
"wallet-connect-networks-not-supported": "{{dapp}} requires an unsupported network.", "wallet-connect-networks-not-supported": "{{dapp}} requires an unsupported network.",
"wallet-connect-no-internet-warning": "Oops, you have no internet. Try again later!",
"wallet-connect-proposal-description": "By connecting you allow {{name}} to retrieve your account address and enable Web3", "wallet-connect-proposal-description": "By connecting you allow {{name}} to retrieve your account address and enable Web3",
"wallet-connect-proposal-title": "Would like to connect with your wallet", "wallet-connect-proposal-title": "Would like to connect with your wallet",
"wallet-connect-qr-expired": "WalletConnect QR has expired", "wallet-connect-qr-expired": "WalletConnect QR has expired",