mirror of
https://github.com/status-im/status-react.git
synced 2025-02-24 16:48:45 +00:00
* [#20150] feat: wallet connect pairing via deep links * [#20150] feat: redirect to the dapp after finish response * [#20150] test: add tests for events and utils * [#20150] fix: reviewer's feedback
This commit is contained in:
parent
e61702c8bb
commit
4a8bb704bf
@ -38,9 +38,12 @@
|
|||||||
[path]
|
[path]
|
||||||
(map #(str % path) status-web-urls))
|
(map #(str % path) status-web-urls))
|
||||||
|
|
||||||
|
|
||||||
(def handled-schemes (set (into uri-schemes status-web-urls)))
|
(def handled-schemes (set (into uri-schemes status-web-urls)))
|
||||||
|
|
||||||
|
(defn wc-normalize-uri
|
||||||
|
[uri]
|
||||||
|
(if (string/includes? uri "//wc:") (string/replace-first uri "/?" "?") uri))
|
||||||
|
|
||||||
(def group-chat-extractor
|
(def group-chat-extractor
|
||||||
{[#"(.*)" :params] {"" :group-chat
|
{[#"(.*)" :params] {"" :group-chat
|
||||||
"/" :group-chat}})
|
"/" :group-chat}})
|
||||||
@ -60,7 +63,9 @@
|
|||||||
["wallet/" :account] :wallet-account
|
["wallet/" :account] :wallet-account
|
||||||
[user-with-data-path :user-data] :user
|
[user-with-data-path :user-data] :user
|
||||||
"c" :community
|
"c" :community
|
||||||
"u" :user}
|
"u" :user
|
||||||
|
#"wc:([^\?]+)" :wallet-connect
|
||||||
|
"wc" :wallet-connect}
|
||||||
ethereum-scheme eip-extractor}])
|
ethereum-scheme eip-extractor}])
|
||||||
|
|
||||||
(defn parse-query-params
|
(defn parse-query-params
|
||||||
@ -75,6 +80,11 @@
|
|||||||
(when-not (string/blank? fragment)
|
(when-not (string/blank? fragment)
|
||||||
fragment)))
|
fragment)))
|
||||||
|
|
||||||
|
(defn remove-scheme
|
||||||
|
[uri]
|
||||||
|
(let [[_ url] (string/split uri #"://")]
|
||||||
|
url))
|
||||||
|
|
||||||
(defn match-uri
|
(defn match-uri
|
||||||
[uri]
|
[uri]
|
||||||
(let [;; bidi has trouble parse path with `=` in it extract `=` here and add back to parsed
|
(let [;; bidi has trouble parse path with `=` in it extract `=` here and add back to parsed
|
||||||
@ -88,13 +98,17 @@
|
|||||||
uri-without-equal-in-path
|
uri-without-equal-in-path
|
||||||
(if equal-end-of-base64url (string/replace-first uri equal-end-of-base64url "") uri)
|
(if equal-end-of-base64url (string/replace-first uri equal-end-of-base64url "") uri)
|
||||||
|
|
||||||
|
;;bidi has issue to detect wc regex with /?, couldn't fine any other workaround
|
||||||
|
normalize-uri
|
||||||
|
(wc-normalize-uri uri-without-equal-in-path)
|
||||||
|
|
||||||
;; fragment is the one after `#`, usually user-id, ens-name, community-id
|
;; fragment is the one after `#`, usually user-id, ens-name, community-id
|
||||||
fragment (parse-fragment uri)
|
fragment (parse-fragment uri)
|
||||||
ens? (utils.ens/is-valid-eth-name? fragment)
|
ens? (utils.ens/is-valid-eth-name? fragment)
|
||||||
compressed-key? (validators/valid-compressed-key? fragment)
|
compressed-key? (validators/valid-compressed-key? fragment)
|
||||||
|
|
||||||
{:keys [handler route-params] :as parsed}
|
{:keys [handler route-params query-params] :as parsed}
|
||||||
(assoc (bidi/match-route routes uri-without-equal-in-path)
|
(assoc (bidi/match-route routes normalize-uri)
|
||||||
:uri uri
|
:uri uri
|
||||||
:query-params (parse-query-params uri))]
|
:query-params (parse-query-params uri))]
|
||||||
(cond-> parsed
|
(cond-> parsed
|
||||||
@ -131,7 +145,13 @@
|
|||||||
(update-in [:route-params :user-data] #(str % equal-end-of-base64url))
|
(update-in [:route-params :user-data] #(str % equal-end-of-base64url))
|
||||||
|
|
||||||
(and (= handler :user) compressed-key?)
|
(and (= handler :user) compressed-key?)
|
||||||
(assoc-in [:route-params :user-id] fragment))))
|
(assoc-in [:route-params :user-id] fragment)
|
||||||
|
|
||||||
|
(= handler :wallet-connect)
|
||||||
|
(assoc-in [:route-params :uri]
|
||||||
|
(if (get query-params "uri")
|
||||||
|
(get query-params "uri")
|
||||||
|
(remove-scheme normalize-uri))))))
|
||||||
|
|
||||||
(defn match-contact-async
|
(defn match-contact-async
|
||||||
[chain {:keys [user-id ens-name]} callback]
|
[chain {:keys [user-id ens-name]} callback]
|
||||||
@ -328,6 +348,10 @@
|
|||||||
(= handler :wallet-account)
|
(= handler :wallet-account)
|
||||||
(cb (match-wallet-account route-params))
|
(cb (match-wallet-account route-params))
|
||||||
|
|
||||||
|
(= handler :wallet-connect)
|
||||||
|
(cb {:type :wallet-connect
|
||||||
|
:uri (:uri route-params)})
|
||||||
|
|
||||||
(address/address? uri)
|
(address/address? uri)
|
||||||
(cb (address->eip681 uri))
|
(cb (address->eip681 uri))
|
||||||
|
|
||||||
|
@ -105,6 +105,12 @@
|
|||||||
[full-url]
|
[full-url]
|
||||||
(log/info "universal-links: no handler for " full-url))
|
(log/info "universal-links: no handler for " full-url))
|
||||||
|
|
||||||
|
(rf/defn handle-wallet-connect
|
||||||
|
[_ uri]
|
||||||
|
(log/info "universal-links: handle-wallet-connect" uri)
|
||||||
|
{:dispatch-later {:ms 1500
|
||||||
|
:dispatch [:wallet-connect/on-scan-connection uri]}})
|
||||||
|
|
||||||
(defn dispatch-url
|
(defn dispatch-url
|
||||||
"Dispatch url so we can get access to re-frame/db"
|
"Dispatch url so we can get access to re-frame/db"
|
||||||
[url]
|
[url]
|
||||||
@ -117,7 +123,7 @@
|
|||||||
|
|
||||||
(rf/defn on-handle
|
(rf/defn on-handle
|
||||||
{:events [:universal-links/match-value]}
|
{:events [:universal-links/match-value]}
|
||||||
[cofx url {:keys [type chat-id community-id] :as data}]
|
[cofx url {:keys [type chat-id community-id uri] :as data}]
|
||||||
(case type
|
(case type
|
||||||
:group-chat (handle-group-chat cofx data)
|
:group-chat (handle-group-chat cofx data)
|
||||||
:private-chat (handle-private-chat cofx data)
|
:private-chat (handle-private-chat cofx data)
|
||||||
@ -130,6 +136,7 @@
|
|||||||
:browser (handle-browse cofx data)
|
:browser (handle-browse cofx data)
|
||||||
:eip681 (handle-eip681 cofx data)
|
:eip681 (handle-eip681 cofx data)
|
||||||
:wallet-account (handle-wallet-account cofx data)
|
:wallet-account (handle-wallet-account cofx data)
|
||||||
|
:wallet-connect (handle-wallet-connect cofx uri)
|
||||||
(handle-not-found url)))
|
(handle-not-found url)))
|
||||||
|
|
||||||
(rf/defn route-url
|
(rf/defn route-url
|
||||||
|
@ -52,6 +52,19 @@
|
|||||||
[proposal]
|
[proposal]
|
||||||
(get-in proposal [:params :proposer :metadata]))
|
(get-in proposal [:params :proposer :metadata]))
|
||||||
|
|
||||||
|
(defn get-current-request-dapp
|
||||||
|
[request sessions]
|
||||||
|
(let [dapp-url (get-in request [:event :verifyContext :verified :origin])]
|
||||||
|
(->> sessions
|
||||||
|
(filter (fn [session]
|
||||||
|
(= (utils.string/remove-trailing-slash dapp-url)
|
||||||
|
(utils.string/remove-trailing-slash (get session :url)))))
|
||||||
|
first)))
|
||||||
|
|
||||||
|
(defn get-dapp-redirect-url
|
||||||
|
[session]
|
||||||
|
(get-in session [:peer :metadata :redirect :native]))
|
||||||
|
|
||||||
(defn get-db-current-request-params
|
(defn get-db-current-request-params
|
||||||
[db]
|
[db]
|
||||||
(-> db
|
(-> db
|
||||||
|
27
src/status_im/contexts/wallet/wallet_connect/core_test.cljs
Normal file
27
src/status_im/contexts/wallet/wallet_connect/core_test.cljs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
(ns status-im.contexts.wallet.wallet-connect.core-test
|
||||||
|
(:require
|
||||||
|
[cljs.test :refer-macros [deftest is testing]]
|
||||||
|
[status-im.contexts.wallet.wallet-connect.core :as sut]))
|
||||||
|
|
||||||
|
(deftest get-current-request-dapp-test
|
||||||
|
(testing "returns the correct dapp based on the request's origin"
|
||||||
|
(let [request {:event {:verifyContext {:verified {:origin "https://dapp.com"}}}}
|
||||||
|
sessions [{:url "https://dapp.com"}
|
||||||
|
{:url "https://anotherdapp.com"}]]
|
||||||
|
(is (= {:url "https://dapp.com"}
|
||||||
|
(sut/get-current-request-dapp request sessions)))))
|
||||||
|
|
||||||
|
(testing "returns nil if no matching dapp is found"
|
||||||
|
(let [request {:event {:verifyContext {:verified {:origin "https://dapp.com"}}}}
|
||||||
|
sessions [{:url "https://anotherdapp.com"}]]
|
||||||
|
(is (nil? (sut/get-current-request-dapp request sessions))))))
|
||||||
|
|
||||||
|
(deftest get-dapp-redirect-url-test
|
||||||
|
(testing "returns the native redirect URL if it exists"
|
||||||
|
(let [session {:peer {:metadata {:redirect {:native "native://redirect-url"}}}}]
|
||||||
|
(is (= "native://redirect-url"
|
||||||
|
(sut/get-dapp-redirect-url session)))))
|
||||||
|
|
||||||
|
(testing "returns nil if no redirect URL is found"
|
||||||
|
(let [session {:peer {:metadata {}}}]
|
||||||
|
(is (nil? (sut/get-dapp-redirect-url session))))))
|
@ -317,13 +317,17 @@
|
|||||||
(rf/reg-event-fx
|
(rf/reg-event-fx
|
||||||
:wallet-connect/persist-session
|
:wallet-connect/persist-session
|
||||||
(fn [_ [session-info]]
|
(fn [_ [session-info]]
|
||||||
{:fx [[:json-rpc/call
|
(let [redirect-url (-> session-info
|
||||||
[{:method "wallet_addWalletConnectSession"
|
(js->clj :keywordize-keys true)
|
||||||
:params [(js/JSON.stringify session-info)]
|
(wallet-connect-core/get-dapp-redirect-url))]
|
||||||
:on-success (fn []
|
{:fx [[:json-rpc/call
|
||||||
(log/info "Wallet Connect session persisted")
|
[{:method "wallet_addWalletConnectSession"
|
||||||
(rf/dispatch [:wallet-connect/fetch-persisted-sessions]))
|
:params [(js/JSON.stringify session-info)]
|
||||||
:on-error #(log/info "Wallet Connect session persistence failed" %)}]]]}))
|
:on-success (fn []
|
||||||
|
(log/info "Wallet Connect session persisted")
|
||||||
|
(rf/dispatch [:wallet-connect/fetch-persisted-sessions])
|
||||||
|
(rf/dispatch [:wallet-connect/redirect-to-dapp redirect-url]))
|
||||||
|
:on-error #(log/info "Wallet Connect session persistence failed" %)}]]]})))
|
||||||
|
|
||||||
(rf/reg-event-fx
|
(rf/reg-event-fx
|
||||||
:wallet-connect/disconnect-session
|
:wallet-connect/disconnect-session
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
|
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
|
||||||
[status-im.contexts.wallet.wallet-connect.utils :as wc-utils]
|
[status-im.contexts.wallet.wallet-connect.utils :as wc-utils]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[utils.i18n :as i18n]))
|
[utils.i18n :as i18n]
|
||||||
|
[utils.transforms :as transforms]))
|
||||||
|
|
||||||
(rf/reg-event-fx
|
(rf/reg-event-fx
|
||||||
:wallet-connect/respond-current-session
|
:wallet-connect/respond-current-session
|
||||||
@ -132,8 +133,21 @@
|
|||||||
:event :wallet-connect/send-response
|
:event :wallet-connect/send-response
|
||||||
:wallet-connect-event event}))
|
:wallet-connect-event event}))
|
||||||
:on-success (fn []
|
:on-success (fn []
|
||||||
|
(rf/dispatch [:wallet-connect/redirect-to-dapp])
|
||||||
(log/info "Successfully sent Wallet Connect response to dApp"))}]]}))))
|
(log/info "Successfully sent Wallet Connect response to dApp"))}]]}))))
|
||||||
|
|
||||||
|
(rf/reg-event-fx
|
||||||
|
:wallet-connect/redirect-to-dapp
|
||||||
|
(fn [{:keys [db]} [url]]
|
||||||
|
(let [redirect-url (or url
|
||||||
|
(->> (get db :wallet-connect/current-request)
|
||||||
|
(wallet-connect-core/get-current-request-dapp
|
||||||
|
(get db :wallet-connect/sessions))
|
||||||
|
:sessionJson
|
||||||
|
transforms/json->clj
|
||||||
|
wallet-connect-core/get-dapp-redirect-url))]
|
||||||
|
{:fx [[:open-url redirect-url]]})))
|
||||||
|
|
||||||
(rf/reg-event-fx
|
(rf/reg-event-fx
|
||||||
:wallet-connect/dismiss-request-modal
|
:wallet-connect/dismiss-request-modal
|
||||||
(fn [{:keys [db]} _]
|
(fn [{:keys [db]} _]
|
||||||
@ -143,12 +157,6 @@
|
|||||||
wallet-connect-core/method-to-screen)]
|
wallet-connect-core/method-to-screen)]
|
||||||
{:fx [[:dispatch [:dismiss-modal 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
|
(rf/reg-event-fx
|
||||||
:wallet-connect/dismiss-request-modal
|
:wallet-connect/dismiss-request-modal
|
||||||
(fn [{:keys [db]} _]
|
(fn [{:keys [db]} _]
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
(ns status-im.contexts.wallet.wallet-connect.responding-events-test
|
||||||
|
(:require
|
||||||
|
[cljs.test :refer-macros [is]]
|
||||||
|
matcher-combinators.test
|
||||||
|
[re-frame.db :as rf-db]
|
||||||
|
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
|
||||||
|
status-im.contexts.wallet.wallet-connect.responding-events
|
||||||
|
[test-helpers.unit :as h]
|
||||||
|
[utils.transforms :as transforms]))
|
||||||
|
|
||||||
|
(h/deftest-event :wallet-connect/redirect-to-dapp
|
||||||
|
[event-id dispatch]
|
||||||
|
(let [current-request {:event {:verifyContext {:verified {:origin "https://dapp.com"}}}}
|
||||||
|
session-json "{\"peer\":{\"metadata\":{\"redirect\":{\"native\":\"native://redirect-url\"}}}}"
|
||||||
|
sessions [{:url "https://dapp.com"
|
||||||
|
:sessionJson session-json}]]
|
||||||
|
(reset! rf-db/app-db {:wallet-connect {:current-request current-request
|
||||||
|
:sessions sessions}})
|
||||||
|
(with-redefs [wallet-connect-core/get-current-request-dapp
|
||||||
|
(fn [_ _] (first sessions))
|
||||||
|
transforms/json->clj
|
||||||
|
(fn [json] (js/JSON.parse json))
|
||||||
|
wallet-connect-core/get-dapp-redirect-url
|
||||||
|
(fn [_] "native://redirect-url")]
|
||||||
|
|
||||||
|
(is (match? {:fx [[:open-url "native://redirect-url"]]}
|
||||||
|
(dispatch [event-id]))))))
|
@ -1,11 +1,14 @@
|
|||||||
(ns status-im.navigation.events
|
(ns status-im.navigation.events
|
||||||
(:require
|
(:require
|
||||||
|
[clojure.string :as string]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
|
[react-native.core :as react]
|
||||||
[status-im.contexts.shell.jump-to.events :as shell.events]
|
[status-im.contexts.shell.jump-to.events :as shell.events]
|
||||||
[status-im.contexts.shell.jump-to.state :as shell.state]
|
[status-im.contexts.shell.jump-to.state :as shell.state]
|
||||||
[status-im.contexts.shell.jump-to.utils :as shell.utils]
|
[status-im.contexts.shell.jump-to.utils :as shell.utils]
|
||||||
[status-im.feature-flags :as ff]
|
[status-im.feature-flags :as ff]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]
|
||||||
|
[utils.url :as url]))
|
||||||
|
|
||||||
(defn- all-screens-params
|
(defn- all-screens-params
|
||||||
[db view screen-params]
|
[db view screen-params]
|
||||||
@ -142,3 +145,9 @@
|
|||||||
{:fx [[:effects.share/open config]]})
|
{:fx [[:effects.share/open config]]})
|
||||||
|
|
||||||
(rf/reg-event-fx :open-share open-share)
|
(rf/reg-event-fx :open-share open-share)
|
||||||
|
|
||||||
|
(rf/reg-fx
|
||||||
|
:open-url
|
||||||
|
(fn [url]
|
||||||
|
(when (not (string/blank? url))
|
||||||
|
(.openURL ^js react/linking (url/normalize-url url)))))
|
||||||
|
@ -41,12 +41,7 @@
|
|||||||
:<- [:wallet-connect/current-request]
|
:<- [:wallet-connect/current-request]
|
||||||
:<- [:wallet-connect/sessions]
|
:<- [:wallet-connect/sessions]
|
||||||
(fn [[request sessions]]
|
(fn [[request sessions]]
|
||||||
(let [dapp-url (get-in request [:event :verifyContext :verified :origin])]
|
(wallet-connect-core/get-current-request-dapp request sessions)))
|
||||||
(->> sessions
|
|
||||||
(filter (fn [session]
|
|
||||||
(= (utils.string/remove-trailing-slash dapp-url)
|
|
||||||
(utils.string/remove-trailing-slash (get session :url)))))
|
|
||||||
(first)))))
|
|
||||||
|
|
||||||
(rf/reg-sub
|
(rf/reg-sub
|
||||||
:wallet-connect/sessions-for-current-account
|
:wallet-connect/sessions-for-current-account
|
||||||
|
Loading…
x
Reference in New Issue
Block a user