Fix WalletConnect transactions (#20608)

* fix: sign-transaction

Signed-off-by: Lungu Cristian <lungucristian95@gmail.com>

* fix: sendTranasaction not working

Signed-off-by: Lungu Cristian <lungucristian95@gmail.com>

* ref: removing 0x from the signature

Signed-off-by: Lungu Cristian <lungucristian95@gmail.com>

* ref: tx data from responding to processing events

Signed-off-by: Lungu Cristian <lungucristian95@gmail.com>

* fix: request dapp subscription

Signed-off-by: Lungu Cristian <lungucristian95@gmail.com>

* fix: tx data bug

Signed-off-by: Lungu Cristian <lungucristian95@gmail.com>

---------

Signed-off-by: Lungu Cristian <lungucristian95@gmail.com>
This commit is contained in:
Lungu Cristian 2024-07-03 12:13:13 +02:00 committed by GitHub
parent e58e2209bb
commit f51f52ec27
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 169 additions and 60 deletions

View File

@ -282,6 +282,8 @@
(def ^:const wallet-connect-session-proposal-event "session_proposal") (def ^:const wallet-connect-session-proposal-event "session_proposal")
(def ^:const wallet-connect-session-request-event "session_request") (def ^:const wallet-connect-session-request-event "session_request")
(def ^:const transaction-pending-type-wallet-connect-transfer "WalletConnectTransfer")
(def ^:const dapp-permission-contact-code "contact-code") (def ^:const dapp-permission-contact-code "contact-code")
(def ^:const dapp-permission-web3 "web3") (def ^:const dapp-permission-web3 "web3")
(def ^:const dapp-permission-qr-code "qr-code") (def ^:const dapp-permission-qr-code "qr-code")

View File

@ -1,5 +1,6 @@
(ns status-im.contexts.wallet.wallet-connect.effects (ns status-im.contexts.wallet.wallet-connect.effects
(:require [cljs-bean.core :as bean] (:require
[cljs-bean.core :as bean]
[native-module.core :as native-module] [native-module.core :as native-module]
[promesa.core :as promesa] [promesa.core :as promesa]
[re-frame.core :as rf] [re-frame.core :as rf]
@ -7,6 +8,7 @@
[status-im.config :as config] [status-im.config :as config]
[status-im.constants :as constants] [status-im.constants :as constants]
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core] [status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
[status-im.contexts.wallet.wallet-connect.transactions :as transactions]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.security.core :as security] [utils.security.core :as security]
[utils.transforms :as transforms])) [utils.transforms :as transforms]))
@ -92,10 +94,24 @@
(promesa/then on-success) (promesa/then on-success)
(promesa/catch on-error)))) (promesa/catch on-error))))
(rf/reg-fx
:effects.wallet-connect/sign-transaction
(fn [{:keys [password address chain-id tx on-success on-error]}]
(-> (transactions/sign-transaction (security/safe-unmask-data password) address tx chain-id)
(promesa/then on-success)
(promesa/catch on-error))))
(rf/reg-fx
:effects.wallet-connect/send-transaction
(fn [{:keys [password address chain-id tx on-success on-error]}]
(-> (transactions/send-transaction (security/safe-unmask-data password) address tx chain-id)
(promesa/then on-success)
(promesa/catch on-error))))
(rf/reg-fx (rf/reg-fx
:effects.wallet-connect/sign-typed-data :effects.wallet-connect/sign-typed-data
(fn [{:keys [password address data version on-success on-error]}] (fn [{:keys [password address data version on-success on-error]}]
(-> (wallet-connect-core/sign-typed-data version data address password) (-> (wallet-connect-core/sign-typed-data version data address (security/safe-unmask-data password))
(promesa/then wallet-connect-core/extract-native-call-signature) (promesa/then wallet-connect-core/extract-native-call-signature)
(promesa/then on-success) (promesa/then on-success)
(promesa/catch on-error)))) (promesa/catch on-error))))

View File

@ -1,5 +1,6 @@
(ns status-im.contexts.wallet.wallet-connect.processing-events (ns status-im.contexts.wallet.wallet-connect.processing-events
(:require [native-module.core :as native-module] (:require [clojure.string :as string]
[native-module.core :as native-module]
[re-frame.core :as rf] [re-frame.core :as rf]
[status-im.constants :as constants] [status-im.constants :as constants]
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core] [status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
@ -45,7 +46,7 @@
{:db (update-in db {:db (update-in db
[:wallet-connect/current-request] [:wallet-connect/current-request]
assoc assoc
:address address :address (string/lower-case address)
:raw-data raw-data :raw-data raw-data
:display-data (or parsed-data raw-data))}))) :display-data (or parsed-data raw-data))})))
@ -57,7 +58,7 @@
{:db (update-in db {:db (update-in db
[:wallet-connect/current-request] [:wallet-connect/current-request]
assoc assoc
:address address :address (string/lower-case address)
:raw-data raw-data :raw-data raw-data
:display-data (or parsed-data raw-data))}))) :display-data (or parsed-data raw-data))})))
@ -68,12 +69,17 @@
display-data (-> event display-data (-> event
clj->js clj->js
(js/JSON.stringify nil 2)) (js/JSON.stringify nil 2))
{:keys [to]} (-> event wallet-connect-core/get-request-params first)]
{:keys [from] :as tx} (-> event wallet-connect-core/get-request-params first)
chain-id (-> event
(get-in [:params :chainId])
wallet-connect-core/eip155->chain-id)]
{:db (update-in db {:db (update-in db
[:wallet-connect/current-request] [:wallet-connect/current-request]
assoc assoc
:address to :address (string/lower-case from)
:raw-data event :raw-data tx
:chain-id chain-id
:display-data display-data)}))) :display-data display-data)})))
(rf/reg-event-fx (rf/reg-event-fx
@ -81,12 +87,16 @@
(fn [{:keys [db]}] (fn [{:keys [db]}]
(let [event (wallet-connect-core/get-db-current-request-event db) (let [event (wallet-connect-core/get-db-current-request-event db)
display-data (.stringify js/JSON (clj->js event) nil 2) display-data (.stringify js/JSON (clj->js event) nil 2)
{:keys [to]} (-> event wallet-connect-core/get-request-params first)] {:keys [from] :as tx} (-> event wallet-connect-core/get-request-params first)
chain-id (-> event
(get-in [:params :chainId])
wallet-connect-core/eip155->chain-id)]
{:db (update-in db {:db (update-in db
[:wallet-connect/current-request] [:wallet-connect/current-request]
assoc assoc
:address to :address (string/lower-case from)
:raw-data event :raw-data tx
:chain-id chain-id
:display-data display-data)}))) :display-data display-data)})))
(rf/reg-event-fx (rf/reg-event-fx
@ -103,6 +113,6 @@
{:db (update-in db {:db (update-in db
[:wallet-connect/current-request] [:wallet-connect/current-request]
assoc assoc
:address address :address (string/lower-case address)
:raw-data (or parsed-data raw-data) :display-data (or parsed-data raw-data)
:display-data parsed-data)}))) :raw-data raw-data)})))

View File

@ -14,17 +14,13 @@
[:dispatch [:wallet-connect/respond-personal-sign password]] [:dispatch [:wallet-connect/respond-personal-sign password]]
constants/wallet-connect-eth-send-transaction-method constants/wallet-connect-eth-send-transaction-method
[:dispatch [:dispatch [:wallet-connect/respond-send-transaction-data password]]
[:wallet-connect/respond-build-transaction
#(rf/dispatch [:wallet-connect/respond-send-transaction-data password %])]]
constants/wallet-connect-eth-sign-method constants/wallet-connect-eth-sign-method
[:dispatch [:wallet-connect/respond-eth-sign password]] [:dispatch [:wallet-connect/respond-eth-sign password]]
constants/wallet-connect-eth-sign-transaction-method constants/wallet-connect-eth-sign-transaction-method
[:dispatch [:dispatch [:wallet-connect/respond-sign-transaction-data password]]
[:wallet-connect/respond-build-transaction
#(rf/dispatch [:wallet-connect/respond-sign-transaction-data password %])]]
constants/wallet-connect-eth-sign-typed-method constants/wallet-connect-eth-sign-typed-method
[:dispatch [:wallet-connect/respond-sign-typed-data password :v1]] [:dispatch [:wallet-connect/respond-sign-typed-data password :v1]]
@ -67,40 +63,27 @@
:on-error #(rf/dispatch [:wallet-connect/on-sign-error %]) :on-error #(rf/dispatch [:wallet-connect/on-sign-error %])
:on-success #(rf/dispatch [:wallet-connect/send-response %])}]]}))) :on-success #(rf/dispatch [:wallet-connect/send-response %])}]]})))
(rf/reg-event-fx
:wallet-connect/respond-build-transaction
(fn [{:keys [db]} [on-success]]
(let [{:keys [raw-data]} (get db :wallet-connect/current-request)
chain-id (-> raw-data
(get-in [:params :chainId])
wallet-connect-core/eip155->chain-id)]
{:fx [[:json-rpc/call
[{:method "wallet_buildTransaction"
:params [chain-id (js/JSON.stringify raw-data)]
:on-success on-success
:on-error [:wallet-connect/on-sign-error]}]]]})))
(rf/reg-event-fx (rf/reg-event-fx
:wallet-connect/respond-send-transaction-data :wallet-connect/respond-send-transaction-data
(fn [_ [password data]] (fn [{:keys [db]} [password]]
(let [{:keys [address] (let [{:keys [chain-id raw-data address]} (get db :wallet-connect/current-request)]
message-to-sign :messageToSign} data] {:fx [[:effects.wallet-connect/send-transaction
{:fx [[:effects.wallet-connect/sign-message
{:password password {:password password
:address address :address address
:data message-to-sign :chain-id chain-id
:tx raw-data
:on-error #(rf/dispatch [:wallet-connect/on-sign-error %]) :on-error #(rf/dispatch [:wallet-connect/on-sign-error %])
:on-success #(rf/dispatch [:wallet-connect/send-response %])}]]}))) :on-success #(rf/dispatch [:wallet-connect/send-response %])}]]})))
(rf/reg-event-fx (rf/reg-event-fx
:wallet-connect/respond-sign-transaction-data :wallet-connect/respond-sign-transaction-data
(fn [_ [password data]] (fn [{:keys [db]} [password]]
(let [{:keys [address] (let [{:keys [chain-id raw-data address]} (get db :wallet-connect/current-request)]
message-to-sign :messageToSign} data] {:fx [[:effects.wallet-connect/sign-transaction
{:fx [[:effects.wallet-connect/sign-message
{:password password {:password password
:address address :address address
:data message-to-sign :chain-id chain-id
:tx raw-data
:on-error #(rf/dispatch [:wallet-connect/on-sign-error %]) :on-error #(rf/dispatch [:wallet-connect/on-sign-error %])
:on-success #(rf/dispatch [:wallet-connect/send-response %])}]]}))) :on-success #(rf/dispatch [:wallet-connect/send-response %])}]]})))

View File

@ -0,0 +1,98 @@
(ns status-im.contexts.wallet.wallet-connect.transactions
(:require [cljs-bean.core :as bean]
[clojure.string :as string]
[oops.core :as oops]
[promesa.core :as promesa]
[status-im.common.json-rpc.events :as rpc-events]
[status-im.constants :as constants]
[utils.transforms :as transforms]))
(defn- call-rpc
"Helper to handle RPC calls to status-go as promises"
[method & args]
(promesa/create
(fn [p-resolve p-reject]
(rpc-events/call {:method method
:params (vec args)
:on-success p-resolve
:on-error p-reject
:js-response true}))))
(defn- strip-hex-prefix
"Strips the extra 0 in hex value if present"
[hex-value]
(let [formatted-hex (string/replace hex-value #"^0x0*" "0x")]
(if (= formatted-hex "0x")
"0x0"
formatted-hex)))
(defn- format-tx-hex-values
"Due to how status-go expects hex values, we should remove the extra 0s in transaction hex values e.g. 0x0f -> 0xf"
[tx]
(let [tx-keys [:gasLimit :gas :gasPrice :nonce :value :maxFeePerGas :maxPriorityFeePerGas]]
(reduce (fn [acc tx-key]
(if (and (contains? tx tx-key)
(not (nil? (get tx tx-key))))
(update acc tx-key strip-hex-prefix)
acc))
tx
tx-keys)))
(defn- prepare-transaction-for-rpc
"Formats the transaction and transforms it into a stringified JS object, ready to be passed to an RPC call."
[tx]
(-> tx
format-tx-hex-values
bean/->js
(transforms/js-stringify 0)))
(defn wallet-sign-message-rpc
[password address data]
(-> (call-rpc "wallet_signMessage"
data
address
password)
;; NOTE: removing `0x`, as status-go expects the signature without it.
(promesa/then #(subs % 2))))
(defn- wallet-build-transaction-rpc
[chain-id tx]
(-> (call-rpc "wallet_buildTransaction" chain-id tx)
(promesa/then #(hash-map :message-to-sign (oops/oget % "messageToSign")
:tx-args (oops/oget % "txArgs")))))
(defn- wallet-build-raw-transaction-rpc
[chain-id tx-args signature]
(-> (call-rpc "wallet_buildRawTransaction"
chain-id
(transforms/js-stringify tx-args 0)
signature)
(promesa/then #(oops/oget % "rawTx"))))
(defn- wallet-send-transaction-with-signature-rpc
[chain-id tx-args signature]
(call-rpc "wallet_sendTransactionWithSignature"
chain-id
constants/transaction-pending-type-wallet-connect-transfer
(transforms/js-stringify tx-args 0)
signature))
(defn sign-transaction
[password address tx chain-id]
(promesa/let
[formatted-tx (prepare-transaction-for-rpc tx)
{:keys [message-to-sign tx-args]} (wallet-build-transaction-rpc chain-id formatted-tx)
signature (wallet-sign-message-rpc password address message-to-sign)
raw-tx (wallet-build-raw-transaction-rpc chain-id tx-args signature)]
raw-tx))
(defn send-transaction
[password address tx chain-id]
(promesa/let
[formatted-tx (prepare-transaction-for-rpc tx)
{:keys [message-to-sign tx-args]} (wallet-build-transaction-rpc chain-id formatted-tx)
signature (wallet-sign-message-rpc password address message-to-sign)
tx (wallet-send-transaction-with-signature-rpc chain-id
tx-args
signature)]
tx))

View File

@ -39,7 +39,7 @@
:<- [:wallet-connect/current-request] :<- [:wallet-connect/current-request]
:<- [:wallet-connect/pairings] :<- [:wallet-connect/pairings]
(fn [[request pairings]] (fn [[request pairings]]
(let [dapp-url (get-in request [:raw-data :verifyContext :verified :origin])] (let [dapp-url (get-in request [:event :verifyContext :verified :origin])]
(->> pairings (->> pairings
(filter (fn [pairing] (filter (fn [pairing]
(= dapp-url (get-in pairing [:peerMetadata :url])))) (= dapp-url (get-in pairing [:peerMetadata :url]))))