Restructure wallet-connect namespaces (#21167)
Co-authored-by: Mohsen <maxghafori@gmail.com>
This commit is contained in:
parent
d7242f1c70
commit
9135e915ab
|
@ -6,7 +6,7 @@
|
|||
[status-im.common.scan-qr-code.view :as scan-qr-code]
|
||||
[status-im.common.validation.general :as validators]
|
||||
[status-im.contexts.communities.events]
|
||||
[status-im.contexts.wallet.wallet-connect.utils :as wc-utils]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.uri :as wc-uri]
|
||||
[status-im.feature-flags :as ff]
|
||||
[utils.address :as utils-address]
|
||||
[utils.debounce :as debounce]
|
||||
|
@ -100,7 +100,7 @@
|
|||
nil
|
||||
|
||||
(and
|
||||
(wc-utils/valid-uri? scanned-text)
|
||||
(wc-uri/valid-uri? scanned-text)
|
||||
(ff/enabled? ::ff/wallet.wallet-connect))
|
||||
(handle-wallet-connect scanned-text)
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.wallet.connected-dapps.disconnect-dapp.view :as disconnect-dapp]
|
||||
[status-im.contexts.wallet.connected-dapps.style :as style]
|
||||
[status-im.contexts.wallet.wallet-connect.core :as core]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as data-store]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.string]))
|
||||
|
@ -107,9 +107,14 @@
|
|||
:content-container-style (style/dapps-list theme)
|
||||
:render-fn (fn [{:keys [topic pairingTopic name url iconUrl]}]
|
||||
[quo/dapp
|
||||
{:dapp {:avatar (core/compute-dapp-icon-path iconUrl
|
||||
{:dapp {:avatar
|
||||
(data-store/compute-dapp-icon-path
|
||||
iconUrl
|
||||
url)
|
||||
:name
|
||||
(data-store/compute-dapp-name
|
||||
name
|
||||
url)
|
||||
:name (core/compute-dapp-name name url)
|
||||
:value url
|
||||
:topic topic
|
||||
:pairing-topic pairingTopic
|
||||
|
|
|
@ -1,204 +0,0 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.core
|
||||
(:require [clojure.edn :as edn]
|
||||
[clojure.set :as set]
|
||||
[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]))
|
||||
|
||||
(def method-to-screen
|
||||
{constants/wallet-connect-personal-sign-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-typed-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-typed-v4-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-send-transaction-method :screen/wallet-connect.send-transaction
|
||||
constants/wallet-connect-eth-sign-transaction-method :screen/wallet-connect.sign-transaction})
|
||||
|
||||
(defn extract-native-call-signature
|
||||
[data]
|
||||
(-> data transforms/json->clj :result))
|
||||
|
||||
(defn chain-id->eip155
|
||||
[chain-id]
|
||||
(str "eip155:" chain-id))
|
||||
|
||||
(defn eip155->chain-id
|
||||
[chain-id-str]
|
||||
(-> chain-id-str
|
||||
(string/split #":")
|
||||
last
|
||||
edn/read-string))
|
||||
|
||||
(defn format-eip155-address
|
||||
[address chain-id]
|
||||
(str chain-id ":" address))
|
||||
|
||||
(defn get-request-method
|
||||
[event]
|
||||
(get-in event [:params :request :method]))
|
||||
|
||||
(defn get-request-params
|
||||
[event]
|
||||
(get-in event [:params :request :params]))
|
||||
|
||||
(defn get-db-current-request-event
|
||||
[db]
|
||||
(get-in db [:wallet-connect/current-request :event]))
|
||||
|
||||
(defn get-session-dapp-metadata
|
||||
[proposal]
|
||||
(let [metadata (get-in proposal [:params :proposer :metadata])
|
||||
origin (get-in proposal [:verifyContext :verified :origin])]
|
||||
(or metadata {:url origin})))
|
||||
|
||||
(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
|
||||
[db]
|
||||
(-> db
|
||||
get-db-current-request-event
|
||||
get-request-params))
|
||||
|
||||
(def ^:private sign-typed-data-by-version
|
||||
{:v1 native-module/sign-typed-data
|
||||
:v4 native-module/sign-typed-data-v4})
|
||||
|
||||
(defn sign-typed-data
|
||||
[version data address password]
|
||||
(let [f (get sign-typed-data-by-version version)]
|
||||
(->> password
|
||||
security/safe-unmask-data
|
||||
(f data address))))
|
||||
|
||||
(defn get-proposal-networks
|
||||
[proposal]
|
||||
(let [required-namespaces (get-in proposal [:params :requiredNamespaces])
|
||||
optional-namespaces (get-in proposal [:params :optionalNamespaces])]
|
||||
(->> [required-namespaces optional-namespaces]
|
||||
(map #(get-in % [:eip155 :chains]))
|
||||
(apply concat)
|
||||
(into #{}))))
|
||||
|
||||
(defn proposal-networks-intersection
|
||||
[proposal supported-networks]
|
||||
(let [proposed-networks (get-proposal-networks proposal)]
|
||||
(->> supported-networks
|
||||
(filter #(->> %
|
||||
chain-id->eip155
|
||||
(contains? proposed-networks))))))
|
||||
|
||||
(defn required-networks-supported?
|
||||
[proposal supported-networks]
|
||||
(let [supported-namespaces #{:eip155}
|
||||
required-namespaces (get-in proposal [:params :requiredNamespaces])]
|
||||
(when (every? #(contains? supported-namespaces %)
|
||||
(keys required-namespaces))
|
||||
(let [required-networks (get-in required-namespaces [:eip155 :chains])
|
||||
supported-eip155 (set (map chain-id->eip155 supported-networks))]
|
||||
(every? #(contains? supported-eip155 %)
|
||||
required-networks)))))
|
||||
|
||||
(defn get-networks-by-mode
|
||||
[db]
|
||||
(let [test-mode? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
networks (get-in db [:wallet :networks (if test-mode? :test :prod)])]
|
||||
(mapv #(-> % :chain-id) networks)))
|
||||
|
||||
(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]
|
||||
(let [add-testnet-name (fn [testnet-name]
|
||||
(update network :full-name #(str % " " testnet-name)))]
|
||||
(condp #(contains? %1 %2) (:chain-id network)
|
||||
constants/sepolia-chain-ids (add-testnet-name constants/sepolia-full-name)
|
||||
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 session-networks-allowed?
|
||||
[testnet-mode? {:keys [chains]}]
|
||||
(let [chain-ids (set (map (fn [chain]
|
||||
(-> chain
|
||||
(string/split ":")
|
||||
second
|
||||
js/parseInt))
|
||||
chains))]
|
||||
(if testnet-mode?
|
||||
(set/subset? chain-ids (set/union constants/sepolia-chain-ids constants/goerli-chain-ids))
|
||||
(set/subset? chain-ids constants/mainnet-chain-ids))))
|
||||
|
||||
(defn event-should-be-handled?
|
||||
[db {:keys [topic]}]
|
||||
(let [testnet-mode? (get-in db [:profile/profile :test-networks-enabled?])]
|
||||
(some #(and (= (:topic %) topic)
|
||||
(session-networks-allowed? testnet-mode? %))
|
||||
(:wallet-connect/sessions db))))
|
||||
|
||||
(defn sdk-session->db-session
|
||||
[{:keys [topic expiry pairingTopic] :as session}]
|
||||
{:topic topic
|
||||
:expiry expiry
|
||||
:sessionJson (transforms/clj->json session)
|
||||
:pairingTopic pairingTopic
|
||||
:name (get-in session [:peer :metadata :name])
|
||||
:iconUrl (get-in session [:peer :metadata :icons 0])
|
||||
:url (get-in session [:peer :metadata :url])
|
||||
:accounts (get-in session [:namespaces :eip155 :accounts])
|
||||
:chains (get-in session [:namespaces :eip155 :chains])
|
||||
:disconnected false})
|
||||
|
||||
(defn filter-operable-accounts
|
||||
[accounts]
|
||||
(filter #(and (:operable? %)
|
||||
(not (:watch-only? %)))
|
||||
accounts))
|
||||
|
||||
(defn filter-sessions-for-account-addresses
|
||||
[account-addresses sessions]
|
||||
(filter (fn [{:keys [accounts]}]
|
||||
(some (fn [account]
|
||||
(some (fn [account-address]
|
||||
(clojure.string/includes? account account-address))
|
||||
account-addresses))
|
||||
accounts))
|
||||
sessions))
|
||||
|
||||
(defn compute-dapp-name
|
||||
"Sometimes dapps have no name or an empty name. Return url as name in that case"
|
||||
[name url]
|
||||
(if (seq name)
|
||||
name
|
||||
(when (seq url)
|
||||
(-> url
|
||||
utils.string/remove-trailing-slash
|
||||
utils.string/remove-http-prefix
|
||||
string/capitalize))))
|
||||
|
||||
(defn compute-dapp-icon-path
|
||||
"Some dapps have icons with relative paths, make paths absolute in those cases, send nil if icon is missing"
|
||||
[icon-path url]
|
||||
(when (and (seq icon-path)
|
||||
(seq url))
|
||||
(if (string/starts-with? icon-path "http")
|
||||
icon-path
|
||||
(str (utils.string/remove-trailing-slash url) icon-path))))
|
|
@ -1,27 +0,0 @@
|
|||
(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))))))
|
|
@ -1,358 +0,0 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.events
|
||||
(:require [re-frame.core :as rf]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
|
||||
status-im.contexts.wallet.wallet-connect.effects
|
||||
status-im.contexts.wallet.wallet-connect.processing-events
|
||||
status-im.contexts.wallet.wallet-connect.responding-events
|
||||
[status-im.contexts.wallet.wallet-connect.utils :as wc-utils]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.transforms :as types]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/init
|
||||
(fn [{:keys [db]}]
|
||||
(let [network-status (:network/status db)
|
||||
web3-wallet-missing? (-> db :wallet-connect/web3-wallet boolean not)]
|
||||
(if (and (= network-status :online) web3-wallet-missing?)
|
||||
(do (log/info "Initialising WalletConnect SDK")
|
||||
{: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
|
||||
(fn [{:keys [db]} [web3-wallet]]
|
||||
(log/info "WalletConnect SDK initialisation successful")
|
||||
{:db (assoc db :wallet-connect/web3-wallet web3-wallet)
|
||||
: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)]
|
||||
(when (and is-connected? logged-in?)
|
||||
(log/info "Re-Initialising WalletConnect SDK due to network change")
|
||||
{:fx [[:dispatch [:wallet-connect/init]]]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/register-event-listeners
|
||||
(fn [{:keys [db]}]
|
||||
(let [web3-wallet (get db :wallet-connect/web3-wallet)]
|
||||
{:fx [[:effects.wallet-connect/register-event-listener
|
||||
[web3-wallet
|
||||
constants/wallet-connect-session-proposal-event
|
||||
#(rf/dispatch [:wallet-connect/on-session-proposal %])]]
|
||||
[:effects.wallet-connect/register-event-listener
|
||||
[web3-wallet
|
||||
constants/wallet-connect-session-request-event
|
||||
#(rf/dispatch [:wallet-connect/on-session-request %])]]
|
||||
[:effects.wallet-connect/register-event-listener
|
||||
[web3-wallet
|
||||
constants/wallet-connect-session-delete-event
|
||||
#(rf/dispatch [:wallet-connect/on-session-delete %])]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-init-fail
|
||||
(fn [_ [error]]
|
||||
(log/error "Failed to initialize Wallet Connect"
|
||||
{:error error
|
||||
:event :wallet-connect/on-init-fail})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-session-proposal
|
||||
(fn [{:keys [db]} [proposal]]
|
||||
(log/info "Received Wallet Connect session proposal: " proposal)
|
||||
(let [accounts (get-in db [:wallet :accounts])
|
||||
current-viewing-address (get-in db [:wallet :current-viewing-account-address])
|
||||
available-accounts (wallet-connect-core/filter-operable-accounts (vals accounts))
|
||||
networks (wallet-connect-core/get-networks-by-mode db)
|
||||
session-networks (wallet-connect-core/proposal-networks-intersection proposal
|
||||
networks)
|
||||
required-networks-supported? (wallet-connect-core/required-networks-supported? proposal
|
||||
networks)]
|
||||
(if (and (not-empty session-networks) required-networks-supported?)
|
||||
{:db (update db
|
||||
:wallet-connect/current-proposal assoc
|
||||
:request proposal
|
||||
:session-networks session-networks
|
||||
:address (or current-viewing-address
|
||||
(-> available-accounts
|
||||
first
|
||||
:address)))
|
||||
:fx [[:dispatch
|
||||
[:open-modal :screen/wallet.wallet-connect-session-proposal]]]}
|
||||
{:fx [[:dispatch
|
||||
[:wallet-connect/show-session-networks-unsupported-toast proposal]]
|
||||
[:dispatch
|
||||
[:wallet-connect/reject-session-proposal proposal]]]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/show-session-networks-unsupported-toast
|
||||
(fn [{:keys [db]} [proposal]]
|
||||
(let [{:keys [name url]} (wallet-connect-core/get-session-dapp-metadata proposal)]
|
||||
{:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :negative
|
||||
:theme (:theme db)
|
||||
:text (i18n/label :t/wallet-connect-networks-not-supported
|
||||
{:dapp (wallet-connect-core/compute-dapp-name name url)})}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-session-request
|
||||
(fn [{:keys [db]} [event]]
|
||||
(if (wallet-connect-core/event-should-be-handled? db event)
|
||||
{:fx [[:dispatch [:wallet-connect/process-session-request event]]]}
|
||||
{:fx [[:dispatch
|
||||
[:wallet-connect/show-session-networks-unsupported-toast event]]
|
||||
[:dispatch
|
||||
[:wallet-connect/send-response
|
||||
{:request event
|
||||
:error (wallet-connect/get-sdk-error
|
||||
constants/wallet-connect-user-rejected-chains-error-key)}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-session-delete
|
||||
(fn [{:keys [db]} [{:keys [topic] :as event}]]
|
||||
(when (wallet-connect-core/event-should-be-handled? db event)
|
||||
(log/info "Received Wallet Connect session delete from the SDK: " event)
|
||||
{:fx [[:dispatch [:wallet-connect/disconnect-session topic]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/reset-current-session-proposal
|
||||
(fn [{:keys [db]}]
|
||||
{:db (dissoc db :wallet-connect/current-proposal)}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/set-current-proposal-address
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc-in db [:wallet-connect/current-proposal :address] address)}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/reset-current-request
|
||||
(fn [{:keys [db]}]
|
||||
{:db (dissoc db :wallet-connect/current-request)}))
|
||||
|
||||
(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)
|
||||
network-status (:network/status db)]
|
||||
(log/info "Disconnecting dApp session" topic)
|
||||
(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
|
||||
(fn [{:keys [db]} [url]]
|
||||
(let [web3-wallet (get db :wallet-connect/web3-wallet)]
|
||||
{:fx [[:effects.wallet-connect/pair
|
||||
{:web3-wallet web3-wallet
|
||||
:url url
|
||||
:on-fail #(log/error "Failed to pair with dApp" {:error %})
|
||||
:on-success #(log/info "dApp paired successfully")}]]})))
|
||||
|
||||
(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))
|
||||
network-status (:network/status db)
|
||||
expiry (get-in current-proposal [:params :expiryTimestamp])]
|
||||
(if (= network-status :online)
|
||||
{:db (assoc-in db [:wallet-connect/current-proposal :response-sent?] true)
|
||||
:fx [(if (wc-utils/timestamp-expired? expiry)
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :wallet-connect-proposal-expired
|
||||
:type :negative
|
||||
:text (i18n/label :t/wallet-connect-proposal-expired)}]]
|
||||
[: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 [{: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?)
|
||||
(not version-supported?)
|
||||
(= network-status :offline)
|
||||
expired?)
|
||||
{:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :negative
|
||||
:theme :dark
|
||||
: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?
|
||||
(i18n/label :t/wallet-connect-qr-expired)
|
||||
|
||||
(not version-supported?)
|
||||
(i18n/label :t/wallet-connect-version-not-supported
|
||||
{:version version})
|
||||
|
||||
:else
|
||||
(i18n/label :t/something-went-wrong))}]]]}
|
||||
{:fx [[:dispatch [:wallet-connect/pair scanned-text]]]}))))
|
||||
|
||||
;; We first load sessions from database, then we initiate a call to Wallet Connect SDK and
|
||||
;; then replace the list we have stored in the database with the one that came from the SDK.
|
||||
;; In addition to that, we also update the backend state by marking sessions that are not
|
||||
;; active anymore by calling `:wallet-connect/disconnect-session`.
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/fetch-active-sessions-success
|
||||
(fn [{:keys [db now]} [sessions]]
|
||||
(let [persisted-sessions (:wallet-connect/sessions db)
|
||||
account-addresses (->> (get-in db [:wallet :accounts])
|
||||
vals
|
||||
wallet-connect-core/filter-operable-accounts
|
||||
(map :address))
|
||||
sessions (->> (js->clj sessions :keywordize-keys true)
|
||||
vals
|
||||
(map wallet-connect-core/sdk-session->db-session)
|
||||
(wallet-connect-core/filter-sessions-for-account-addresses
|
||||
account-addresses))
|
||||
session-topics (set (map :topic sessions))
|
||||
expired-sessions (filter
|
||||
(fn [{:keys [expiry topic]}]
|
||||
(or (< expiry (/ now 1000))
|
||||
(not (contains? session-topics topic))))
|
||||
persisted-sessions)]
|
||||
(when (seq expired-sessions)
|
||||
(log/info "Updating WalletConnect persisted sessions due to expired/inactive sessions"
|
||||
{:expired expired-sessions}))
|
||||
{:fx (mapv (fn [{:keys [topic]}]
|
||||
[:dispatch [:wallet-connect/disconnect-session topic]])
|
||||
expired-sessions)
|
||||
:db (assoc db :wallet-connect/sessions sessions)})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/fetch-active-sessions
|
||||
(fn [{:keys [db]}]
|
||||
(let [web3-wallet (get db :wallet-connect/web3-wallet)]
|
||||
{:fx [[:effects.wallet-connect/fetch-active-sessions
|
||||
{:web3-wallet web3-wallet
|
||||
:on-fail #(log/error "Failed to get active sessions" {:error %})
|
||||
:on-success #(rf/dispatch [:wallet-connect/fetch-active-sessions-success %])}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/fetch-persisted-sessions-success
|
||||
(fn [{:keys [db]} [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
|
||||
:wallet-connect/fetch-persisted-sessions-fail
|
||||
(fn [_ [error]]
|
||||
(log/info "Wallet Connect fetch persisted sessions failed" error)
|
||||
{:fx [[:dispatch [:wallet-connect/fetch-active-sessions]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/fetch-persisted-sessions
|
||||
(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
|
||||
(fn [_ [session-info]]
|
||||
(let [redirect-url (-> session-info
|
||||
(js->clj :keywordize-keys true)
|
||||
(wallet-connect-core/get-dapp-redirect-url))]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wallet_addWalletConnectSession"
|
||||
:params [(js/JSON.stringify session-info)]
|
||||
: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
|
||||
:wallet-connect/disconnect-session
|
||||
(fn [{:keys [db]} [topic]]
|
||||
(log/info "Removing session from persistance and state" topic)
|
||||
{:db (update db
|
||||
:wallet-connect/sessions
|
||||
(fn [sessions]
|
||||
(->> sessions
|
||||
(remove #(= (:topic %) topic))
|
||||
(into []))))
|
||||
:fx [[:json-rpc/call
|
||||
[{:method "wallet_disconnectWalletConnectSession"
|
||||
: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)}]]]}))
|
|
@ -0,0 +1,92 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.events.core
|
||||
(:require [re-frame.core :as rf]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.constants :as constants]
|
||||
status-im.contexts.wallet.wallet-connect.events.effects
|
||||
status-im.contexts.wallet.wallet-connect.events.session-proposals
|
||||
status-im.contexts.wallet.wallet-connect.events.session-requests
|
||||
status-im.contexts.wallet.wallet-connect.events.session-responses
|
||||
status-im.contexts.wallet.wallet-connect.events.sessions
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/init
|
||||
(fn [{:keys [db]}]
|
||||
(let [network-status (:network/status db)
|
||||
web3-wallet-missing? (-> db :wallet-connect/web3-wallet boolean not)]
|
||||
(if (and (= network-status :online) web3-wallet-missing?)
|
||||
(do (log/info "Initialising WalletConnect SDK")
|
||||
{: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
|
||||
(fn [{:keys [db]} [web3-wallet]]
|
||||
(log/info "WalletConnect SDK initialisation successful")
|
||||
{:db (assoc db :wallet-connect/web3-wallet web3-wallet)
|
||||
: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)]
|
||||
(when (and is-connected? logged-in?)
|
||||
(log/info "Re-Initialising WalletConnect SDK due to network change")
|
||||
{:fx [[:dispatch [:wallet-connect/init]]]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/register-event-listeners
|
||||
(fn [{:keys [db]}]
|
||||
(let [web3-wallet (get db :wallet-connect/web3-wallet)]
|
||||
{:fx [[:effects.wallet-connect/register-event-listener
|
||||
[web3-wallet
|
||||
constants/wallet-connect-session-proposal-event
|
||||
#(rf/dispatch [:wallet-connect/on-session-proposal %])]]
|
||||
[:effects.wallet-connect/register-event-listener
|
||||
[web3-wallet
|
||||
constants/wallet-connect-session-request-event
|
||||
#(rf/dispatch [:wallet-connect/on-session-request %])]]
|
||||
[:effects.wallet-connect/register-event-listener
|
||||
[web3-wallet
|
||||
constants/wallet-connect-session-delete-event
|
||||
#(rf/dispatch [:wallet-connect/on-session-delete %])]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-init-fail
|
||||
(fn [_ [error]]
|
||||
(log/error "Failed to initialize Wallet Connect"
|
||||
{:error error
|
||||
:event :wallet-connect/on-init-fail})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-session-request
|
||||
(fn [{:keys [db]} [event]]
|
||||
(if (networks/event-should-be-handled? db event)
|
||||
{:fx [[:dispatch [:wallet-connect/process-session-request event]]]}
|
||||
{:fx [[:dispatch
|
||||
[:wallet-connect/show-session-networks-unsupported-toast event]]
|
||||
[:dispatch
|
||||
[:wallet-connect/send-response
|
||||
{:request event
|
||||
:error (wallet-connect/get-sdk-error
|
||||
constants/wallet-connect-user-rejected-chains-error-key)}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/reset-current-request
|
||||
(fn [{:keys [db]}]
|
||||
{:db (dissoc db :wallet-connect/current-request)}))
|
||||
|
||||
(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)}]]]}))
|
|
@ -1,12 +1,12 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.effects
|
||||
(ns status-im.contexts.wallet.wallet-connect.events.effects
|
||||
(:require
|
||||
[promesa.core :as promesa]
|
||||
[re-frame.core :as rf]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.wallet-connect.signing :as signing]
|
||||
[status-im.contexts.wallet.wallet-connect.transactions :as transactions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.signing :as signing]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transactions]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.security.core :as security]))
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.events.session-proposals
|
||||
(:require [re-frame.core :as rf]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.sessions :as sessions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.uri :as uri]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/pair
|
||||
(fn [{:keys [db]} [url]]
|
||||
(let [web3-wallet (get db :wallet-connect/web3-wallet)]
|
||||
{:fx [[:effects.wallet-connect/pair
|
||||
{:web3-wallet web3-wallet
|
||||
:url url
|
||||
:on-fail #(log/error "Failed to pair with dApp" {:error %})
|
||||
:on-success #(log/info "dApp paired successfully")}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-scan-connection
|
||||
(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? (uri/valid-wc-uri? parsed-uri)
|
||||
expired? (-> parsed-uri
|
||||
:expiryTimestamp
|
||||
uri/timestamp-expired?)
|
||||
version-supported? (uri/version-supported? version)]
|
||||
(if (or (not valid-wc-uri?)
|
||||
(not version-supported?)
|
||||
(= network-status :offline)
|
||||
expired?)
|
||||
{:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :negative
|
||||
:theme :dark
|
||||
: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?
|
||||
(i18n/label :t/wallet-connect-qr-expired)
|
||||
|
||||
(not version-supported?)
|
||||
(i18n/label :t/wallet-connect-version-not-supported
|
||||
{:version version})
|
||||
|
||||
:else
|
||||
(i18n/label :t/something-went-wrong))}]]]}
|
||||
{:fx [[:dispatch [:wallet-connect/pair scanned-text]]]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-session-proposal
|
||||
(fn [{:keys [db]} [proposal]]
|
||||
(log/info "Received Wallet Connect session proposal: " proposal)
|
||||
(let [accounts (get-in db [:wallet :accounts])
|
||||
current-viewing-address (get-in db [:wallet :current-viewing-account-address])
|
||||
available-accounts (sessions/filter-operable-accounts (vals accounts))
|
||||
networks (networks/get-networks-by-mode db)
|
||||
session-networks (networks/proposal-networks-intersection proposal networks)
|
||||
required-networks-supported? (networks/required-networks-supported? proposal networks)]
|
||||
(if (and (not-empty session-networks) required-networks-supported?)
|
||||
{:db (update db
|
||||
:wallet-connect/current-proposal assoc
|
||||
:request proposal
|
||||
:session-networks session-networks
|
||||
:address (or current-viewing-address
|
||||
(-> available-accounts
|
||||
first
|
||||
:address)))
|
||||
:fx [[:dispatch [:open-modal :screen/wallet.wallet-connect-session-proposal]]]}
|
||||
{:fx [[:dispatch [:wallet-connect/show-session-networks-unsupported-toast proposal]]
|
||||
[:dispatch [:wallet-connect/reject-session-proposal proposal]]]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/show-session-networks-unsupported-toast
|
||||
(fn [{:keys [db]} [proposal]]
|
||||
(let [{:keys [name url]} (data-store/get-session-dapp-metadata proposal)]
|
||||
{:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :negative
|
||||
:theme (:theme db)
|
||||
:text (i18n/label :t/wallet-connect-networks-not-supported
|
||||
{:dapp (data-store/compute-dapp-name name url)})}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/reset-current-session-proposal
|
||||
(fn [{:keys [db]}]
|
||||
{:db (dissoc db :wallet-connect/current-proposal)}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/set-current-proposal-address
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc-in db [:wallet-connect/current-proposal :address] address)}))
|
||||
|
||||
|
||||
(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 networks/chain-id->eip155)
|
||||
vec)
|
||||
current-address (get-in db [:wallet-connect/current-proposal :address])
|
||||
accounts (-> (partial networks/format-eip155-address current-address)
|
||||
(map session-networks))
|
||||
network-status (:network/status db)
|
||||
expiry (get-in current-proposal [:params :expiryTimestamp])]
|
||||
(if (= network-status :online)
|
||||
{:db (assoc-in db [:wallet-connect/current-proposal :response-sent?] true)
|
||||
:fx [(if (uri/timestamp-expired? expiry)
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :wallet-connect-proposal-expired
|
||||
:type :negative
|
||||
:text (i18n/label :t/wallet-connect-proposal-expired)}]]
|
||||
[: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]]]}))))
|
|
@ -1,12 +1,14 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.processing-events
|
||||
(ns status-im.contexts.wallet.wallet-connect.events.session-requests
|
||||
(:require [cljs-bean.core :as bean]
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[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]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.signing :as signing]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transactions]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.transforms :as transforms]))
|
||||
|
@ -15,8 +17,8 @@
|
|||
:wallet-connect/show-request-modal
|
||||
(fn [{:keys [db]}]
|
||||
(let [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)]
|
||||
method (data-store/get-request-method event)
|
||||
screen (data-store/method-to-screen method)]
|
||||
(if screen
|
||||
{:fx [[:dispatch [:open-modal screen]]]}
|
||||
(log/error "Didn't find screen for Wallet Connect method"
|
||||
|
@ -25,7 +27,7 @@
|
|||
(rf/reg-event-fx
|
||||
:wallet-connect/process-session-request
|
||||
(fn [{:keys [db]} [event]]
|
||||
(let [method (wallet-connect-core/get-request-method event)
|
||||
(let [method (data-store/get-request-method event)
|
||||
existing-event (get-in db [:wallet-connect/current-request :event])]
|
||||
(log/info "Processing Wallet Connect session request" method)
|
||||
;; NOTE: make sure we don't show two requests at the same time
|
||||
|
@ -55,7 +57,7 @@
|
|||
(rf/reg-event-fx
|
||||
:wallet-connect/process-personal-sign
|
||||
(fn [{:keys [db]}]
|
||||
(let [[raw-data address] (wallet-connect-core/get-db-current-request-params db)
|
||||
(let [[raw-data address] (data-store/get-db-current-request-params db)
|
||||
parsed-data (native-module/hex-to-utf8 raw-data)]
|
||||
{:db (update-in db
|
||||
[:wallet-connect/current-request]
|
||||
|
@ -68,7 +70,7 @@
|
|||
(rf/reg-event-fx
|
||||
:wallet-connect/process-eth-sign
|
||||
(fn [{:keys [db]}]
|
||||
(let [[address raw-data] (wallet-connect-core/get-db-current-request-params db)
|
||||
(let [[address raw-data] (data-store/get-db-current-request-params db)
|
||||
parsed-data (native-module/hex-to-utf8 raw-data)]
|
||||
{:db (update-in db
|
||||
[:wallet-connect/current-request]
|
||||
|
@ -98,11 +100,11 @@
|
|||
(rf/reg-event-fx
|
||||
:wallet-connect/process-eth-send-transaction
|
||||
(fn [{:keys [db]}]
|
||||
(let [event (wallet-connect-core/get-db-current-request-event db)
|
||||
tx (-> event wallet-connect-core/get-request-params first)
|
||||
(let [event (data-store/get-db-current-request-event db)
|
||||
tx (-> event data-store/get-request-params first)
|
||||
chain-id (-> event
|
||||
(get-in [:params :chainId])
|
||||
wallet-connect-core/eip155->chain-id)]
|
||||
networks/eip155->chain-id)]
|
||||
{:fx [[:effects.wallet-connect/prepare-transaction
|
||||
{:tx tx
|
||||
:chain-id chain-id
|
||||
|
@ -112,11 +114,11 @@
|
|||
(rf/reg-event-fx
|
||||
:wallet-connect/process-eth-sign-transaction
|
||||
(fn [{:keys [db]}]
|
||||
(let [event (wallet-connect-core/get-db-current-request-event db)
|
||||
tx (-> event wallet-connect-core/get-request-params first)
|
||||
(let [event (data-store/get-db-current-request-event db)
|
||||
tx (-> event data-store/get-request-params first)
|
||||
chain-id (-> event
|
||||
(get-in [:params :chainId])
|
||||
wallet-connect-core/eip155->chain-id)]
|
||||
networks/eip155->chain-id)]
|
||||
{:fx [[:effects.wallet-connect/prepare-transaction
|
||||
{:tx tx
|
||||
:chain-id chain-id
|
||||
|
@ -127,11 +129,11 @@
|
|||
:wallet-connect/process-sign-typed
|
||||
(fn [{:keys [db]}]
|
||||
(try
|
||||
(let [[address raw-data] (wallet-connect-core/get-db-current-request-params db)
|
||||
(let [[address raw-data] (data-store/get-db-current-request-params db)
|
||||
parsed-raw-data (transforms/js-parse raw-data)
|
||||
session-chain-id (-> (wallet-connect-core/get-db-current-request-event db)
|
||||
session-chain-id (-> (data-store/get-db-current-request-event db)
|
||||
(get-in [:params :chainId])
|
||||
wallet-connect-core/eip155->chain-id)
|
||||
networks/eip155->chain-id)
|
||||
data-chain-id (-> parsed-raw-data
|
||||
transforms/js->clj
|
||||
signing/typed-data-chain-id)
|
||||
|
@ -156,20 +158,20 @@
|
|||
[:wallet-connect/on-processing-error
|
||||
(ex-info "Failed to parse JSON typed data"
|
||||
{:error err
|
||||
:data (wallet-connect-core/get-db-current-request-params db)})]]]}))))
|
||||
:data (data-store/get-db-current-request-params db)})]]]}))))
|
||||
|
||||
(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
|
||||
networks/chain-id->network-details
|
||||
:full-name)
|
||||
expected-network-name (-> expected-chain-id
|
||||
wallet-connect-core/chain-id->network-details
|
||||
networks/chain-id->network-details
|
||||
:full-name)
|
||||
toast-message (i18n/label :t/wallet-connect-typed-data-wrong-chain-id-warning
|
||||
{:wrong-chain (or wrong-network-name
|
||||
(wallet-connect-core/chain-id->eip155
|
||||
(networks/chain-id->eip155
|
||||
wrong-chain-id))
|
||||
:expected-chain expected-network-name})]
|
||||
{:fx [[:dispatch
|
||||
|
@ -186,7 +188,7 @@
|
|||
: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)]
|
||||
method (data-store/get-request-method event)]
|
||||
(log/error "Failed to process Wallet Connect request"
|
||||
{:error error
|
||||
:address address
|
|
@ -1,9 +1,10 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.responding-events
|
||||
(ns status-im.contexts.wallet.wallet-connect.events.session-responses
|
||||
(:require [re-frame.core :as rf]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.constants :as constants]
|
||||
[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.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.uri :as uri]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.transforms :as transforms]))
|
||||
|
@ -12,10 +13,10 @@
|
|||
:wallet-connect/respond-current-session
|
||||
(fn [{:keys [db]} [password]]
|
||||
(let [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)
|
||||
method (data-store/get-request-method event)
|
||||
screen (data-store/method-to-screen method)
|
||||
expiry (get-in event [:params :request :expiryTimestamp])]
|
||||
(if (wc-utils/timestamp-expired? expiry)
|
||||
(if (uri/timestamp-expired? expiry)
|
||||
{:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :new-wallet-account-created
|
||||
|
@ -99,7 +100,7 @@
|
|||
: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)]
|
||||
method (data-store/get-request-method event)]
|
||||
(log/error "Failed to sign Wallet Connect request"
|
||||
{:error error
|
||||
:address address
|
||||
|
@ -118,7 +119,7 @@
|
|||
(fn [{:keys [db]} [{:keys [request result error]}]]
|
||||
(when-let [{:keys [id topic] :as event} (or request
|
||||
(get-in db [:wallet-connect/current-request :event]))]
|
||||
(let [method (wallet-connect-core/get-request-method event)
|
||||
(let [method (data-store/get-request-method event)
|
||||
web3-wallet (get db :wallet-connect/web3-wallet)]
|
||||
{:db (assoc-in db [:wallet-connect/current-request :response-sent?] true)
|
||||
:fx [[:effects.wallet-connect/respond-session-request
|
||||
|
@ -142,11 +143,11 @@
|
|||
(fn [{:keys [db]} [url]]
|
||||
(let [redirect-url (or url
|
||||
(->> (get db :wallet-connect/current-request)
|
||||
(wallet-connect-core/get-current-request-dapp
|
||||
(data-store/get-current-request-dapp
|
||||
(get db :wallet-connect/sessions))
|
||||
:sessionJson
|
||||
transforms/json->clj
|
||||
wallet-connect-core/get-dapp-redirect-url))]
|
||||
data-store/get-dapp-redirect-url))]
|
||||
{:fx [[:open-url redirect-url]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
|
@ -154,17 +155,8 @@
|
|||
(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/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)]
|
||||
data-store/get-request-method
|
||||
data-store/method-to-screen)]
|
||||
{:fx [[:dispatch [:dismiss-modal screen]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
|
@ -1,10 +1,10 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.responding-events-test
|
||||
(ns status-im.contexts.wallet.wallet-connect.events.session-responses-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
|
||||
status-im.contexts.wallet.wallet-connect.events.session-responses
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as data-store]
|
||||
[test-helpers.unit :as h]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
|
@ -16,11 +16,11 @@
|
|||
: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
|
||||
(with-redefs [data-store/get-current-request-dapp
|
||||
(fn [_ _] (first sessions))
|
||||
transforms/json->clj
|
||||
(fn [json] (js/JSON.parse json))
|
||||
wallet-connect-core/get-dapp-redirect-url
|
||||
data-store/get-dapp-redirect-url
|
||||
(fn [_] "native://redirect-url")]
|
||||
|
||||
(is (match? {:fx [[:open-url "native://redirect-url"]]}
|
|
@ -0,0 +1,141 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.events.sessions
|
||||
(:require [re-frame.core :as rf]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.sessions :as sessions]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.transforms :as types]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-session-delete
|
||||
(fn [{:keys [db]} [{:keys [topic] :as event}]]
|
||||
(when (networks/event-should-be-handled? db event)
|
||||
(log/info "Received Wallet Connect session delete from the SDK: " event)
|
||||
{:fx [[:dispatch [:wallet-connect/disconnect-persisted-session topic]]]})))
|
||||
|
||||
(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)
|
||||
network-status (:network/status db)]
|
||||
(log/info "Disconnecting dApp session" topic)
|
||||
(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-persisted-session topic])
|
||||
(when on-success
|
||||
(on-success)))}]]}
|
||||
{:fx [[:dispatch [:wallet-connect/no-internet-toast]]]}))))
|
||||
|
||||
;; We first load sessions from database, then we initiate a call to Wallet Connect SDK and
|
||||
;; then replace the list we have stored in the database with the one that came from the SDK.
|
||||
;; In addition to that, we also update the backend state by marking sessions that are not
|
||||
;; active anymore by calling `:wallet-connect/disconnect-session`.
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/fetch-active-sessions-success
|
||||
(fn [{:keys [db now]} [sessions]]
|
||||
(let [persisted-sessions (:wallet-connect/sessions db)
|
||||
account-addresses (->> (get-in db [:wallet :accounts])
|
||||
vals
|
||||
sessions/filter-operable-accounts
|
||||
(map :address))
|
||||
sessions (->> (js->clj sessions :keywordize-keys true)
|
||||
vals
|
||||
(map sessions/sdk-session->db-session)
|
||||
(sessions/filter-sessions-for-account-addresses
|
||||
account-addresses))
|
||||
session-topics (set (map :topic sessions))
|
||||
expired-sessions (filter
|
||||
(fn [{:keys [expiry topic]}]
|
||||
(or (< expiry (/ now 1000))
|
||||
(not (contains? session-topics topic))))
|
||||
persisted-sessions)]
|
||||
(when (seq expired-sessions)
|
||||
(log/info "Updating WalletConnect persisted sessions due to expired/inactive sessions"
|
||||
{:expired expired-sessions}))
|
||||
{:fx (mapv (fn [{:keys [topic]}]
|
||||
[:dispatch [:wallet-connect/disconnect-persisted-session topic]])
|
||||
expired-sessions)
|
||||
:db (assoc db :wallet-connect/sessions sessions)})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/fetch-active-sessions
|
||||
(fn [{:keys [db]}]
|
||||
(let [web3-wallet (get db :wallet-connect/web3-wallet)]
|
||||
{:fx [[:effects.wallet-connect/fetch-active-sessions
|
||||
{:web3-wallet web3-wallet
|
||||
:on-fail #(log/error "Failed to get active sessions" {:error %})
|
||||
:on-success #(rf/dispatch [:wallet-connect/fetch-active-sessions-success %])}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/fetch-persisted-sessions-success
|
||||
(fn [{:keys [db]} [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
|
||||
:wallet-connect/fetch-persisted-sessions-fail
|
||||
(fn [_ [error]]
|
||||
(log/info "Wallet Connect fetch persisted sessions failed" error)
|
||||
{:fx [[:dispatch [:wallet-connect/fetch-active-sessions]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/fetch-persisted-sessions
|
||||
(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
|
||||
(fn [_ [session-info]]
|
||||
(let [redirect-url (-> session-info
|
||||
(js->clj :keywordize-keys true)
|
||||
(data-store/get-dapp-redirect-url))]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wallet_addWalletConnectSession"
|
||||
:params [(js/JSON.stringify session-info)]
|
||||
: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
|
||||
:wallet-connect/disconnect-persisted-session
|
||||
(fn [{:keys [db]} [topic]]
|
||||
(log/info "Removing session from persistance and state" topic)
|
||||
{:db (update db
|
||||
:wallet-connect/sessions
|
||||
(fn [sessions]
|
||||
(->> sessions
|
||||
(remove #(= (:topic %) topic))
|
||||
(into []))))
|
||||
:fx [[:json-rpc/call
|
||||
[{:method "wallet_disconnectWalletConnectSession"
|
||||
:params [topic]
|
||||
:on-success #(log/info "Wallet Connect session disconnected")
|
||||
:on-error #(log/info "Wallet Connect session persistence failed" %)}]]]}))
|
|
@ -2,14 +2,15 @@
|
|||
(:require [clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.contexts.wallet.wallet-connect.core :as core]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.common.header.style :as style]))
|
||||
[status-im.contexts.wallet.wallet-connect.modals.common.header.style :as style]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]))
|
||||
|
||||
(defn view
|
||||
[{:keys [label dapp account]}]
|
||||
[rn/view {:style style/header-container}
|
||||
(let [{:keys [name iconUrl url]} dapp
|
||||
image-source (core/compute-dapp-icon-path iconUrl url)]
|
||||
image-source (data-store/compute-dapp-icon-path iconUrl url)]
|
||||
[rn/view {:style style/dapp-container}
|
||||
[quo/summary-tag
|
||||
{:type :dapp
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.session-proposal.style
|
||||
(ns status-im.contexts.wallet.wallet-connect.modals.session-proposal.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(def dapp-avatar
|
|
@ -1,4 +1,4 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.session-proposal.view
|
||||
(ns status-im.contexts.wallet.wallet-connect.modals.session-proposal.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
|
@ -6,8 +6,8 @@
|
|||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
|
||||
[status-im.contexts.wallet.wallet-connect.session-proposal.style :as style]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.session-proposal.style :as style]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as data-store]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.string]))
|
||||
|
@ -17,8 +17,8 @@
|
|||
(let [proposer (rf/sub [:wallet-connect/session-proposer])
|
||||
{:keys [icons name url]} (:metadata proposer)
|
||||
first-icon (first icons)
|
||||
dapp-name (wallet-connect-core/compute-dapp-name name url)
|
||||
profile-picture (wallet-connect-core/compute-dapp-icon-path first-icon url)]
|
||||
dapp-name (data-store/compute-dapp-name name url)
|
||||
profile-picture (data-store/compute-dapp-icon-path first-icon url)]
|
||||
[:<>
|
||||
[rn/view {:style style/dapp-avatar}
|
||||
[quo/user-avatar
|
|
@ -0,0 +1,75 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.utils.data-store
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[status-im.constants :as constants]
|
||||
utils.string
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn compute-dapp-name
|
||||
"Sometimes dapps have no name or an empty name. Return url as name in that case"
|
||||
[name url]
|
||||
(if (seq name)
|
||||
name
|
||||
(when (seq url)
|
||||
(-> url
|
||||
utils.string/remove-trailing-slash
|
||||
utils.string/remove-http-prefix
|
||||
string/capitalize))))
|
||||
|
||||
(defn compute-dapp-icon-path
|
||||
"Some dapps have icons with relative paths, make paths absolute in those cases, send nil if icon is missing"
|
||||
[icon-path url]
|
||||
(when (and (seq icon-path)
|
||||
(seq url))
|
||||
(if (string/starts-with? icon-path "http")
|
||||
icon-path
|
||||
(str (utils.string/remove-trailing-slash url) icon-path))))
|
||||
|
||||
(def method-to-screen
|
||||
{constants/wallet-connect-personal-sign-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-typed-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-typed-v4-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-send-transaction-method :screen/wallet-connect.send-transaction
|
||||
constants/wallet-connect-eth-sign-transaction-method :screen/wallet-connect.sign-transaction})
|
||||
|
||||
(defn extract-native-call-signature
|
||||
[data]
|
||||
(-> data transforms/json->clj :result))
|
||||
|
||||
(defn get-request-method
|
||||
[event]
|
||||
(get-in event [:params :request :method]))
|
||||
|
||||
(defn get-request-params
|
||||
[event]
|
||||
(get-in event [:params :request :params]))
|
||||
|
||||
(defn get-db-current-request-event
|
||||
[db]
|
||||
(get-in db [:wallet-connect/current-request :event]))
|
||||
|
||||
(defn get-session-dapp-metadata
|
||||
[proposal]
|
||||
(let [metadata (get-in proposal [:params :proposer :metadata])
|
||||
origin (get-in proposal [:verifyContext :verified :origin])]
|
||||
(or metadata {:url origin})))
|
||||
|
||||
(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
|
||||
[db]
|
||||
(-> db
|
||||
get-db-current-request-event
|
||||
get-request-params))
|
|
@ -0,0 +1,27 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.utils.data-store-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest is testing]]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :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))))))
|
|
@ -0,0 +1,92 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.utils.networks
|
||||
(:require [clojure.edn :as edn]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as string]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils.networks :as networks]
|
||||
[utils.string]))
|
||||
|
||||
(defn chain-id->eip155
|
||||
[chain-id]
|
||||
(str "eip155:" chain-id))
|
||||
|
||||
(defn eip155->chain-id
|
||||
[chain-id-str]
|
||||
(-> chain-id-str
|
||||
(string/split #":")
|
||||
last
|
||||
edn/read-string))
|
||||
|
||||
(defn format-eip155-address
|
||||
[address chain-id]
|
||||
(str chain-id ":" address))
|
||||
|
||||
(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]
|
||||
(let [add-testnet-name (fn [testnet-name]
|
||||
(update network :full-name #(str % " " testnet-name)))]
|
||||
(condp #(contains? %1 %2) (:chain-id network)
|
||||
constants/sepolia-chain-ids (add-testnet-name constants/sepolia-full-name)
|
||||
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 session-networks-allowed?
|
||||
[testnet-mode? {:keys [chains]}]
|
||||
(let [chain-ids (set (map (fn [chain]
|
||||
(-> chain
|
||||
(string/split ":")
|
||||
second
|
||||
js/parseInt))
|
||||
chains))]
|
||||
(if testnet-mode?
|
||||
(set/subset? chain-ids (set/union constants/sepolia-chain-ids constants/goerli-chain-ids))
|
||||
(set/subset? chain-ids constants/mainnet-chain-ids))))
|
||||
|
||||
(defn get-proposal-networks
|
||||
[proposal]
|
||||
(let [required-namespaces (get-in proposal [:params :requiredNamespaces])
|
||||
optional-namespaces (get-in proposal [:params :optionalNamespaces])]
|
||||
(->> [required-namespaces optional-namespaces]
|
||||
(map #(get-in % [:eip155 :chains]))
|
||||
(apply concat)
|
||||
(into #{}))))
|
||||
|
||||
(defn proposal-networks-intersection
|
||||
[proposal supported-networks]
|
||||
(let [proposed-networks (get-proposal-networks proposal)]
|
||||
(->> supported-networks
|
||||
(filter #(->> %
|
||||
chain-id->eip155
|
||||
(contains? proposed-networks))))))
|
||||
|
||||
(defn required-networks-supported?
|
||||
[proposal supported-networks]
|
||||
(let [supported-namespaces #{:eip155}
|
||||
required-namespaces (get-in proposal [:params :requiredNamespaces])]
|
||||
(when (every? #(contains? supported-namespaces %)
|
||||
(keys required-namespaces))
|
||||
(let [required-networks (get-in required-namespaces [:eip155 :chains])
|
||||
supported-eip155 (set (map chain-id->eip155 supported-networks))]
|
||||
(every? #(contains? supported-eip155 %)
|
||||
required-networks)))))
|
||||
|
||||
(defn get-networks-by-mode
|
||||
[db]
|
||||
(let [test-mode? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
networks (get-in db [:wallet :networks (if test-mode? :test :prod)])]
|
||||
(mapv #(-> % :chain-id) networks)))
|
||||
|
||||
(defn event-should-be-handled?
|
||||
[db {:keys [topic]}]
|
||||
(let [testnet-mode? (get-in db [:profile/profile :test-networks-enabled?])]
|
||||
(some #(and (= (:topic %) topic)
|
||||
(session-networks-allowed? testnet-mode? %))
|
||||
(:wallet-connect/sessions db))))
|
|
@ -1,4 +1,4 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.rpc
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.rpc
|
||||
(:require [oops.core :as oops]
|
||||
[promesa.core :as promesa]
|
||||
[status-im.common.json-rpc.events :as rpc-events]
|
|
@ -0,0 +1,33 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.utils.sessions
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn sdk-session->db-session
|
||||
[{:keys [topic expiry pairingTopic] :as session}]
|
||||
{:topic topic
|
||||
:expiry expiry
|
||||
:sessionJson (transforms/clj->json session)
|
||||
:pairingTopic pairingTopic
|
||||
:name (get-in session [:peer :metadata :name])
|
||||
:iconUrl (get-in session [:peer :metadata :icons 0])
|
||||
:url (get-in session [:peer :metadata :url])
|
||||
:accounts (get-in session [:namespaces :eip155 :accounts])
|
||||
:chains (get-in session [:namespaces :eip155 :chains])
|
||||
:disconnected false})
|
||||
|
||||
(defn filter-operable-accounts
|
||||
[accounts]
|
||||
(filter #(and (:operable? %)
|
||||
(not (:watch-only? %)))
|
||||
accounts))
|
||||
|
||||
(defn filter-sessions-for-account-addresses
|
||||
[account-addresses sessions]
|
||||
(filter (fn [{:keys [accounts]}]
|
||||
(some (fn [account]
|
||||
(some (fn [account-address]
|
||||
(string/includes? account account-address))
|
||||
account-addresses))
|
||||
accounts))
|
||||
sessions))
|
|
@ -1,8 +1,10 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.signing
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.signing
|
||||
(:require [native-module.core :as native-module]
|
||||
[promesa.core :as promesa]
|
||||
[status-im.contexts.wallet.wallet-connect.core :as core]
|
||||
[status-im.contexts.wallet.wallet-connect.rpc :as rpc]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
|
||||
[utils.hex :as hex]
|
||||
[utils.number :as number]
|
||||
[utils.transforms :as transforms]))
|
||||
|
@ -29,7 +31,7 @@
|
|||
:password password}
|
||||
transforms/clj->json
|
||||
native-module/sign-message
|
||||
(promesa/then core/extract-native-call-signature)))
|
||||
(promesa/then data-store/extract-native-call-signature)))
|
||||
|
||||
(defn personal-sign
|
||||
[password address data]
|
||||
|
@ -40,7 +42,7 @@
|
|||
(defn eth-sign-typed-data
|
||||
[password address data chain-id-eip155 version]
|
||||
(let [legacy? (= version :v1)
|
||||
chain-id (core/eip155->chain-id chain-id-eip155)]
|
||||
chain-id (networks/eip155->chain-id chain-id-eip155)]
|
||||
(rpc/wallet-safe-sign-typed-data data
|
||||
address
|
||||
password
|
|
@ -1,17 +1,18 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.transactions
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.transactions
|
||||
(:require [cljs-bean.core :as bean]
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[promesa.core :as promesa]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.wallet-connect.core :as core]
|
||||
[status-im.contexts.wallet.wallet-connect.rpc :as rpc]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
|
||||
[utils.money :as money]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn transaction-request?
|
||||
[event]
|
||||
(->> (core/get-request-method event)
|
||||
(->> (data-store/get-request-method event)
|
||||
(contains? #{constants/wallet-connect-eth-send-transaction-method
|
||||
constants/wallet-connect-eth-sign-transaction-method})))
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
(ns status-im.contexts.wallet.wallet-connect.utils
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.uri
|
||||
(:require [react-native.wallet-connect :as wallet-connect]))
|
||||
|
||||
(defn version-supported?
|
|
@ -48,7 +48,7 @@
|
|||
status-im.contexts.wallet.send.events
|
||||
status-im.contexts.wallet.signals
|
||||
status-im.contexts.wallet.swap.events
|
||||
status-im.contexts.wallet.wallet-connect.events
|
||||
status-im.contexts.wallet.wallet-connect.events.core
|
||||
[status-im.db :as db]
|
||||
status-im.navigation.effects
|
||||
status-im.navigation.events
|
||||
|
|
|
@ -127,10 +127,11 @@
|
|||
[status-im.contexts.wallet.swap.swap-proposal.view :as wallet-swap-propasal]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.send-transaction.view :as
|
||||
wallet-connect-send-transaction]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.session-proposal.view :as
|
||||
wallet-connect-session-proposal]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.sign-message.view :as wallet-connect-sign-message]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.sign-transaction.view :as
|
||||
wallet-connect-sign-transaction]
|
||||
[status-im.contexts.wallet.wallet-connect.session-proposal.view :as wallet-connect-session-proposal]
|
||||
[status-im.navigation.options :as options]
|
||||
[status-im.navigation.transitions :as transitions]))
|
||||
|
||||
|
|
|
@ -20,12 +20,12 @@
|
|||
status-im.subs.wallet.activities
|
||||
status-im.subs.wallet.buy
|
||||
status-im.subs.wallet.collectibles
|
||||
status-im.subs.wallet.dapps.core
|
||||
status-im.subs.wallet.networks
|
||||
status-im.subs.wallet.saved-addresses
|
||||
status-im.subs.wallet.send
|
||||
status-im.subs.wallet.swap
|
||||
status-im.subs.wallet.wallet
|
||||
status-im.subs.wallet.wallet-connect))
|
||||
status-im.subs.wallet.wallet))
|
||||
|
||||
(defn reg-root-key-sub
|
||||
[sub-name db-key]
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
(ns status-im.subs.wallet.dapps.core
|
||||
(:require [re-frame.core :as rf]
|
||||
[status-im.contexts.wallet.common.utils :as wallet-utils]
|
||||
status-im.subs.wallet.dapps.proposals
|
||||
status-im.subs.wallet.dapps.requests
|
||||
status-im.subs.wallet.dapps.sessions
|
||||
status-im.subs.wallet.dapps.transactions
|
||||
[utils.string]))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/account-details-by-address
|
||||
:<- [:wallet/accounts-without-watched-accounts]
|
||||
(fn [accounts [_ address]]
|
||||
(let [{:keys [customization-color name emoji]} (wallet-utils/get-account-by-address accounts address)]
|
||||
{:customization-color customization-color
|
||||
:name name
|
||||
:emoji emoji})))
|
|
@ -0,0 +1,45 @@
|
|||
(ns status-im.subs.wallet.dapps.proposals
|
||||
(:require [re-frame.core :as rf]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[utils.string]))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-proposal-request
|
||||
:<- [:wallet-connect/current-proposal]
|
||||
:-> :request)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/session-proposal-networks
|
||||
:<- [:wallet-connect/current-proposal]
|
||||
:-> :session-networks)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/session-proposer
|
||||
:<- [:wallet-connect/current-proposal-request]
|
||||
(fn [proposal]
|
||||
(-> proposal :params :proposer)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/session-proposer-name
|
||||
:<- [:wallet-connect/session-proposer]
|
||||
(fn [proposer]
|
||||
(let [{:keys [name url]} (-> proposer :metadata)]
|
||||
(data-store/compute-dapp-name name url))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/session-proposal-network-details
|
||||
:<- [:wallet-connect/session-proposal-networks]
|
||||
:<- [:wallet/network-details]
|
||||
(fn [[session-networks network-details]]
|
||||
(let [supported-networks (map :chain-id network-details)
|
||||
session-networks (filterv #(contains? (set session-networks) (:chain-id %))
|
||||
network-details)
|
||||
all-networks-in-session? (= (count supported-networks) (count session-networks))]
|
||||
{:session-networks session-networks
|
||||
:all-networks-in-session? all-networks-in-session?})))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-proposal-address
|
||||
(fn [db]
|
||||
(get-in db [:wallet-connect/current-proposal :address])))
|
|
@ -1,9 +1,9 @@
|
|||
(ns status-im.subs.wallet.wallet-connect-test
|
||||
(ns status-im.subs.wallet.dapps.proposals-test
|
||||
(:require
|
||||
[cljs.test :refer [is testing]]
|
||||
[re-frame.db :as rf-db]
|
||||
status-im.subs.root
|
||||
status-im.subs.wallet.wallet-connect
|
||||
status-im.subs.wallet.dapps.core
|
||||
[test-helpers.unit :as h]
|
||||
[utils.re-frame :as rf]))
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
(ns status-im.subs.wallet.dapps.requests
|
||||
(:require [re-frame.core :as rf]
|
||||
[status-im.contexts.wallet.common.utils :as wallet-utils]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[utils.string]))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-address
|
||||
:<- [:wallet-connect/current-request]
|
||||
:-> :address)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-display-data
|
||||
:<- [:wallet-connect/current-request]
|
||||
:-> :display-data)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-account-details
|
||||
:<- [:wallet-connect/current-request-address]
|
||||
:<- [:wallet/accounts-without-watched-accounts]
|
||||
(fn [[address accounts]]
|
||||
(let [{:keys [customization-color name emoji]} (wallet-utils/get-account-by-address accounts address)]
|
||||
{:customization-color customization-color
|
||||
:name name
|
||||
:emoji emoji})))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-dapp
|
||||
:<- [:wallet-connect/current-request]
|
||||
:<- [:wallet-connect/sessions]
|
||||
(fn [[request sessions]]
|
||||
(data-store/get-current-request-dapp request sessions)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/chain-id
|
||||
:<- [:wallet-connect/current-request]
|
||||
(fn [request]
|
||||
(-> request
|
||||
(get-in [:event :params :chainId])
|
||||
(networks/eip155->chain-id))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-network
|
||||
:<- [:wallet-connect/chain-id]
|
||||
networks/chain-id->network-details)
|
|
@ -0,0 +1,25 @@
|
|||
(ns status-im.subs.wallet.dapps.sessions
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :as rf]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[utils.string]))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/sessions-for-current-account
|
||||
:<- [:wallet-connect/sessions]
|
||||
:<- [:wallet/current-viewing-account-address]
|
||||
(fn [[sessions address]]
|
||||
(filter
|
||||
(fn [{:keys [accounts]}]
|
||||
(some #(string/includes? % address) accounts))
|
||||
sessions)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/sessions-for-current-account-and-networks
|
||||
:<- [:wallet-connect/sessions-for-current-account]
|
||||
:<- [:profile/test-networks-enabled?]
|
||||
(fn [[sessions testnet-mode?]]
|
||||
(filter
|
||||
(partial networks/session-networks-allowed? testnet-mode?)
|
||||
sessions)))
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
(ns status-im.subs.wallet.dapps.transactions
|
||||
(:require [re-frame.core :as rf]
|
||||
[status-im.contexts.wallet.common.utils :as wallet-utils]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transactions]
|
||||
[utils.money :as money]
|
||||
[utils.string]))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/transaction-args
|
||||
:<- [:wallet-connect/current-request]
|
||||
(fn [{:keys [event transaction]}]
|
||||
(when (transactions/transaction-request? event)
|
||||
transaction)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/transaction-suggested-fees
|
||||
:<- [:wallet-connect/current-request]
|
||||
(fn [{:keys [event raw-data]}]
|
||||
(when (transactions/transaction-request? event)
|
||||
(:suggested-fees raw-data))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/transaction-max-fees-wei
|
||||
:<- [:wallet-connect/transaction-args]
|
||||
:<- [:wallet-connect/transaction-suggested-fees]
|
||||
(fn [[transaction suggested-fees]]
|
||||
(when transaction
|
||||
(let [{:keys [gasPrice gas gasLimit maxFeePerGas]} transaction
|
||||
eip-1559-chain? (:eip1559Enabled suggested-fees)
|
||||
gas-limit (or gasLimit gas)
|
||||
max-gas-fee (if eip-1559-chain? maxFeePerGas gasPrice)]
|
||||
(money/bignumber (* max-gas-fee gas-limit))))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/account-eth-token
|
||||
:<- [:wallet-connect/current-request-address]
|
||||
:<- [:wallet/accounts]
|
||||
(fn [[address accounts]]
|
||||
(let [fee-token "ETH"
|
||||
find-account #(when (= (:address %) address) %)
|
||||
find-token #(when (= (:symbol %) fee-token) %)]
|
||||
(->> accounts
|
||||
(some find-account)
|
||||
:tokens
|
||||
(some find-token)))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-transaction-information
|
||||
:<- [:wallet-connect/chain-id]
|
||||
:<- [:wallet-connect/transaction-max-fees-wei]
|
||||
:<- [:wallet-connect/transaction-args]
|
||||
:<- [:wallet-connect/account-eth-token]
|
||||
:<- [:profile/currency]
|
||||
:<- [:profile/currency-symbol]
|
||||
(fn [[chain-id max-fees-wei transaction eth-token currency currency-symbol]]
|
||||
(when transaction
|
||||
(let [max-fees-ether (money/wei->ether max-fees-wei)
|
||||
max-fees-fiat (wallet-utils/calculate-token-fiat-value {:currency currency
|
||||
:balance max-fees-ether
|
||||
:token eth-token})
|
||||
max-fees-fiat-formatted (-> (wallet-utils/get-standard-crypto-format eth-token max-fees-ether)
|
||||
(wallet-utils/get-standard-fiat-format currency-symbol
|
||||
max-fees-fiat))
|
||||
balance (-> eth-token
|
||||
(get-in [:balances-per-chain chain-id :raw-balance])
|
||||
money/bignumber)
|
||||
tx-value (money/bignumber (:value transaction))
|
||||
total-transaction-value (money/add max-fees-wei tx-value)]
|
||||
{:total-transaction-value total-transaction-value
|
||||
:balance balance
|
||||
:max-fees max-fees-wei
|
||||
:max-fees-fiat-value max-fees-fiat
|
||||
:max-fees-fiat-formatted max-fees-fiat-formatted
|
||||
:error-state (cond
|
||||
(not (money/sufficient-funds? tx-value balance))
|
||||
:not-enough-assets
|
||||
|
||||
(not (money/sufficient-funds? total-transaction-value
|
||||
balance))
|
||||
:not-enough-assets-to-pay-gas-fees)}))))
|
|
@ -1,190 +0,0 @@
|
|||
(ns status-im.subs.wallet.wallet-connect
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :as rf]
|
||||
[status-im.contexts.wallet.common.utils :as wallet-utils]
|
||||
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
|
||||
[status-im.contexts.wallet.wallet-connect.transactions :as transactions]
|
||||
[utils.money :as money]
|
||||
[utils.string]))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-address
|
||||
:<- [:wallet-connect/current-request]
|
||||
:-> :address)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-display-data
|
||||
:<- [:wallet-connect/current-request]
|
||||
:-> :display-data)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/account-details-by-address
|
||||
:<- [:wallet/accounts-without-watched-accounts]
|
||||
(fn [accounts [_ address]]
|
||||
(let [{:keys [customization-color name emoji]} (wallet-utils/get-account-by-address accounts address)]
|
||||
{:customization-color customization-color
|
||||
:name name
|
||||
:emoji emoji})))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-account-details
|
||||
:<- [:wallet-connect/current-request-address]
|
||||
:<- [:wallet/accounts-without-watched-accounts]
|
||||
(fn [[address accounts]]
|
||||
(let [{:keys [customization-color name emoji]} (wallet-utils/get-account-by-address accounts address)]
|
||||
{:customization-color customization-color
|
||||
:name name
|
||||
:emoji emoji})))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-dapp
|
||||
:<- [:wallet-connect/current-request]
|
||||
:<- [:wallet-connect/sessions]
|
||||
(fn [[request sessions]]
|
||||
(wallet-connect-core/get-current-request-dapp request sessions)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/sessions-for-current-account
|
||||
:<- [:wallet-connect/sessions]
|
||||
:<- [:wallet/current-viewing-account-address]
|
||||
(fn [[sessions address]]
|
||||
(filter
|
||||
(fn [{:keys [accounts]}]
|
||||
(some #(string/includes? % address) accounts))
|
||||
sessions)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/sessions-for-current-account-and-networks
|
||||
:<- [:wallet-connect/sessions-for-current-account]
|
||||
:<- [:profile/test-networks-enabled?]
|
||||
(fn [[sessions testnet-mode?]]
|
||||
(filter
|
||||
(partial wallet-connect-core/session-networks-allowed? testnet-mode?)
|
||||
sessions)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/chain-id
|
||||
:<- [:wallet-connect/current-request]
|
||||
(fn [request]
|
||||
(-> request
|
||||
(get-in [:event :params :chainId])
|
||||
(wallet-connect-core/eip155->chain-id))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-network
|
||||
:<- [:wallet-connect/chain-id]
|
||||
wallet-connect-core/chain-id->network-details)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/transaction-args
|
||||
:<- [:wallet-connect/current-request]
|
||||
(fn [{:keys [event transaction]}]
|
||||
(when (transactions/transaction-request? event)
|
||||
transaction)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/transaction-suggested-fees
|
||||
:<- [:wallet-connect/current-request]
|
||||
(fn [{:keys [event raw-data]}]
|
||||
(when (transactions/transaction-request? event)
|
||||
(:suggested-fees raw-data))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/transaction-max-fees-wei
|
||||
:<- [:wallet-connect/transaction-args]
|
||||
:<- [:wallet-connect/transaction-suggested-fees]
|
||||
(fn [[transaction suggested-fees]]
|
||||
(when transaction
|
||||
(let [{:keys [gasPrice gas gasLimit maxFeePerGas]} transaction
|
||||
eip-1559-chain? (:eip1559Enabled suggested-fees)
|
||||
gas-limit (or gasLimit gas)
|
||||
max-gas-fee (if eip-1559-chain? maxFeePerGas gasPrice)]
|
||||
(money/bignumber (* max-gas-fee gas-limit))))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/account-eth-token
|
||||
:<- [:wallet-connect/current-request-address]
|
||||
:<- [:wallet/accounts]
|
||||
(fn [[address accounts]]
|
||||
(let [fee-token "ETH"
|
||||
find-account #(when (= (:address %) address) %)
|
||||
find-token #(when (= (:symbol %) fee-token) %)]
|
||||
(->> accounts
|
||||
(some find-account)
|
||||
:tokens
|
||||
(some find-token)))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-request-transaction-information
|
||||
:<- [:wallet-connect/chain-id]
|
||||
:<- [:wallet-connect/transaction-max-fees-wei]
|
||||
:<- [:wallet-connect/transaction-args]
|
||||
:<- [:wallet-connect/account-eth-token]
|
||||
:<- [:profile/currency]
|
||||
:<- [:profile/currency-symbol]
|
||||
(fn [[chain-id max-fees-wei transaction eth-token currency currency-symbol]]
|
||||
(when transaction
|
||||
(let [max-fees-ether (money/wei->ether max-fees-wei)
|
||||
max-fees-fiat (wallet-utils/calculate-token-fiat-value {:currency currency
|
||||
:balance max-fees-ether
|
||||
:token eth-token})
|
||||
max-fees-fiat-formatted (-> (wallet-utils/get-standard-crypto-format eth-token max-fees-ether)
|
||||
(wallet-utils/get-standard-fiat-format currency-symbol
|
||||
max-fees-fiat))
|
||||
balance (-> eth-token
|
||||
(get-in [:balances-per-chain chain-id :raw-balance])
|
||||
money/bignumber)
|
||||
tx-value (money/bignumber (:value transaction))
|
||||
total-transaction-value (money/add max-fees-wei tx-value)]
|
||||
{:total-transaction-value total-transaction-value
|
||||
:balance balance
|
||||
:max-fees max-fees-wei
|
||||
:max-fees-fiat-value max-fees-fiat
|
||||
:max-fees-fiat-formatted max-fees-fiat-formatted
|
||||
:error-state (cond
|
||||
(not (money/sufficient-funds? tx-value balance))
|
||||
:not-enough-assets
|
||||
|
||||
(not (money/sufficient-funds? total-transaction-value
|
||||
balance))
|
||||
:not-enough-assets-to-pay-gas-fees)}))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-proposal-request
|
||||
:<- [:wallet-connect/current-proposal]
|
||||
:-> :request)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/session-proposal-networks
|
||||
:<- [:wallet-connect/current-proposal]
|
||||
:-> :session-networks)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/session-proposer
|
||||
:<- [:wallet-connect/current-proposal-request]
|
||||
(fn [proposal]
|
||||
(-> proposal :params :proposer)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/session-proposer-name
|
||||
:<- [:wallet-connect/session-proposer]
|
||||
(fn [proposer]
|
||||
(let [{:keys [name url]} (-> proposer :metadata)]
|
||||
(wallet-connect-core/compute-dapp-name name url))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/session-proposal-network-details
|
||||
:<- [:wallet-connect/session-proposal-networks]
|
||||
:<- [:wallet/network-details]
|
||||
(fn [[session-networks network-details]]
|
||||
(let [supported-networks (map :chain-id network-details)
|
||||
session-networks (filterv #(contains? (set session-networks) (:chain-id %))
|
||||
network-details)
|
||||
all-networks-in-session? (= (count supported-networks) (count session-networks))]
|
||||
{:session-networks session-networks
|
||||
:all-networks-in-session? all-networks-in-session?})))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/current-proposal-address
|
||||
(fn [db]
|
||||
(get-in db [:wallet-connect/current-proposal :address])))
|
Loading…
Reference in New Issue