feat: added transaction record

This commit is contained in:
Cristian Lungu 2024-10-21 12:14:00 +03:00
parent 78ed7f5805
commit f9f8d4c524
No known key found for this signature in database
GPG Key ID: 00D675EDE1B264D9
7 changed files with 189 additions and 109 deletions

View File

@ -82,17 +82,16 @@
(rf/reg-event-fx
:wallet-connect/prepare-transaction-success
(fn [{:keys [db]} [prepared-tx]]
(let [{:keys [tx-args tx-details]} prepared-tx
tx (-> tx-args
bean/->clj
(transactions/Transaction. tx-details))]
(let [{:keys [tx-args]} prepared-tx
tx (-> tx-args
bean/->clj)]
{:db (update-in db
[:wallet-connect/current-request]
assoc
:raw-data prepared-tx
:address (.sender tx)
:transaction-summary (.summary tx)
:display-data (.beautify-params tx))})))
:raw-data prepared-tx
:transaction tx
:address (transactions/get-sender tx)
:display-data (transactions/beautify-transaction tx))})))
(rf/reg-event-fx
:wallet-connect/process-eth-send-transaction

View File

@ -55,7 +55,7 @@
:wallet-connect/respond-sign-typed-data
(fn [{:keys [db]} [password typed-data-version]]
(let [{:keys [address raw-data event]} (get db :wallet-connect/current-request)
chain-id (get-in event [:params :chainId])]
chain-id (data-store/get-chain-id event)]
{:fx [[:effects.wallet-connect/sign-typed-data
{:password password
:address address
@ -68,8 +68,9 @@
(rf/reg-event-fx
:wallet-connect/respond-send-transaction-data
(fn [{:keys [db]} [password]]
(let [{:keys [chain-id raw-data address]} (get db :wallet-connect/current-request)
{:keys [tx-hash tx-args]} raw-data]
(let [{:keys [raw-data address event]} (get db :wallet-connect/current-request)
{:keys [tx-hash tx-args]} raw-data
chain-id (data-store/get-chain-id event)]
{:fx [[:effects.wallet-connect/send-transaction
{:password password
:address address

View File

@ -13,6 +13,7 @@
[status-im.contexts.wallet.wallet-connect.modals.common.page-nav.view :as page-nav]
[status-im.contexts.wallet.wallet-connect.modals.common.style :as style]
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transaction-utils]
[status-im.setup.hot-reload :as hot-reload]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@ -73,9 +74,9 @@
(set! (.-current refetch-interval-ref)
(js/setInterval refetch-transaction constants/wallet-connect-transaction-refresh-interval-ms))))
(rn/use-unmount (fn []
(clear-interval)
(rf/dispatch [:wallet-connect/on-request-modal-dismissed])))
(hot-reload/use-safe-unmount (fn []
(clear-interval)
(rf/dispatch [:wallet-connect/on-request-modal-dismissed])))
[rn/view {:style (style/container bottom)}
[quo/gradient-cover {:customization-color customization-color}]

View File

@ -1,6 +1,5 @@
(ns status-im.contexts.wallet.wallet-connect.utils.rpc
(:require [cljs-bean.core :as bean]
[oops.core :as oops]
(:require [oops.core :as oops]
[promesa.core :as promesa]
[status-im.common.json-rpc.events :as rpc-events]
[status-im.constants :as constants]
@ -13,15 +12,6 @@
{:message-to-sign (oops/oget res :messageToSign)
:tx-args (oops/oget res :txArgs)}))
(defn wallet-build-raw-transaction
[chain-id tx-args signature]
(-> (rpc-events/call-async "wallet_buildRawTransaction"
true
chain-id
(transforms/js-stringify tx-args 0)
signature)
(promesa/then #(oops/oget % "rawTx"))))
(defn wallet-send-transaction-with-signature
[chain-id tx-args signature]
(rpc-events/call-async "wallet_sendTransactionWithSignature"
@ -80,9 +70,3 @@
[chain-id max-fee-per-gas]
(-> (rpc-events/call-async "wallet_getTransactionEstimatedTime" true chain-id max-fee-per-gas)
(promesa/then transforms/js->clj)))
(defn wallet-get-transaction-details
[transaction]
(->> (transforms/js-stringify transaction 0)
(rpc-events/call-async "wallet_getTransactionMetadata" true)
(transforms/js->clj)))

View File

@ -7,6 +7,8 @@
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
data-store]
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
[utils.address :as address]
[utils.hex :as hex]
[utils.money :as money]
[utils.transforms :as transforms]))
@ -132,11 +134,9 @@
(prepare-transaction-fees tx
tx-priority)
prepare-transaction-for-rpc
(rpc/wallet-build-transaction chain-id))
details (rpc/wallet-get-transaction-details tx-args)]
(rpc/wallet-build-transaction chain-id))]
{:tx-args tx-args
:tx-hash message-to-sign
:tx-details details
:tx-estimations estimations}))
(defn send-transaction
@ -153,82 +153,134 @@
(= k :Symbol)))
data))
(defrecord Transaction
[version from to gas gasPrice value nonce maxFeePerGas
maxPriorityFeePerGas input data multiTransactionID])
(def tx-args
(defn create-transaction
[tx]
;; TODO add malli check schema
(map->Transaction tx))
(defn- non-empty-hex
[hex-string]
(let [normalized (hex/normalize-hex hex-string)]
(when-not (string/blank? normalized)
hex-string)))
(defn get-data
[^Transaction tx]
(let [{:keys [input data]} tx]
(or (non-empty-hex input)
(non-empty-hex data))))
(def function-selector-to-type
{constants/method-id-transfer :transaction/erc-20-transfer
constants/method-id-approve :transaction/erc-20-approve})
(defn get-type
[^Transaction tx]
(let [tx-data (get-data tx)
eth-transfer? (nil? tx-data)
contract-type (when-not eth-transfer?
(-> tx-data (subs 0 10) function-selector-to-type))]
(cond
eth-transfer? :transaction/eth-transfer
(keyword? contract-type) contract-type
:else :transaction/unknown)))
(defn get-sender
[^Transaction tx]
(-> tx :from string/lower-case))
(defn- subs-bytes
[hex-data start-bytes end-bytes]
(when (-> hex-data count (/ 2) (>= end-bytes))
(-> hex-data
hex/normalize-hex
(subs (* start-bytes 2)
(* end-bytes 2)))))
(defn- decode-erc-20-transfer
"Decode ERC20 transfer data, which has the following function signature:
`approve(spender, amount)`"
[tx-data]
(when (>= (count tx-data) 138)
(let [selector (subs-bytes tx-data 0 4) ;; Function selector (first 4 bytes)
recipient-hex (subs-bytes tx-data 16 36) ;; Recipient address (next 32 bytes)
amount-hex (subs-bytes tx-data 36 68)] ;; Amount (next 32 bytes)
{:selector selector
:recipient (address/normalized-hex recipient-hex)
:amount (money/from-hex amount-hex)})))
(defn- decode-erc-20-approve
"Decode ERC20 transfer data, which has the following function signature:
`approve(spender, amount)`"
[tx-data]
(when (>= (count tx-data) 138)
(let [selector (subs-bytes tx-data 0 4) ;; Function selector (first 4 bytes)
spender-hex (subs-bytes tx-data 16 36) ;; Spender address (next 32 bytes)
amount-hex (subs-bytes tx-data 36 68)] ;; Amount (next 32 bytes)
{:selector selector
:spender (address/normalized-hex spender-hex)
:amount (money/from-hex amount-hex)})))
(defn get-recipient
"Get the transaction recipient, depending on the transaction type"
[^Transaction tx]
(let [default (:to tx)]
(condp = (get-type tx)
:transaction/eth-transfer default
:transaction/erc-20-transfer (-> tx
get-data
decode-erc-20-transfer
:recipient
(or default))
:transaction/erc-20-approve (-> tx
get-data
decode-erc-20-approve
:spender
(or default))
default)))
(defn get-amount
[^Transaction tx]
(let [default (-> tx :value money/from-hex)]
(condp = (get-type tx)
:transaction/eth-transfer default
:transaction/erc-20-transfer (-> tx get-data decode-erc-20-transfer :amount)
:transaction/erc-20-approve (-> tx get-data decode-erc-20-approve :amount)
default)))
(->
(decode-erc-20-transfer
"0xa9059cbb00000000000000000000000097654628dd47c2d88fc9b3d0cc38a92e46a32cd400000000000000000000000000000000000000000000000a0af513f7628a8000"))
(def tt
{:version 0
:from "0xb18ec1808bd8b84f244c6e34cbedee9b0cd7e1fb"
:to "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
:gas "0x21563"
:gasPrice "0xda9a06de5"
:gas "0x21e76"
:gasPrice "0x8b491f4cf"
:value "0x0"
:nonce "0x19"
:maxFeePerGas "0xda9a06de5"
:maxPriorityFeePerGas "0x5d56b25c"
:nonce "0x1b"
:maxFeePerGas "0x8b491f4cf"
:maxPriorityFeePerGas "0x3b9aca00"
:input "0x"
:data
"0xa9059cbb00000000000000000000000097654628dd47c2d88fc9b3d0cc38a92e46a32cd4000000000000000000000000000000000000000000000016ca63768fcf860000"
"0xa9059cbb00000000000000000000000097654628dd47c2d88fc9b3d0cc38a92e46a32cd400000000000000000000000000000000000000000000000a0af513f7628a8000"
:multiTransactionID 0})
(def tx-met
{:FunctionSelector "0xa9059cbb"
:FunctionName "transfer"
:Recipient "0x97654628dd47c2d88fc9b3d0cc38a92e46a32cd4"
:Amount "420412000000000000000"
:TokenID "<nil>"})
(get-amount tt)
(-> tt
decode-erc-20-transfer)
(defrecord Transaction [params metadata]
Object
(beautify-params [this]
(-> this :params beautify-transaction))
(get-type tt)
(type [this]
(condp = (get-in this [:metadata :FunctionName])
"" :transaction/eth-transfer
"transfer" :transaction/erc-20-transfer
"approve" :transaction/approve
:else :transaction/unknown))
(amount [this]
(let [metadata-amount (get-in this [:metadata :Amount])
params-amount (get-in this [:params :value])]
(-> (condp =
(.type this)
:transaction/erc-20-transfer
metadata-amount
:transaction/approve
metadata-amount
:else
params-amount)
money/bignumber)))
(sender [this]
(-> this :params :from string/lower-case))
(recipient [this]
(let [metadata-recipient (get-in this [:metadata :Recipient])
params-recipient (get-in this [:params :to])]
(-> (condp =
(.type this)
:transaction/erc-20-transfer
metadata-recipient
:transaction/approve
metadata-recipient
:else
params-recipient)
string/lower-case)))
(token-address [this]
(when (->> this
.type
(contains? #{:transaction/erc-20-transfer
:transaction/approve}))
(-> this :params :to string/lower-case)))
(summary [this]
{:type (.type this)
:amount (.amount this)
:recipient (.recipient this)
:sender (.sender this)
:token-address (.token-address this)}))
(def tx (->Transaction tx-args tx-met))
(defn get-contract-address
[^Transaction tx]
(condp = (get-type tx)
:transaction/erc-20-transfer (:to tx)
:transaction/erc-20-approve (:to tx)
nil))

View File

@ -1,7 +1,6 @@
(ns status-im.contexts.wallet.wallet-connect.utils.typed-data
(:require [clojure.string :as string]
[status-im.constants :as constants]
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
[utils.number :as number]))
@ -85,9 +84,8 @@
data-chain-id)))
(defn sign
[password address data chain-id-eip155 version]
(let [legacy? (= version :v1)
chain-id (networks/eip155->chain-id chain-id-eip155)]
[password address data chain-id version]
(let [legacy? (= version :v1)]
(rpc/wallet-safe-sign-typed-data data
address
password

View File

@ -6,11 +6,11 @@
[utils.string]))
(rf/reg-sub
:wallet-connect/transaction-args
:wallet-connect/transaction
:<- [:wallet-connect/current-request]
(fn [{:keys [event transaction]}]
(when (transactions/transaction-request? event)
transaction)))
(transactions/create-transaction transaction))))
(rf/reg-sub
:wallet-connect/transaction-suggested-fees
@ -22,7 +22,7 @@
(rf/reg-sub
:wallet-connect/transaction-max-fees-wei
:<- [:wallet-connect/transaction-args]
:<- [:wallet-connect/transaction]
:<- [:wallet-connect/transaction-suggested-fees]
(fn [[transaction suggested-fees]]
(when transaction
@ -49,7 +49,7 @@
:wallet-connect/current-request-transaction-information
:<- [:wallet-connect/chain-id]
:<- [:wallet-connect/transaction-max-fees-wei]
:<- [:wallet-connect/transaction-args]
:<- [:wallet-connect/transaction]
:<- [:wallet-connect/account-eth-token]
:<- [:profile/currency]
:<- [:profile/currency-symbol]
@ -78,3 +78,48 @@
(not (money/sufficient-funds? total-transaction-value
balance))
:not-enough-assets-to-pay-gas-fees)}))))
(rf/reg-sub
:wallet-connect/transaction-type
:<- [:wallet-connect/transaction]
transactions/get-type)
(rf/reg-sub
:wallet-connect/transaction-recipient
:<- [:wallet-connect/transaction]
transactions/get-recipient)
(rf/reg-sub
:wallet-connect/transaction-amount
:<- [:wallet-connect/transaction]
transactions/get-amount)
(rf/reg-sub
:wallet-connect/transaction-contract
:<- [:wallet-connect/transaction]
:<- [:wallet-connect/transaction-type]
:<- [:wallet/tokens]
(fn [[transaction type tokens]]
(->> tokens
:by-address
(some #(when (= (:address %) (transactions/get-contract-address transaction)) %)))
))
(comment
(->> [#_[:wallet-connect/transaction]
#_[:wallet-connect/transaction-type]
#_[:wallet-connect/transaction-recipient]
#_[:wallet-connect/transaction-amount]
[:wallet-connect/transaction-contract]
#_[:wallet/tokens]
]
(map (comp deref rf/subscribe)))
;; => ({:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e",
;; :decimals 18, :key "1-0x744d70fdbe2ba4cf95131626614a1763df805b9e", :community-id nil,
;; :symbol "SNT", :sources ["Uniswap Labs Default Token List" "Status Token List"], :name
;; "Status Network Token", :type :erc20, :verified? true, :chain-id 1,
;; :image nil})
)