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
Lungu Cristian c6a63e30b2 fix: usage of web3-wallet (#20864) 2024-07-24 13:54:30 +03:00
Lungu Cristian 07005f8ad5 Reject typeddata request when wrong chainId inside typed data (#20821)
* fix: reject typeddata request if wrong chainid

* fix: lint
2024-07-24 12:12:40 +03:00
Jamie Caprani 3ab345563c fix(wallet): adjust max amount to not include network being bridged to (#20604) 2024-07-24 01:54:12 -07:00
51 changed files with 840 additions and 405 deletions
+2 -1
View File
@@ -74,7 +74,8 @@
;; https://github.com/borkdude/clj-kondo/issues/867
:unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY
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}
:unsorted-required-namespaces {:level :error}
: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",
"jar": {
"sha1": "4c94bd510f0c18a20191e46dd6becedebc640bbd",
"sha256": "0wpla2hx0s4mda58ndyd8938zmnz1gyhgfr6pzfphy27xfbvsssl"
"sha1": "f0830a112cae8ee931a90d9f39214a0ed4d44150",
"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
nrepl/bencode/1.1.0/bencode-1.1.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-launcher/1.10.11/ant-launcher-1.10.11.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"]
[org.slf4j/slf4j-nop "2.0.9"]
[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.
[clj-kondo/clj-kondo "2024.03.13"]
-1
View File
@@ -18,7 +18,6 @@
legacy.status-im.multiaccounts.logout.core
[legacy.status-im.multiaccounts.model :as multiaccounts.model]
legacy.status-im.multiaccounts.update.core
legacy.status-im.network.net-info
legacy.status-im.pairing.core
legacy.status-im.profile.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]
[react-native.platform :as utils.platform]
[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.navigation.events :as navigation]
[taoensso.timbre :as log]
@@ -220,6 +221,12 @@
:name (:name 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
[{:keys [db]} installations]
{:db (update db
@@ -228,7 +235,10 @@
(fn [acc {:keys [id] :as 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
{:events [:pairing.callback/get-our-installations-success]}
@@ -243,6 +253,24 @@
{}
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
{:events [:pairing.callback/enable-installation-success]}
[cofx installation-id]
-2
View File
@@ -15,8 +15,6 @@
(reg-root-key-sub :visibility-status-updates :visibility-status-updates)
(reg-root-key-sub :fleets/custom-fleets :custom-fleets)
(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 :peers-summary :peers-summary)
(reg-root-key-sub :web3-node-version :web3-node-version)
+1 -1
View File
@@ -127,7 +127,7 @@
[:app-state
:current-chat-id
:network
:network-status
:network/status
:peers-summary
:sync-state
:view-id
+1 -1
View File
@@ -171,7 +171,7 @@
#js
{:getEnforcing {}})
(def net-info #js {})
(def net-info #js {:addEventListener identity})
(def react-native-biometrics #js {:default {}})
(def react-native-static-safe-area-insets #js {:default {}})
+5 -4
View File
@@ -23,7 +23,7 @@
(oops/ocall wc-utils
"buildApprovedNamespaces"
(bean/->js {:proposal proposal
:supportedNamespaces supported-namespaces})))
:supportedNamespaces (clj->js supported-namespaces)})))
;; Get an error from this list:
;; https://github.com/WalletConnect/walletconnect-monorepo/blob/c6e9529418a0c81d4efcc6ac4e61f242a50b56c5/packages/utils/src/errors.ts
@@ -51,9 +51,10 @@
(defn reject-session
[{:keys [web3-wallet id reason]}]
(.rejectSession web3-wallet
(clj->js {:id id
:reason reason})))
(oops/ocall web3-wallet
"rejectSession"
(bean/->js {:id id
:reason reason})))
(defn approve-session
[{:keys [web3-wallet id approved-namespaces]}]
@@ -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]}
[_]
{: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 [:navigate-to-within-stack
[:screen/onboarding.welcome
:screen/onboarding.generating-keys]]))
:screen/onboarding.enable-notifications]]))
:type :primary
:icon-left :i/notifications
:accessibility-label :enable-notifications-button
@@ -52,7 +52,7 @@
nil)
(rf/dispatch [:navigate-to-within-stack
[:screen/onboarding.welcome
:screen/onboarding.generating-keys]]))
:screen/onboarding.enable-notifications]]))
:accessibility-label :enable-notifications-later-button
:type :grey
:background :blur
+22 -16
View File
@@ -125,25 +125,31 @@
mnemonic key-uid]))
on-error]})
;; TODO: clear syncing data if key-uid does not match
(rf/defn seed-phrase-validated
{:events [:onboarding/seed-phrase-validated]}
[{:keys [db]} seed-phrase key-uid]
(if (contains? (:profile/profiles-overview db) key-uid)
{:effects.utils/show-confirmation
{:title (i18n/label :t/multiaccount-exists-title)
:content (i18n/label :t/multiaccount-exists-content)
:confirm-button-text (i18n/label :t/unlock)
:on-accept (fn []
(re-frame/dispatch [:pop-to-root :screen/profile.profiles])
(re-frame/dispatch
[:profile/profile-selected key-uid]))
:on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}}
{:db (assoc-in db [:onboarding/profile :seed-phrase] seed-phrase)
:dispatch [:navigate-to-within-stack
[:screen/onboarding.create-profile
(get db
:onboarding/navigated-to-enter-seed-phrase-from-screen
:screen/onboarding.new-to-status)]]}))
(let [next-screen (if (and (seq (:syncing/key-uid db))
(= (:syncing/key-uid db) key-uid))
:screen/onboarding.create-profile-password
:screen/onboarding.create-profile)]
(if (contains? (:profile/profiles-overview db) key-uid)
{:effects.utils/show-confirmation
{:title (i18n/label :t/multiaccount-exists-title)
:content (i18n/label :t/multiaccount-exists-content)
:confirm-button-text (i18n/label :t/unlock)
:on-accept (fn []
(re-frame/dispatch [:pop-to-root :screen/profile.profiles])
(re-frame/dispatch
[:profile/profile-selected key-uid]))
:on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}}
{: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
{:events [:onboarding/navigate-to-create-profile]}
@@ -2,6 +2,13 @@
(:require
[quo.foundations.colors :as colors]))
(def absolute-fill
{:position :absolute
:top 0
:bottom 0
:left 0
:right 0})
(defn page-container
[in-onboarding?]
{:flex 1
@@ -26,33 +26,62 @@
:title-accessibility-label :progress-screen-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
[profile-color in-onboarding? logged-in?]
[quo/button
{:on-press (fn []
(rf/dispatch [:syncing/clear-states])
(cond
logged-in? (rf/dispatch [:navigate-back])
in-onboarding? (rf/dispatch [:navigate-back-to
: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)])
[profile-color in-onboarding? logged-in? view-id]
[rn/view
(when-not logged-in?
[quo/button
{:on-press #(navigate-to-enter-seed-phrase view-id)
:accessibility-label :try-seed-phrase-button
:customization-color profile-color
:container-style style/try-again-button}
(i18n/label :t/enter-seed-phrase)])
[quo/button
{:on-press (fn []
(rf/dispatch [:syncing/clear-states])
(cond
logged-in? (rf/dispatch [:navigate-back])
in-onboarding? (rf/dispatch [:navigate-back-to
: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
[in-onboarding?]
(let [pairing-status (rf/sub [:pairing/pairing-status])
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?)}
(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}]
[page-title (pairing-progress pairing-status)]
(if config/show-not-implemented-features?
@@ -63,7 +92,7 @@
[quo/text "[Error here]"]])
[rn/view {:flex 1}])
(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
[]
@@ -3,6 +3,13 @@
[quo.foundations.colors :as colors]
[react-native.reanimated :as reanimated]))
(def absolute-fill
{:position :absolute
:top 0
:bottom 0
:left 0
:right 0})
(defn page-container
[top]
{:flex 1
@@ -66,7 +66,8 @@
translate-x (reanimated/use-shared-value 0)
window-width (:width (rn/get-window))]
[rn/view {:style (style/page-container top)}
[background/view true]
[rn/view {:style style/absolute-fill}
[background/view true]]
[reanimated/view
{:style (style/content translate-x)}
[page-title]
@@ -124,6 +124,8 @@
:on-success [:profile.login/node-info-fetched]
:on-error #(log/error "node-info: failed error" %)}]]
[:pairing/get-our-installations]
(when (:syncing/installation-id db)
[:dispatch [:pairing/finish-seed-phrase-fallback-syncing]])
(when-not new-account?
[:dispatch [:universal-links/process-stored-event]])]})))
@@ -2,6 +2,7 @@
(:require
[native-module.core :as native-module]
[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.recover.effects
[utils.re-frame :as rf]
@@ -17,11 +18,11 @@
(assoc-in [:syncing :login-sha3-password] login-sha3-password))
:effects.profile/restore-and-login
(merge (profile.config/create)
{:displayName display-name
:mnemonic (security/safe-unmask-data seed-phrase)
:password login-sha3-password
:imagePath (profile.config/strip-file-prefix image-path)
:customizationColor color
:emoji (emoji-picker.utils/random-emoji)
:fetchBackup true})}))
(assoc (profile.config/create)
:displayName display-name
:mnemonic (security/safe-unmask-data seed-phrase)
:password login-sha3-password
:imagePath (profile.config/strip-file-prefix image-path)
:customizationColor (or color constants/profile-default-color)
:emoji (emoji-picker.utils/random-emoji)
:fetchBackup true)}))
@@ -7,6 +7,7 @@
[react-native.safe-area :as safe-area]
[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.wallet.common.utils :as utils]
[status-im.contexts.wallet.common.validation :as validation]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
@@ -18,20 +19,21 @@
(defn- validate-input
[account-addresses saved-addresses user-input]
(cond
(string/blank? user-input)
nil
(let [[_ address-without-prefix] (utils/split-prefix-and-address user-input)]
(cond
(string/blank? user-input)
nil
(contains? saved-addresses user-input)
:existing-saved-address
(contains? saved-addresses address-without-prefix)
:existing-saved-address
(contains? account-addresses user-input)
:own-account
(contains? account-addresses address-without-prefix)
:own-account
(not
(or (validation/eth-address? user-input)
(validation/ens-name? user-input)))
:invalid-address-or-ens))
(not
(or (validation/eth-address? user-input)
(validation/ens-name? user-input)))
:invalid-address-or-ens)))
(defn- address-input
[{:keys [input-value on-change-text paste-into-input clear-input]}]
@@ -93,8 +95,9 @@
(defn- existing-saved-address
[{:keys [address]}]
(let [{:keys [name customization-color chain-short-names ens ens?]}
(rf/sub [:wallet/saved-address-by-address address])]
(let [[_ address-without-prefix] (utils/split-prefix-and-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}
[quo/text
{:size :paragraph-1
@@ -105,7 +108,7 @@
{:blur? true
:active-state? true
:user-props {:name name
:address (str chain-short-names address)
:address (str chain-short-names address-without-prefix)
:ens (when ens? ens)
:customization-color customization-color
:blur? true}
@@ -168,20 +171,21 @@
(rn/use-mount #(rf/dispatch [:wallet/clear-address-to-save]))
[quo/overlay {:type :shell}
[floating-button-page/view
{:footer-container-padding 0
:header [quo/page-nav
{:type :no-title
:icon-name :i/close
:behind-overlay? true
:on-press navigate-back
:margin-top (safe-area/get-top)
:accessibility-label :add-address-to-save-page-nav}]
:footer (when (= view-id :screen/settings.add-address-to-save)
[quo/button
{:customization-color profile-color
:disabled? button-disabled?
:on-press on-press-continue}
(i18n/label :t/continue)])}
{:footer-container-padding 0
:keyboard-should-persist-taps :handled
:header [quo/page-nav
{:type :no-title
:icon-name :i/close
:behind-overlay? true
:on-press navigate-back
:margin-top (safe-area/get-top)
:accessibility-label :add-address-to-save-page-nav}]
:footer (when (= view-id :screen/settings.add-address-to-save)
[quo/button
{:customization-color profile-color
:disabled? button-disabled?
:on-press on-press-continue}
(i18n/label :t/continue)])}
[quo/page-top
{:container-style style/header-container
:blur? true
@@ -105,24 +105,25 @@
[ens ens? open-network-preferences address-text])]
[quo/overlay {:type :shell}
[floating-button-page/view
{:footer-container-padding (if edit? (+ (safe-area/get-bottom) 12) 0)
:header [quo/page-nav
{:type :no-title
:background :blur
:icon-name (if edit? :i/close :i/arrow-left)
:on-press navigate-back
:margin-top (when-not edit? (safe-area/get-top))
:accessibility-label :save-address-page-nav}]
:footer [quo/button
{:accessibility-label :save-address-button
:type :primary
:customization-color address-color
:disabled? (string/blank? address-label)
:on-press on-press-save}
(i18n/label :t/save-address)]
:customization-color address-color
:gradient-cover? true
:shell-overlay? true}
{:footer-container-padding (if edit? (+ (safe-area/get-bottom) 12) 0)
:keyboard-should-persist-taps :handled
:header [quo/page-nav
{:type :no-title
:background :blur
:icon-name (if edit? :i/close :i/arrow-left)
:on-press navigate-back
:margin-top (when-not edit? (safe-area/get-top))
:accessibility-label :save-address-page-nav}]
:footer [quo/button
{:accessibility-label :save-address-button
:type :primary
:customization-color address-color
:disabled? (string/blank? address-label)
:on-press on-press-save}
(i18n/label :t/save-address)]
:customization-color address-color
:gradient-cover? true
:shell-overlay? true}
[quo/wallet-user-avatar
{:full-name (if (string/blank? address-label)
placeholder
+20 -3
View File
@@ -46,13 +46,29 @@
(log/info "[local-pairing] input-connection-string-for-bootstrapping callback"
{:response res
:event :syncing/input-connection-string-for-bootstrapping})
(let [error (when (sync-utils/extract-error res)
(str "generic-error: " res))]
(when (some? error)
(let [response (transforms/json->clj res)
installation-id (:installationId response)
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
{:type :negative
: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
{:events [:syncing/preflight-outbound-check]}
[_ set-checks-passed]
@@ -96,6 +112,7 @@
(when (sync-utils/valid-connection-string? response)
(on-valid-connection-string response)
(rf/dispatch [:syncing/update-role constants/local-pairing-role-sender])
(rf/dispatch [:syncing/initiate-pairing-process])
(rf/dispatch [:hide-bottom-sheet])))]
(when-not (and error (string/blank? error))
(let [key-uid (get-in db [:profile/profile :key-uid])
@@ -12,13 +12,16 @@
(hot-reload/use-safe-unmount #(rf/dispatch [:wallet/clean-routes-calculation]))
[rn/view {:style style/bridge-send-wrapper}
[input-amount/view
{:current-screen-id :screen/wallet.bridge-input-amount
:button-one-label (i18n/label :t/review-bridge)
:button-one-props {:icon-left :i/bridge}
:on-confirm (fn [amount]
(rf/dispatch [:wallet/set-token-amount-to-bridge
{:amount amount
:stack-id :screen/wallet.bridge-input-amount}]))
:on-navigate-back (fn []
(rf/dispatch [:wallet/clean-disabled-from-networks])
(rf/dispatch [:wallet/clean-send-amount]))}]])
{:current-screen-id :screen/wallet.bridge-input-amount
:button-one-label (i18n/label :t/review-bridge)
:button-one-props {:icon-left :i/bridge}
:enabled-from-chain-ids (rf/sub
[:wallet/bridge-from-chain-ids])
:from-enabled-networks (rf/sub [:wallet/bridge-from-networks])
:on-confirm (fn [amount]
(rf/dispatch [:wallet/set-token-amount-to-bridge
{:amount amount
:stack-id :screen/wallet.bridge-input-amount}]))
:on-navigate-back (fn []
(rf/dispatch [:wallet/clean-disabled-from-networks])
(rf/dispatch [:wallet/clean-send-amount]))}]])
@@ -1,7 +1,6 @@
(ns status-im.contexts.wallet.data-store-test
(:require
[cljs.test :refer-macros [deftest is testing]]
[matcher-combinators.matchers :as matchers]
matcher-combinators.test
[status-im.contexts.wallet.data-store :as sut]))
@@ -162,82 +161,73 @@
(deftest reconcile-keypairs-test
(testing "reconcile-keypairs represents updated key pairs and accounts"
(is
(match?
(matchers/match-with
[set? matchers/set-equals
map? matchers/equals]
{:removed-keypair-ids #{}
:removed-account-addresses #{}
:updated-accounts-by-address {"1x123" (merge account
{:key-uid "0x123"
:address "1x123"})
"1x456" (merge account
{:key-uid "0x456"
:address "1x456"
:operable? false
:operable :no})}
:updated-keypairs-by-id {"0x123" {:key-uid "0x123"
:type :seed
:lowest-operability :fully
:accounts [(merge account
{:key-uid "0x123"
:address "1x123"})]}
"0x456" {:key-uid "0x456"
:type :key
:lowest-operability :no
:accounts [(merge account
{:key-uid "0x456"
:address "1x456"
:operable? false
:operable :no})]}}})
(match-strict?
{:removed-keypair-ids #{}
:removed-account-addresses #{}
:updated-accounts-by-address {"1x123" (merge account
{:key-uid "0x123"
:address "1x123"})
"1x456" (merge account
{:key-uid "0x456"
:address "1x456"
:operable? false
:operable :no})}
:updated-keypairs-by-id {"0x123" {:key-uid "0x123"
:type :seed
:lowest-operability :fully
:accounts [(merge account
{:key-uid "0x123"
:address "1x123"})]}
"0x456" {:key-uid "0x456"
:type :key
:lowest-operability :no
:accounts [(merge account
{:key-uid "0x456"
:address "1x456"
:operable? false
:operable :no})]}}}
(sut/reconcile-keypairs [raw-keypair-seed-phrase
raw-keypair-private-key]))))
(testing "reconcile-keypairs represents removed key pairs and accounts"
(is
(match?
(matchers/match-with
[set? matchers/set-equals
map? matchers/equals]
{:removed-keypair-ids #{"0x456"}
:removed-account-addresses #{"1x456"}
:updated-accounts-by-address {"1x123" (merge account
{:key-uid "0x123"
:address "1x123"})}
:updated-keypairs-by-id {"0x123" {:key-uid "0x123"
:type :seed
:lowest-operability :fully
:accounts [(merge account
{:key-uid "0x123"
:address "1x123"})]}}})
(match-strict?
{:removed-keypair-ids #{"0x456"}
:removed-account-addresses #{"1x456"}
:updated-accounts-by-address {"1x123" (merge account
{:key-uid "0x123"
:address "1x123"})}
:updated-keypairs-by-id {"0x123" {:key-uid "0x123"
:type :seed
:lowest-operability :fully
:accounts [(merge account
{:key-uid "0x123"
:address "1x123"})]}}}
(sut/reconcile-keypairs [raw-keypair-seed-phrase
(assoc raw-keypair-private-key :removed true)]))))
(testing "reconcile-keypairs ignores chat accounts inside updated accounts"
(is
(match?
(matchers/match-with
[set? matchers/set-equals
map? matchers/equals]
{:removed-keypair-ids #{}
:removed-account-addresses #{}
:updated-accounts-by-address {"2x000" (merge account
{:key-uid "0x000"
:address "2x000"
:chat false
:wallet true
:default-account? true})}
:updated-keypairs-by-id {"0x000" {:key-uid "0x000"
:type :profile
:lowest-operability :fully
:accounts [(merge account
{:key-uid "0x000"
:address "1x000"
:chat true
:wallet false
:default-account? false})
(merge account
{:key-uid "0x000"
:address "2x000"
:chat false
:wallet true
:default-account? true})]}}})
(match-strict?
{:removed-keypair-ids #{}
:removed-account-addresses #{}
:updated-accounts-by-address {"2x000" (merge account
{:key-uid "0x000"
:address "2x000"
:chat false
:wallet true
:default-account? true})}
:updated-keypairs-by-id {"0x000" {:key-uid "0x000"
:type :profile
:lowest-operability :fully
:accounts [(merge account
{:key-uid "0x000"
:address "1x000"
:chat true
:wallet false
:default-account? false})
(merge account
{:key-uid "0x000"
:address "2x000"
:chat false
:wallet true
:default-account? true})]}}}
(sut/reconcile-keypairs [raw-keypair-profile])))))
@@ -146,6 +146,8 @@
button-one-props :button-one-props
current-screen-id :current-screen-id
initial-crypto-currency? :initial-crypto-currency?
enabled-from-chain-ids :enabled-from-chain-ids
from-enabled-networks :from-enabled-networks
:or {initial-crypto-currency? true}}]
(let [_ (rn/dismiss-keyboard!)
bottom (safe-area/get-bottom)
@@ -164,9 +166,6 @@
token-decimals :decimals
:as
token} (rf/sub [:wallet/wallet-send-token])
send-enabled-networks (rf/sub [:wallet/wallet-send-enabled-networks])
enabled-from-chain-ids (rf/sub
[:wallet/wallet-send-enabled-from-chain-ids])
send-from-locked-amounts (rf/sub [:wallet/wallet-send-from-locked-amounts])
{token-balance :total-balance
available-balance :available-balance
@@ -355,7 +354,7 @@
:currency-symbol currency-symbol
:crypto-decimals (min token-decimals 6)
:error? (controlled-input/input-error input-state)
:networks (seq send-enabled-networks)
:networks (seq from-enabled-networks)
:title (i18n/label
:t/send-limit
{:limit (if crypto-currency?
@@ -429,3 +428,4 @@
(set-just-toggled-mode? false)
(set-input-state controlled-input/delete-all)
(rf/dispatch [:wallet/clean-suggested-routes]))}]]))
@@ -8,9 +8,12 @@
(defn view
[]
[input-amount/view
{:current-screen-id :screen/wallet.send-input-amount
:button-one-label (i18n/label :t/review-send)
:on-navigate-back (fn []
(rf/dispatch [:wallet/clean-disabled-from-networks])
(rf/dispatch [:wallet/clean-from-locked-amounts])
(rf/dispatch [:wallet/clean-send-amount]))}])
{:current-screen-id :screen/wallet.send-input-amount
:button-one-label (i18n/label :t/review-send)
:enabled-from-chain-ids (rf/sub
[:wallet/wallet-send-enabled-from-chain-ids])
:from-enabled-networks (rf/sub [:wallet/wallet-send-enabled-networks])
:on-navigate-back (fn []
(rf/dispatch [:wallet/clean-disabled-from-networks])
(rf/dispatch [:wallet/clean-from-locked-amounts])
(rf/dispatch [:wallet/clean-send-amount]))}])
@@ -3,6 +3,7 @@
[clojure.string :as string]
[native-module.core :as native-module]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.utils.networks :as networks]
[utils.security.core :as security]
[utils.string]
[utils.transforms :as transforms]))
@@ -101,7 +102,7 @@
networks (get-in db [:wallet :networks (if test-mode? :test :prod)])]
(mapv #(-> % :chain-id) networks)))
(defn add-full-testnet-name
(defn- add-full-testnet-name
"Updates the `:full-name` key with the full testnet name if using testnet `:chain-id`.\n
e.g. `{:full-name \"Mainnet\"}` -> `{:full-name \"Mainnet Sepolia\"`}`"
[network]
@@ -112,6 +113,12 @@
constants/goerli-chain-ids (add-testnet-name constants/goerli-full-name)
network)))
(defn chain-id->network-details
[chain-id]
(-> chain-id
(networks/get-network-details)
(add-full-testnet-name)))
(defn event-should-be-handled?
[db {:keys [topic]}]
(some #(= topic %)
@@ -50,11 +50,15 @@
(rf/reg-fx
: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
approved-namespaces (wallet-connect/build-approved-namespaces
params
supported-namespaces)]
approved-namespaces (->> {:eip155
{:chains networks
:accounts accounts
:methods constants/wallet-connect-supported-methods
:events constants/wallet-connect-supported-events}}
(wallet-connect/build-approved-namespaces
params))]
(-> (wallet-connect/approve-session
{:web3-wallet web3-wallet
:id id
@@ -13,10 +13,14 @@
(rf/reg-event-fx
:wallet-connect/init
(fn []
{:fx [[:effects.wallet-connect/init
{:on-success #(rf/dispatch [:wallet-connect/on-init-success %])
:on-fail #(rf/dispatch [:wallet-connect/on-init-fail %])}]]}))
(fn [{:keys [db]}]
(let [network-status (:network/status db)]
(if (= network-status :online)
{: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
:wallet-connect/on-init-success
@@ -25,6 +29,14 @@
:fx [[:dispatch [:wallet-connect/register-event-listeners]]
[: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
:wallet-connect/register-event-listeners
(fn [{:keys [db]}]
@@ -77,12 +89,12 @@
(rf/reg-event-fx
:wallet-connect/session-networks-unsupported
(fn [_ [proposal]]
(fn [{:keys [db]} [proposal]]
(let [{:keys [name]} (wallet-connect-core/get-session-dapp-metadata proposal)]
{:fx [[:dispatch
[:toasts/upsert
{:type :negative
:theme :dark
:theme (:theme db)
:text (i18n/label :t/wallet-connect-networks-not-supported {:dapp name})}]]]})))
(rf/reg-event-fx
@@ -116,17 +128,20 @@
(rf/reg-event-fx
:wallet-connect/disconnect-dapp
(fn [{:keys [db]} [{:keys [topic on-success on-fail]}]]
(let [web3-wallet (get db :wallet-connect/web3-wallet)]
{:fx [[:effects.wallet-connect/disconnect
{:web3-wallet web3-wallet
:topic topic
:reason (wallet-connect/get-sdk-error
constants/wallet-connect-user-disconnected-reason-key)
:on-fail on-fail
:on-success (fn []
(rf/dispatch [:wallet-connect/disconnect-session topic])
(when on-success
(on-success)))}]]})))
(let [web3-wallet (get db :wallet-connect/web3-wallet)
network-status (:network/status db)]
(if (= network-status :online)
{:fx [[:effects.wallet-connect/disconnect
{:web3-wallet web3-wallet
:topic topic
:reason (wallet-connect/get-sdk-error
constants/wallet-connect-user-disconnected-reason-key)
:on-fail on-fail
:on-success (fn []
(rf/dispatch [:wallet-connect/disconnect-session topic])
(when on-success
(on-success)))}]]}
{:fx [[:dispatch [:wallet-connect/no-internet-toast]]]}))))
(rf/reg-event-fx
:wallet-connect/pair
@@ -141,51 +156,57 @@
(rf/reg-event-fx
:wallet-connect/approve-session
(fn [{:keys [db]}]
(let [web3-wallet (get db :wallet-connect/web3-wallet)
current-proposal (get-in db [:wallet-connect/current-proposal :request])
session-networks (->> (get-in db [:wallet-connect/current-proposal :session-networks])
(map wallet-connect-core/chain-id->eip155)
vec)
current-address (get-in db [:wallet-connect/current-proposal :address])
accounts (-> (partial wallet-connect-core/format-eip155-address current-address)
(map session-networks))
supported-namespaces (clj->js {:eip155
{:chains session-networks
:methods constants/wallet-connect-supported-methods
:events constants/wallet-connect-supported-events
:accounts accounts}})]
{:fx [[:effects.wallet-connect/approve-session
{:web3-wallet web3-wallet
:proposal current-proposal
:supported-namespaces supported-namespaces
:on-success (fn [approved-session]
(log/info "Wallet Connect session approved")
(rf/dispatch [:wallet-connect/reset-current-session-proposal])
(rf/dispatch [:wallet-connect/persist-session approved-session]))
:on-fail (fn [error]
(log/error "Wallet Connect session approval failed"
{:error error
:event :wallet-connect/approve-session})
(rf/dispatch
[:wallet-connect/reset-current-session-proposal]))}]
[:dispatch [:dismiss-modal :screen/wallet.wallet-connect-session-proposal]]]})))
(let [web3-wallet (get db :wallet-connect/web3-wallet)
current-proposal (get-in db [:wallet-connect/current-proposal :request])
session-networks (->> (get-in db [:wallet-connect/current-proposal :session-networks])
(map wallet-connect-core/chain-id->eip155)
vec)
current-address (get-in db [:wallet-connect/current-proposal :address])
accounts (-> (partial wallet-connect-core/format-eip155-address current-address)
(map session-networks))
network-status (:network/status db)]
(if (= network-status :online)
{:fx [[:effects.wallet-connect/approve-session
{:web3-wallet web3-wallet
:proposal current-proposal
:networks session-networks
:accounts accounts
:on-success (fn [approved-session]
(log/info "Wallet Connect session approved")
(rf/dispatch [:wallet-connect/reset-current-session-proposal])
(rf/dispatch [:wallet-connect/persist-session approved-session]))
:on-fail (fn [error]
(log/error "Wallet Connect session approval failed"
{:error error
:event :wallet-connect/approve-session})
(rf/dispatch
[:wallet-connect/reset-current-session-proposal]))}]
[:dispatch [:dismiss-modal :screen/wallet.wallet-connect-session-proposal]]]}
{:fx [[:dispatch [:wallet-connect/no-internet-toast]]]}))))
(rf/reg-event-fx
:wallet-connect/on-scan-connection
(fn [_ [scanned-text]]
(let [parsed-uri (wallet-connect/parse-uri scanned-text)
(fn [{:keys [db]} [scanned-text]]
(let [network-status (:network/status db)
parsed-uri (wallet-connect/parse-uri scanned-text)
version (:version parsed-uri)
valid-wc-uri? (wc-utils/valid-wc-uri? parsed-uri)
expired? (-> parsed-uri
:expiryTimestamp
wc-utils/timestamp-expired?)
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
[:toasts/upsert
{:type :negative
: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)
expired?
@@ -236,16 +257,18 @@
(rf/reg-event-fx
:wallet-connect/fetch-persisted-sessions-success
(fn [{:keys [db]} [sessions]]
(let [sessions' (mapv (fn [{:keys [sessionJson] :as session}]
(assoc session
:accounts
(-> sessionJson
types/json->clj
:namespaces
:eip155
:accounts)))
sessions)]
{:fx [[:dispatch [:wallet-connect/fetch-active-sessions]]]
(let [network-status (:network/status db)
sessions' (mapv (fn [{:keys [sessionJson] :as session}]
(assoc session
:accounts
(-> sessionJson
types/json->clj
:namespaces
:eip155
:accounts)))
sessions)]
{:fx [(when (= network-status :online)
[:dispatch [:wallet-connect/fetch-active-sessions]])]
:db (assoc db :wallet-connect/sessions sessions')})))
(rf/reg-event-fx
@@ -256,14 +279,14 @@
(rf/reg-event-fx
:wallet-connect/fetch-persisted-sessions
(fn [_ _]
{:fx [[:json-rpc/call
[{:method "wallet_getWalletConnectActiveSessions"
;; This is the activeSince timestamp to avoid expired sessions
;; 0 means, return everything
:params [0]
:on-success [:wallet-connect/fetch-persisted-sessions-success]
:on-error [:wallet-connect/fetch-persisted-sessions-fail]}]]]}))
(fn [{:keys [now]} _]
(let [current-timestamp (quot now 1000)]
{:fx [[:json-rpc/call
[{:method "wallet_getWalletConnectActiveSessions"
;; NOTE: This is the activeSince timestamp to avoid expired sessions
:params [current-timestamp]
:on-success [:wallet-connect/fetch-persisted-sessions-success]
:on-error [:wallet-connect/fetch-persisted-sessions-fail]}]]]})))
(rf/reg-event-fx
:wallet-connect/persist-session
@@ -290,3 +313,12 @@
:params [topic]
:on-success #(log/info "Wallet Connect session disconnected")
: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]))
(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])
offline? (rf/sub [:network/offline?])
theme (quo.theme/use-theme)]
[rn/view {:style style/content-container}
(into [rn/view
{:style style/data-items-container}]
children)
[rn/view {:style style/auth-container}
[standard-authentication/slide-button
{:size :size-48
:track-text slide-button-text
:disabled? disabled?
:customization-color customization-color
:on-auth-success on-auth-success
:auth-button-label (i18n/label :t/confirm)}]]
[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]]]))
[:<>
(when (or offline? error-text)
[quo/alert-banner
{:action? false
:text (if offline?
(i18n/label :t/wallet-connect-no-internet-warning)
error-text)}])
[rn/view {:style style/content-container}
(into [rn/view
{:style style/data-items-container}]
children)
[rn/view {:style style/auth-container}
[standard-authentication/slide-button
{:size :size-48
:track-text slide-button-text
:disabled? (or offline? (seq error-text))
:customization-color customization-color
:on-auth-success on-auth-success
:auth-button-label (i18n/label :t/confirm)}]]
[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]]]]))
@@ -7,6 +7,6 @@
[quo/page-nav
{:icon-name :i/close
:background :blur
:on-press #(do (rf/dispatch [:navigate-back])
:on-press #(do (rf/dispatch [:wallet-connect/dismiss-request-modal])
(rf/dispatch [:wallet-connect/reject-session-request]))
:accessibility-label accessibility-label}])
@@ -33,19 +33,16 @@
:dapp dapp
:account account}]
[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
{:warning-label (i18n/label :t/wallet-connect-sign-warning)
: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
{:status :default
:card? false
@@ -32,19 +32,16 @@
:dapp dapp
:account account}]
[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
{:warning-label (i18n/label :t/wallet-connect-sign-warning)
: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
{:status :default
:card? false
@@ -5,8 +5,10 @@
[re-frame.core :as rf]
[status-im.constants :as constants]
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
[status-im.contexts.wallet.wallet-connect.signing :as signing]
[status-im.contexts.wallet.wallet-connect.transactions :as transactions]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.transforms :as transforms]))
(rf/reg-event-fx
@@ -122,15 +124,30 @@
:wallet-connect/process-sign-typed
(fn [{:keys [db]}]
(let [[address raw-data] (wallet-connect-core/get-db-current-request-params db)
parsed-data (try (-> raw-data
transforms/js-parse
parsed-raw-data (transforms/js-parse raw-data)
session-chain-id (-> (wallet-connect-core/get-db-current-request-event db)
(get-in [:params :chainId])
wallet-connect-core/eip155->chain-id)
data-chain-id (-> parsed-raw-data
transforms/js->clj
signing/typed-data-chain-id)
parsed-data (try (-> parsed-raw-data
(transforms/js-dissoc :types :primaryType)
(transforms/js-stringify 2))
(catch js/Error _ nil))]
(if (nil? parsed-data)
(cond
(nil? parsed-data)
{:fx [[:dispatch
[:wallet-connect/on-processing-error
(ex-info "Failed to parse JSON typed data" {:data raw-data})]]]}
(not= session-chain-id data-chain-id)
{:fx [[:dispatch
[:wallet-connect/wrong-typed-data-chain-id
{:expected-chain-id session-chain-id
:wrong-chain-id data-chain-id}]]]}
:else
{:db (update-in db
[:wallet-connect/current-request]
assoc
@@ -139,19 +156,39 @@
:raw-data raw-data)
:fx [[:dispatch [:wallet-connect/show-request-modal]]]}))))
(rf/reg-event-fx
:wallet-connect/wrong-typed-data-chain-id
(fn [_ [{:keys [expected-chain-id wrong-chain-id]}]]
(let [wrong-network-name (-> wrong-chain-id
wallet-connect-core/chain-id->network-details
:full-name)
expected-network-name (-> expected-chain-id
wallet-connect-core/chain-id->network-details
:full-name)
toast-message (i18n/label :t/wallet-connect-typed-data-wrong-chain-id-warning
{:wrong-chain wrong-network-name
:expected-chain expected-network-name})]
{:fx [[:dispatch
[:toasts/upsert
{:type :negative
:theme :dark
:text toast-message}]]
[:dispatch
[:wallet-connect/on-processing-error
(ex-info "Can't proceed signing typed data due to wrong chain-id included in the data"
{:expected-chain-id expected-chain-id
:wrong-chain-id wrong-chain-id})]]]})))
;; TODO: we should reject a request if processing fails
(rf/reg-event-fx
:wallet-connect/on-processing-error
(fn [{:keys [db]} [error]]
(let [{:keys [address event]} (get db :wallet-connect/current-request)
method (wallet-connect-core/get-request-method event)
screen (wallet-connect-core/method-to-screen method)]
method (wallet-connect-core/get-request-method event)]
(log/error "Failed to process Wallet Connect request"
{:error error
:address address
:method method
:wallet-connect-event event
:event :wallet-connect/on-processing-error})
{:fx [[:dispatch [:dismiss-modal screen]]
[:dispatch [:wallet-connect/reset-current-request]]]})))
{:fx [[:dispatch [:wallet-connect/reject-session-request]]]})))
@@ -39,7 +39,7 @@
:data raw-data
:rpc-method rpc-method
:on-error #(rf/dispatch [:wallet-connect/on-sign-error %])
:on-success #(rf/dispatch [:wallet-connect/send-response {:result %}])}]]})))
:on-success #(rf/dispatch [:wallet-connect/finish-session-request %])}]]})))
(rf/reg-event-fx
:wallet-connect/respond-sign-typed-data
@@ -53,7 +53,7 @@
:chain-id chain-id
:version typed-data-version
:on-error #(rf/dispatch [:wallet-connect/on-sign-error %])
:on-success #(rf/dispatch [:wallet-connect/send-response {:result %}])}]]})))
:on-success #(rf/dispatch [:wallet-connect/finish-session-request %])}]]})))
(rf/reg-event-fx
:wallet-connect/respond-send-transaction-data
@@ -67,7 +67,7 @@
:tx-hash tx-hash
:tx-args tx-args
:on-error #(rf/dispatch [:wallet-connect/on-sign-error %])
:on-success #(rf/dispatch [:wallet-connect/send-response {:result %}])}]]})))
:on-success #(rf/dispatch [:wallet-connect/finish-session-request %])}]]})))
(rf/reg-event-fx
:wallet-connect/respond-sign-transaction-data
@@ -81,15 +81,13 @@
:tx-hash tx-hash
:tx-params tx-args
:on-error #(rf/dispatch [:wallet-connect/on-sign-error %])
:on-success #(rf/dispatch [:wallet-connect/send-response {:result %}])}]]})))
:on-success #(rf/dispatch [:wallet-connect/finish-session-request %])}]]})))
;; TODO: should reject if "signing" fails
(rf/reg-event-fx
:wallet-connect/on-sign-error
(fn [{:keys [db]} [error]]
(let [{:keys [raw-data address event]} (get db :wallet-connect/current-request)
method (wallet-connect-core/get-request-method event)
screen (wallet-connect-core/method-to-screen method)]
method (wallet-connect-core/get-request-method event)]
(log/error "Failed to sign Wallet Connect request"
{:error error
:address address
@@ -97,15 +95,14 @@
:method method
:wallet-connect-event event
:event :wallet-connect/on-sign-error})
{:fx [[:dispatch [:dismiss-modal screen]]
[:dispatch [:wallet-connect/reset-current-request]]]})))
{:fx [[:dispatch [:wallet-connect/reject-session-request]]
[:dispatch [:wallet-connect/dismiss-request-modal]]]})))
(rf/reg-event-fx
:wallet-connect/send-response
(fn [{:keys [db]} [{:keys [result error]}]]
(let [{:keys [id topic] :as event} (get-in db [:wallet-connect/current-request :event])
method (wallet-connect-core/get-request-method event)
screen (wallet-connect-core/method-to-screen method)
web3-wallet (get db :wallet-connect/web3-wallet)]
{:fx [[:effects.wallet-connect/respond-session-request
{:web3-wallet web3-wallet
@@ -119,13 +116,26 @@
:method method
:event :wallet-connect/send-response
:wallet-connect-event event})
(rf/dispatch [:dismiss-modal screen])
(rf/dispatch [:wallet-connect/reset-current-request]))
:on-success (fn []
(log/info "Successfully sent Wallet Connect response to dApp")
(rf/dispatch [:dismiss-modal screen])
(rf/dispatch [:wallet-connect/reset-current-request]))}]]})))
(rf/reg-event-fx
:wallet-connect/dismiss-request-modal
(fn [{:keys [db]} _]
(let [screen (-> db
(get-in [:wallet-connect/current-request :event])
wallet-connect-core/get-request-method
wallet-connect-core/method-to-screen)]
{:fx [[:dispatch [:dismiss-modal screen]]]})))
(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]]]}))
(rf/reg-event-fx
:wallet-connect/reject-session-proposal
(fn [{:keys [db]} _]
@@ -143,6 +153,8 @@
;; - Unsupported WC version
;; - Invalid params from dapps
;; - Unsupported method
;; - Failed processing of request
;; - Failed "responding" (signing or sending message/transaction)
(rf/reg-event-fx
:wallet-connect/reject-session-request
(fn [_ _]
@@ -6,6 +6,20 @@
[utils.hex :as hex]
[utils.transforms :as transforms]))
(defn typed-data-chain-id
"Returns the `:chain-id` from typed data if it's present and if the EIP712 domain defines it. Without
the `:chain-id` in the domain type, it will not be signed as part of the typed-data."
[typed-data]
(let [chain-id-type? (->> typed-data
:types
:EIP712Domain
(some #(= "chainId" (:name %))))
data-chain-id (-> typed-data
:domain
:chainId)]
(when chain-id-type?
data-chain-id)))
(defn eth-sign
[password address data]
(-> {:data data
+2 -1
View File
@@ -27,6 +27,7 @@
status-im.contexts.contact.blocking.events
status-im.contexts.keycard.effects
status-im.contexts.keycard.events
status-im.contexts.networks.events
status-im.contexts.onboarding.common.overlay.events
status-im.contexts.onboarding.events
status-im.contexts.profile.events
@@ -57,7 +58,7 @@
cofx
{:db db/app-db
:theme/init-theme nil
:network/listen-to-network-info nil
:effects.network/listen-to-network-info nil
:effects.biometric/get-supported-type nil
:effects.keycard/register-card-events nil
:effects.keycard/check-nfc-enabled nil
+6
View File
@@ -151,3 +151,9 @@
:<- [:toasts]
(fn [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?]}]
(boolean preview-privacy?)))
(re-frame/reg-sub :profile/installation-id
:<- [:profile/profile]
(fn [{:keys [installation-id]}]
installation-id))
(defn- replace-multiaccount-image-uri
[profile ens-names port font-file avatar-opts theme]
(let [{:keys [key-uid ens-name? images
+4
View File
@@ -44,6 +44,10 @@
;;push notifications
(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
(reg-root-key-sub :messenger/started? :messenger/started?)
(reg-root-key-sub :animations :animations)
+19
View File
@@ -61,3 +61,22 @@
:wallet/send-token-not-supported-in-receiver-networks?
:<- [:wallet/wallet-send]
:-> :token-not-supported-in-receiver-networks?)
(rf/reg-sub
:wallet/bridge-from-networks
:<- [:wallet/wallet-send]
:<- [:wallet/network-details]
(fn [[{:keys [bridge-to-chain-id]} networks]]
(set (filter (fn [network]
(not= (:chain-id network) bridge-to-chain-id))
networks))))
(rf/reg-sub
:wallet/bridge-from-chain-ids
:<- [:wallet/wallet-send]
:<- [:wallet/networks-by-mode]
(fn [[{:keys [bridge-to-chain-id]} networks]]
(keep (fn [network]
(when (not= (:chain-id network) bridge-to-chain-id)
(:chain-id network)))
networks)))
@@ -2,7 +2,6 @@
(:require [clojure.string :as string]
[re-frame.core :as rf]
[status-im.contexts.wallet.common.utils :as wallet-utils]
[status-im.contexts.wallet.common.utils.networks :as networks]
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
[status-im.contexts.wallet.wallet-connect.transactions :as transactions]
[utils.money :as money]
@@ -70,10 +69,7 @@
(rf/reg-sub
:wallet-connect/current-request-network
:<- [:wallet-connect/chain-id]
(fn [chain-id]
(-> chain-id
(networks/get-network-details)
(wallet-connect-core/add-full-testnet-name))))
wallet-connect-core/chain-id->network-details)
(rf/reg-sub
:wallet-connect/transaction-args
+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
layer."
(: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.db :as rf-db]
[re-frame.events :as rf-events]
[re-frame.registrar :as rf-registrar]
[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
"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>",
"owner": "status-im",
"repo": "status-go",
"version": "v0.182.37",
"commit-sha1": "4a43b2b2bebe45df2100d1a5c5034105d93e50b8",
"src-sha256": "0f5mm7lx6s2qcy9xpa9v7piqb60yazi6p677fy105yz7hg731cw6"
"version": "feat/enable_sync_fallback",
"commit-sha1": "880152abcac69bb7cf29088ce413d2c4e01be412",
"src-sha256": "067pj4xx0bph9573sdk57hdhq0xkaaz1zmgkk09d27a5fz2rdm4n"
}
+6
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-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-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-opensea": "Check on opensea",
"check-your-account-balance-and-activity": "Check your account balance and activity",
@@ -1626,6 +1627,7 @@
"new-community-title": "New community",
"new-contact": "New contact",
"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-group": "New group",
"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-would-like-to-use-camera": "would like to use your camera",
"pair": "Pair",
"pair-and-sync": "Pair and Sync",
"pair-card": "Pair to this device",
"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-placeholder": "Pair code...",
"pair-device-toast": "Device successfully paired",
"pair-devices": "Pair devices",
"pair-new-device-and-sync": "Pair new device and sync profile",
"pair-this-card": "Pair this card",
"pair-this-device": "Advertise device",
"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-label": "WalletConnect",
"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-title": "Would like to connect with your wallet",
"wallet-connect-qr-expired": "WalletConnect QR has expired",
@@ -2642,6 +2647,7 @@
"wallet-connect-sign-transaction-header": "wants you to sign this transaction with",
"wallet-connect-sign-transaction-warning": "Sign transactions only if you trust the dApp",
"wallet-connect-sign-warning": "Sign only if you trust the dApp",
"wallet-connect-typed-data-wrong-chain-id-warning": "Wrong network in the request data. Expected '{{expected-chain}}', but got '{{wrong-chain}}'",
"wallet-connect-version-not-supported": "WalletConnect version {{version}} is not supported",
"wallet-connect-via": "via",
"wallet-connect-wrong-qr": "Its not a WalletConnect QR",