🤝 [19834] Add dapp connection flow with a basic design (#20204)
* 🔳 QR on success not being called - IDK why, trying things out * 🙃 Stupid of me - My handler was not being called because I wrote the code in a different QR scanner * ✅ Approval screen taking shape * 🧹 Lint fix * 🎛️ Wallet connect session screen shows up - Hard coded the first account - The data item component doesn't support networks or accounts yet - The quo category component cannot show a data-item yet - Connected accept and decline button * 🧰 Fix review issues * 🔨 Fix lint * 🔧 Rename event and move dispatch * 🔧 Fix lint
This commit is contained in:
parent
d7c66319aa
commit
6ea39b5096
|
@ -1,7 +1,8 @@
|
|||
(ns react-native.wallet-connect
|
||||
(:require
|
||||
["@walletconnect/core" :refer [Core]]
|
||||
["@walletconnect/utils" :refer [buildApprovedNamespaces getSdkError]]
|
||||
["@walletconnect/utils" :refer
|
||||
[buildApprovedNamespaces getSdkError parseUri]]
|
||||
["@walletconnect/web3wallet" :refer [Web3Wallet]]))
|
||||
|
||||
(defn- wallet-connect-core
|
||||
|
@ -24,3 +25,9 @@
|
|||
(defn get-sdk-error
|
||||
[error-key]
|
||||
(getSdkError error-key))
|
||||
|
||||
(defn parse-uri
|
||||
[uri]
|
||||
(-> uri
|
||||
parseUri
|
||||
(js->clj :keywordize-keys true)))
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
(goog-define ALCHEMY_OPTIMISM_MAINNET_TOKEN "")
|
||||
(goog-define ALCHEMY_OPTIMISM_GOERLI_TOKEN "")
|
||||
(goog-define ALCHEMY_OPTIMISM_SEPOLIA_TOKEN "")
|
||||
(goog-define WALLET_CONNECT_PROJECT_ID "")
|
||||
(goog-define WALLET_CONNECT_PROJECT_ID "87815d72a81d739d2a7ce15c2cfdefb3")
|
||||
|
||||
(def mainnet-rpc-url (str "https://eth-archival.rpc.grove.city/v1/" POKT_TOKEN))
|
||||
(def goerli-rpc-url (str "https://goerli-archival.gateway.pokt.network/v1/lb/" POKT_TOKEN))
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
(ns status-im.contexts.shell.qr-reader.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
(:require [clojure.string :as string]
|
||||
[react-native.core :as rn]
|
||||
[react-native.hooks :as hooks]
|
||||
[status-im.common.router :as router]
|
||||
|
@ -8,6 +7,7 @@
|
|||
[status-im.common.validation.general :as validators]
|
||||
[status-im.contexts.communities.events]
|
||||
[status-im.contexts.wallet.common.validation :as wallet-validation]
|
||||
[status-im.contexts.wallet.wallet-connect.utils :as wc-utils]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.ethereum.eip.eip681 :as eip681]
|
||||
[utils.i18n :as i18n]
|
||||
|
@ -42,10 +42,6 @@
|
|||
[_]
|
||||
false)
|
||||
|
||||
(defn wallet-connect-code?
|
||||
[scanned-text]
|
||||
(string/starts-with? scanned-text "wc:"))
|
||||
|
||||
(defn url?
|
||||
[scanned-text]
|
||||
(url/url? scanned-text))
|
||||
|
@ -68,6 +64,12 @@
|
|||
[:toasts/upsert invalid-qr-toast]
|
||||
300))
|
||||
|
||||
(defn- handle-wallet-connect
|
||||
[scanned-text]
|
||||
(debounce/debounce-and-dispatch
|
||||
[:wallet-connect/on-scan-connection scanned-text]
|
||||
300))
|
||||
|
||||
(defn on-qr-code-scanned
|
||||
[scanned-text]
|
||||
(cond
|
||||
|
@ -100,9 +102,8 @@
|
|||
;; TODO: https://github.com/status-im/status-mobile/issues/18744
|
||||
nil
|
||||
|
||||
(wallet-connect-code? scanned-text)
|
||||
;; WalletConnect is not working yet, this flow should be updated once WalletConnect is ready
|
||||
nil
|
||||
(wc-utils/valid-uri? scanned-text)
|
||||
(handle-wallet-connect scanned-text)
|
||||
|
||||
(url? scanned-text)
|
||||
(debounce/debounce-and-dispatch [:browser.ui/open-url scanned-text] 300)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
(ns status-im.contexts.wallet.common.scan-account.view
|
||||
(:require [clojure.string :as string]
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[status-im.common.scan-qr-code.view :as scan-qr-code]
|
||||
[status-im.constants :as constants]
|
||||
[utils.debounce :as debounce]
|
||||
|
|
|
@ -51,7 +51,9 @@
|
|||
:wallet-connect/on-session-proposal
|
||||
(fn [{:keys [db]} [proposal]]
|
||||
(log/info "Received Wallet Connect session proposal: " {:id (:id proposal)})
|
||||
{:db (assoc db :wallet-connect/current-proposal proposal)}))
|
||||
{:db (assoc db :wallet-connect/current-proposal proposal)
|
||||
:fx [[:dispatch
|
||||
[:open-modal :screen/wallet.wallet-connect-session-proposal]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-session-request
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.session-proposal.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(def dapp-avatar
|
||||
{:padding-horizontal 20
|
||||
:padding-top 12})
|
||||
|
||||
(def approval-note-container
|
||||
{:margin-horizontal 20
|
||||
:padding 12
|
||||
:border-radius 16
|
||||
:border-width 1
|
||||
:border-color colors/neutral-10
|
||||
:background-color colors/neutral-2_5})
|
||||
|
||||
(def approval-note-title
|
||||
{:color colors/neutral-50
|
||||
:margin-bottom 8})
|
||||
|
||||
(def approval-note-li
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:align-items :center})
|
||||
|
||||
(def approval-li-spacer
|
||||
{:width 8})
|
||||
|
||||
(def detail-item
|
||||
{:margin-bottom 20
|
||||
:margin-horizontal 20
|
||||
:padding 12})
|
|
@ -0,0 +1,119 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.session-proposal.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||
[status-im.contexts.wallet.wallet-connect.session-proposal.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- dapp-metadata
|
||||
[]
|
||||
(let [proposer (rf/sub [:wallet-connect/session-proposer])
|
||||
{:keys [icons name url]} (:metadata proposer)]
|
||||
[:<>
|
||||
[rn/view {:style style/dapp-avatar}
|
||||
[quo/user-avatar
|
||||
{:profile-picture (first icons)
|
||||
:size :big}]]
|
||||
[quo/page-top
|
||||
{:title name
|
||||
:description :context-tag
|
||||
:context-tag {:type :icon
|
||||
:size 32
|
||||
:icon :i/link
|
||||
:context url}}]]))
|
||||
|
||||
(defn- approval-note
|
||||
[]
|
||||
(let [dapp-name (rf/sub [:wallet-connect/session-proposer-name])
|
||||
labels [(i18n/label :t/check-your-account-balance-and-activity)
|
||||
(i18n/label :t/request-txns-and-message-signing)]]
|
||||
[rn/view {:style style/approval-note-container}
|
||||
[quo/text {:style style/approval-note-title}
|
||||
(i18n/label :t/dapp-will-be-able-to {:dapp-name dapp-name})]
|
||||
(map-indexed
|
||||
(fn [idx label]
|
||||
^{:key (str idx label)}
|
||||
[rn/view {:style style/approval-note-li}
|
||||
[quo/icon :i/bullet
|
||||
{:color colors/neutral-50}]
|
||||
[rn/view {:style style/approval-li-spacer}]
|
||||
[quo/text label]])
|
||||
labels)]))
|
||||
|
||||
(defn- accounts-data-item
|
||||
[]
|
||||
;; TODO. This account is currently hard coded in
|
||||
;; `status-im.contexts.wallet.wallet-connect.events`. Should be selectable and changeable
|
||||
(let [accounts (rf/sub [:wallet/accounts-without-watched-accounts])
|
||||
name (-> accounts first :name)]
|
||||
[quo/data-item
|
||||
{:container-style style/detail-item
|
||||
:blur? false
|
||||
:description :default
|
||||
:icon-right? true
|
||||
:right-icon :i/chevron-right
|
||||
:icon-color colors/neutral-10
|
||||
:card? false
|
||||
:label :preview
|
||||
;; TODO. The quo component for data item doesn't support showing accounts yet
|
||||
:status :default
|
||||
:size :small
|
||||
:title (i18n/label :t/account-title)
|
||||
:subtitle name}]))
|
||||
|
||||
(defn- networks-data-item
|
||||
[]
|
||||
[quo/data-item
|
||||
{:container-style style/detail-item
|
||||
:blur? false
|
||||
:description :default
|
||||
:icon-right? true
|
||||
:card? true
|
||||
:label :none
|
||||
:status :default
|
||||
:size :small
|
||||
:title (i18n/label :t/networks)
|
||||
;; TODO. The quo component for data-item does not support showing networks yet
|
||||
:subtitle "Networks will show up here"}])
|
||||
|
||||
(defn- footer
|
||||
[]
|
||||
(let [customization-color (rf/sub [:profile/customization-color])]
|
||||
[quo/bottom-actions
|
||||
{:actions :two-actions
|
||||
:button-two-label (i18n/label :t/decline)
|
||||
:button-two-props {:type :grey
|
||||
:accessibility-label :wc-deny-connection
|
||||
:on-press #(do (rf/dispatch [:navigate-back])
|
||||
(rf/dispatch
|
||||
[:wallet-connect/reset-current-session]))}
|
||||
:button-one-label (i18n/label :t/connect)
|
||||
:button-one-props {:customization-color customization-color
|
||||
:type :primary
|
||||
:accessibility-label :wc-connect
|
||||
:on-press #(rf/dispatch [:wallet-connect/approve-session])}}]))
|
||||
|
||||
(defn- header
|
||||
[]
|
||||
[quo/page-nav
|
||||
{:type :no-title
|
||||
:background :blur
|
||||
:icon-name :i/close
|
||||
:on-press (rn/use-callback #(rf/dispatch [:navigate-back]))
|
||||
:accessibility-label :wc-session-proposal-top-bar}])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[floating-button-page/view
|
||||
{:footer-container-padding 0
|
||||
:header [header]
|
||||
:footer [footer]}
|
||||
[rn/view
|
||||
[dapp-metadata]
|
||||
[accounts-data-item]
|
||||
[networks-data-item]
|
||||
[approval-note]]])
|
|
@ -0,0 +1,29 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.utils
|
||||
(:require [react-native.wallet-connect :as wallet-connect]))
|
||||
|
||||
(defn version-supported?
|
||||
[version]
|
||||
(= version 2))
|
||||
|
||||
(defn- current-timestamp
|
||||
[]
|
||||
(quot (.getTime (js/Date.)) 1000))
|
||||
|
||||
(defn timestamp-expired?
|
||||
[expiry-timestamp]
|
||||
(> (current-timestamp) expiry-timestamp))
|
||||
|
||||
(defn valid-wc-uri?
|
||||
[parsed-uri]
|
||||
(let [{:keys [topic version expiryTimestamp]} parsed-uri]
|
||||
(and (seq topic)
|
||||
(number? version)
|
||||
(number? expiryTimestamp))))
|
||||
|
||||
(defn valid-uri?
|
||||
"Check if the uri is in the wallet-connect format.
|
||||
At this stage, the uri might be expired or from an unsupported version"
|
||||
[s]
|
||||
(-> s
|
||||
wallet-connect/parse-uri
|
||||
valid-wc-uri?))
|
|
@ -106,6 +106,7 @@
|
|||
[status-im.contexts.wallet.send.send-amount.view :as wallet-send-input-amount]
|
||||
[status-im.contexts.wallet.send.transaction-confirmation.view :as wallet-transaction-confirmation]
|
||||
[status-im.contexts.wallet.send.transaction-progress.view :as wallet-transaction-progress]
|
||||
[status-im.contexts.wallet.wallet-connect.session-proposal.view :as wallet-connect-session-proposal]
|
||||
[status-im.contexts.wallet.wallet-connect.sign-message.view :as wallet-connect-sign-message]
|
||||
[status-im.navigation.options :as options]
|
||||
[status-im.navigation.transitions :as transitions]))
|
||||
|
@ -389,6 +390,10 @@
|
|||
:options {:insets {:top? true}}
|
||||
:component wallet-connected-dapps/view}
|
||||
|
||||
{:name :screen/wallet.wallet-connect-session-proposal
|
||||
:options {:sheet? true}
|
||||
:component wallet-connect-session-proposal/view}
|
||||
|
||||
{:name :screen/wallet.edit-account
|
||||
:component wallet-edit-account/view}
|
||||
|
||||
|
|
|
@ -30,3 +30,15 @@
|
|||
{:customization-color customization-color
|
||||
:name name
|
||||
:emoji emoji})))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/session-proposer
|
||||
:<- [:wallet-connect/current-proposal]
|
||||
(fn [proposal]
|
||||
(-> proposal :params :proposer)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/session-proposer-name
|
||||
:<- [:wallet-connect/session-proposer]
|
||||
(fn [proposer]
|
||||
(-> proposer :metadata :name)))
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
(ns status-im.subs.wallet.wallet-connect-test
|
||||
(:require
|
||||
[cljs.test :refer [is testing]]
|
||||
[re-frame.db :as rf-db]
|
||||
status-im.subs.root
|
||||
status-im.subs.wallet.wallet-connect
|
||||
[test-helpers.unit :as h]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def sample-session
|
||||
{:id 1716798889093634
|
||||
:params
|
||||
{:id 1716798889093634
|
||||
:pairingTopic "9b18e1348817a548bbc97f9b4a09278f4fdf7c984e4a61ddf461bd1f57710d33"
|
||||
:expiryTimestamp 1716799189
|
||||
:requiredNamespaces {}
|
||||
:optionalNamespaces {:eip155
|
||||
{:chains ["eip155:1" "eip155:42161" "eip155:137" "eip155:43114" "eip155:56"
|
||||
"eip155:10" "eip155:100"
|
||||
"eip155:324" "eip155:7777777" "eip155:8453" "eip155:42220"
|
||||
"eip155:1313161554" "eip155:11155111" "eip155:11155420"]
|
||||
:methods ["personal_sign" "eth_accounts" "eth_requestAccounts"
|
||||
"eth_sendRawTransaction" "eth_sendTransaction"
|
||||
"eth_sign" "eth_signTransaction" "eth_signTypedData"
|
||||
"eth_signTypedData_v3" "eth_signTypedData_v4"
|
||||
"wallet_addEthereumChain" "wallet_getCallsStatus"
|
||||
"wallet_getCapabilities" "wallet_getPermissions"
|
||||
"wallet_registerOnboarding" "wallet_requestPermissions"
|
||||
"wallet_scanQRCode" "wallet_sendCalls"
|
||||
"wallet_showCallsStatus" "wallet_switchEthereumChain"
|
||||
"wallet_watchAsset"]
|
||||
:events ["chainChanged" "accountsChanged"]}}
|
||||
:relays [{:protocol "irn"}]
|
||||
:proposer {:publicKey "cddea055b8974d93380e6c7e72110145506c06524047866f8034f3db0990137a"
|
||||
:metadata {:name "Web3Modal"
|
||||
:description "Web3Modal Laboratory"
|
||||
:url "https://lab.web3modal.com"
|
||||
:icons ["https://avatars.githubusercontent.com/u/37784886"]}}}
|
||||
:verifyContext {:verified {:verifyUrl "https://verify.walletconnect.com"
|
||||
:validation "VALID"
|
||||
:origin "https://lab.web3modal.com"
|
||||
:isScam false}}})
|
||||
|
||||
(h/deftest-sub :wallet-connect/session-proposer
|
||||
[sub-name]
|
||||
(testing "Return the session proposer public key and metadata"
|
||||
(swap! rf-db/app-db
|
||||
assoc
|
||||
:wallet-connect/current-proposal
|
||||
sample-session)
|
||||
|
||||
(let [proposer (rf/sub [sub-name])]
|
||||
(is (= (-> proposer :publicKey)
|
||||
(-> sample-session :params :proposer :publicKey)))
|
||||
|
||||
(is (= (-> proposer :metadata :url)
|
||||
(-> sample-session :params :proposer :metadata :url))))))
|
||||
|
||||
(h/deftest-sub :wallet-connect/session-proposer-name
|
||||
[sub-name]
|
||||
(testing "Return only the name of the session proposer"
|
||||
(swap! rf-db/app-db
|
||||
assoc
|
||||
:wallet-connect/current-proposal
|
||||
sample-session)
|
||||
|
||||
(is (= (-> sample-session :params :proposer :metadata :name)
|
||||
(rf/sub [sub-name])))))
|
|
@ -1049,6 +1049,7 @@
|
|||
"language-and-currency": "Language and currency",
|
||||
"opening-buy-crypto": "Opening {{site}}...",
|
||||
"network": "Network",
|
||||
"networks": "Networks",
|
||||
"network-chain": "Network chain",
|
||||
"network-fee": "Network fee",
|
||||
"network-id": "Network ID",
|
||||
|
@ -2673,5 +2674,10 @@
|
|||
"saved-address-removed": "Saved address removed",
|
||||
"remove-address": "Remove address",
|
||||
"remove-saved-address": "Remove saved address",
|
||||
"remove-saved-address-description": "Transaction history relating to this address will no longer be labelled ‘{{name}}’."
|
||||
"remove-saved-address-description": "Transaction history relating to this address will no longer be labelled ‘{{name}}’.",
|
||||
"dapp-will-be-able-to": "{{dapp-name}} will be able to:",
|
||||
"check-your-account-balance-and-activity": "Check your account balance and activity",
|
||||
"request-txns-and-message-signing": "Request transactions and message signing",
|
||||
"wallet-connect-qr-expired": "WalletConnect QR has expired",
|
||||
"wallet-connect-version-not-supported": "WalletConnect version {{version}} is not supported"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue