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
This commit is contained in:
Lungu Cristian 2024-07-25 11:21:31 +03:00 committed by GitHub
parent 60ad7c8a29
commit cee21241d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 221 additions and 175 deletions

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

View File

@ -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?)))

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)

View File

@ -127,7 +127,7 @@
[:app-state
:current-chat-id
:network
:network-status
:network/status
:peers-summary
:sync-state
:view-id

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 {}})

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

View File

@ -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?)))

View File

@ -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

View File

@ -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)}]]]}))

View File

@ -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]]]]))

View File

@ -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

View File

@ -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

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

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)))

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)

View File

@ -2632,6 +2632,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",