Update sending transaction end point

This commit is contained in:
alwx 2024-10-31 13:08:50 +01:00
parent 58476a43da
commit 4b08052f39
No known key found for this signature in database
GPG Key ID: D9E51F0C88DB4E2A
22 changed files with 476 additions and 439 deletions

View File

@ -36,15 +36,15 @@
"wallet"
{:fx [[:dispatch [:wallet/signal-received event-js]]]}
"wallet.sign.transactions"
{:fx [[:dispatch
[:standard-auth/authorize-with-keycard
{:on-complete #(rf/dispatch [:keycard/sign-hash %
(first (transforms/js->clj event-js))])}]]]}
"wallet.suggested.routes"
{:fx [[:dispatch [:wallet/handle-suggested-routes (transforms/js->clj event-js)]]]}
"wallet.router.sign-transactions"
{:fx [[:dispatch [:wallet/sign-transactions-signal-received (transforms/js->clj event-js)]]]}
"wallet.router.transactions-sent"
{:fx [[:dispatch [:wallet/transactions-sent-signal-received (transforms/js->clj event-js)]]]}
"envelope.sent"
(messages.transport/update-envelopes-status
cofx

View File

@ -10,7 +10,7 @@
(defn enabled? [v] (= "1" v))
(goog-define INFURA_TOKEN "")
(goog-define INFURA_TOKEN "2a8db7e5dd1b414a896f2a0f73de18f9")
(goog-define POKT_TOKEN "3ef2018191814b7e1009b8d9")
(goog-define STATUS_BUILD_PROXY_USER "")
(goog-define STATUS_BUILD_PROXY_PASSWORD "")

View File

@ -6,7 +6,6 @@
status-im.contexts.keycard.nfc.events
status-im.contexts.keycard.nfc.sheets.events
status-im.contexts.keycard.pin.events
status-im.contexts.keycard.sign.events
[status-im.contexts.keycard.utils :as keycard.utils]
utils.datetime))

View File

@ -1,34 +0,0 @@
(ns status-im.contexts.keycard.sign.events
(:require [utils.address]
[utils.re-frame :as rf]))
(defn get-signature-map
[tx-hash signature]
{tx-hash {:r (subs signature 0 64)
:s (subs signature 64 128)
:v (subs signature 128 130)}})
(rf/reg-event-fx :keycard/sign
(fn [_ [data]]
{:effects.keycard/sign data}))
(rf/reg-event-fx :keycard/sign-hash
(fn [{:keys [db]} [pin-text tx-hash]]
(let [current-address (get-in db [:wallet :current-viewing-account-address])
path (get-in db [:wallet :accounts current-address :path])
key-uid (get-in db [:profile/profile :key-uid])]
{:fx [[:dispatch
[:keycard/connect
{:key-uid key-uid
:on-success
(fn []
(rf/dispatch
[:keycard/sign
{:pin pin-text
:path path
:hash (utils.address/naked-address tx-hash)
:on-success (fn [signature]
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:wallet/proceed-with-transactions-signatures
(get-signature-map tx-hash signature)]))
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]))}]]]})))

View File

@ -548,3 +548,15 @@
(:less-than-three-minutes constants/wallet-transaction-estimation) "1-3"
(:less-than-five-minutes constants/wallet-transaction-estimation) "3-5"
">5"))
(defn transactions->hash-to-transaction-map
[transactions]
(reduce
(fn [acc {to-chain :toChain tx-hash :hash}]
(assoc acc
tx-hash
{:status :pending
:id tx-hash
:chain-id to-chain}))
{}
transactions))

View File

@ -5,6 +5,7 @@
[promesa.core :as promesa]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.contexts.profile.recover.effects :as profile.recover.effects]
[status-im.contexts.wallet.rpc :as wallet-rpc]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
[utils.security.core :as security]
@ -103,3 +104,20 @@
(-> (verify-private-key-for-keypair keypair-key-uid private-key)
(promesa/then (partial rf/call-continuation on-success))
(promesa/catch (partial rf/call-continuation on-error)))))
(defn sign-transaction-hashes
[hashes address password]
(-> (promesa/all
(for [h hashes]
(wallet-rpc/sign-message h address password)))
(promesa/catch (fn [err]
(throw (ex-info "Failed to sign transaction hashes"
{:error err
:code :error/sign-transaction-hashes}))))))
(rf/reg-fx
:effects.wallet/sign-transaction-hashes
(fn [{:keys [hashes address password on-success on-error]}]
(-> (sign-transaction-hashes hashes address password)
(promesa/then on-success)
(promesa/catch on-error))))

View File

@ -686,3 +686,25 @@
(let [full-status (cske/transform-keys message transforms/->kebab-case-keyword)]
{:db (assoc-in db [:wallet :blockchain] full-status)})))
(rf/reg-event-fx
:wallet/sign-transactions-signal-received
(fn [{:keys [db]} [data]]
(let [type (if (or (= (get-in data [:sendDetails :fromToken])
(get-in data [:sendDetails :toToken]))
(string/blank? (get-in data [:sendDetails :toToken])))
:send
:swap)]
{:db (assoc-in db [:wallet :ui type :transaction-for-signing] data)})))
(rf/reg-event-fx
:wallet/transactions-sent-signal-received
(fn [{:keys [db]}
[{sent-transactions :sentTransactions
send-details :sendDetails}]]
(if (get-in db [:wallet :ui :swap])
{:fx [(if-let [error-response (:errorResponse send-details)]
[:dispatch [:wallet.swap/transaction-failure error-response]]
[:dispatch [:wallet.swap/transaction-success sent-transactions]])]}
{:fx [(if-let [error-response (:errorResponse send-details)]
[:dispatch [:wallet/transaction-failure error-response]]
[:dispatch [:wallet/transaction-success sent-transactions]])]})))

View File

@ -0,0 +1,61 @@
(ns status-im.contexts.wallet.rpc
(:require [oops.core :as oops]
[promesa.core :as promesa]
[status-im.common.json-rpc.events :as rpc-events]
[status-im.constants :as constants]
[utils.hex]
[utils.transforms :as transforms]))
(defn build-transaction
[chain-id tx]
(promesa/let [res (rpc-events/call-async "wallet_buildTransaction" true chain-id tx)]
{:message-to-sign (oops/oget res :messageToSign)
:tx-args (oops/oget res :txArgs)}))
(defn 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 hash-message-eip-191
[message]
(rpc-events/call-async "wallet_hashMessageEIP191" true message))
(defn safe-sign-typed-data
[data address password chain-id legacy?]
(rpc-events/call-async "wallet_safeSignTypedDataForDApps"
true
data
address
password
chain-id
legacy?))
(defn get-suggested-fees
[chain-id]
(-> (rpc-events/call-async "wallet_getSuggestedFees" true chain-id)
(promesa/then transforms/js->clj)))
(defn send-transaction-with-signature
[chain-id tx-args signature]
(rpc-events/call-async "wallet_sendTransactionWithSignature"
true
chain-id
constants/transaction-pending-type-wallet-connect-transfer
(transforms/js-stringify tx-args 0)
signature))
(defn sign-message
[message address password]
(-> (rpc-events/call-async "wallet_signMessage"
true
message
address
password)
(promesa/then (fn [s]
{:message message
:signature (utils.hex/normalize-hex s)}))))

View File

@ -1,7 +1,6 @@
(ns status-im.contexts.wallet.send.events
(:require
[clojure.string :as string]
[native-module.core :as native-module]
[status-im.constants :as constants]
[status-im.contexts.wallet.collectible.utils :as collectible.utils]
[status-im.contexts.wallet.common.utils :as utils]
@ -9,11 +8,10 @@
[status-im.contexts.wallet.data-store :as data-store]
[status-im.contexts.wallet.send.utils :as send-utils]
[taoensso.timbre :as log]
[utils.address :as address]
[utils.hex :as utils.hex]
[utils.money :as utils.money]
[utils.number]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.security.core :as security]))
(rf/reg-event-fx :wallet/clean-send-data
(fn [{:keys [db]}]
@ -327,22 +325,30 @@
(rf/reg-event-fx
:wallet/set-token-amount-to-send
(fn [{:keys [db]} [{:keys [amount stack-id start-flow?]}]]
{:db (assoc-in db [:wallet :ui :send :amount] amount)
:fx [[:dispatch
[:wallet/wizard-navigate-forward
{:current-screen stack-id
:start-flow? start-flow?
:flow-id :wallet-send-flow}]]]}))
(let [last-request-uuid (get-in db [:wallet :ui :send :last-request-uuid])]
{:db (-> db
(assoc-in [:wallet :ui :send :amount] amount)
(update-in [:wallet :ui :send] dissoc :transaction-for-signing))
:fx [[:dispatch [:wallet/build-transactions-from-route {:request-uuid last-request-uuid}]]
[:dispatch
[:wallet/wizard-navigate-forward
{:current-screen stack-id
:start-flow? start-flow?
:flow-id :wallet-send-flow}]]]})))
(rf/reg-event-fx
:wallet/set-token-amount-to-bridge
(fn [{:keys [db]} [{:keys [amount stack-id start-flow?]}]]
{:db (assoc-in db [:wallet :ui :send :amount] amount)
:fx [[:dispatch
[:wallet/wizard-navigate-forward
{:current-screen stack-id
:start-flow? start-flow?
:flow-id :wallet-bridge-flow}]]]}))
(let [last-request-uuid (get-in db [:wallet :ui :send :last-request-uuid])]
{:db (-> db
(assoc-in [:wallet :ui :send :amount] amount)
(update-in [:wallet :ui :send] dissoc :transaction-for-signing))
:fx [[:dispatch [:wallet/build-transactions-from-route {:request-uuid last-request-uuid}]]
[:dispatch
[:wallet/wizard-navigate-forward
{:current-screen stack-id
:start-flow? start-flow?
:flow-id :wallet-bridge-flow}]]]})))
(rf/reg-event-fx
:wallet/clean-bridge-to-selection
@ -458,7 +464,8 @@
:token-networks-ids token-networks-ids
:tx-type tx-type
:receiver? true}))
params [{:uuid (str (random-uuid))
request-uuid (str (random-uuid))
params [{:uuid request-uuid
:sendType send-type
:addrFrom from-address
:addrTo to-address
@ -477,7 +484,8 @@
{:db (update-in db
[:wallet :ui :send]
#(-> %
(assoc :amount amount
(assoc :last-request-uuid request-uuid
:amount amount
:loading-suggested-routes? true
:sender-network-values sender-network-values
:receiver-network-values receiver-network-values)
@ -565,27 +573,39 @@
:else [:wallet/suggested-routes-success (fix-routes data)
enough-assets?])]]})))))
(rf/reg-event-fx :wallet/add-authorized-transaction
(fn [{:keys [db]} [transaction]]
(let [transaction-batch-id (:id transaction)
transaction-hashes (:hashes transaction)
transaction-ids (flatten (vals transaction-hashes))
transaction-details (send-utils/map-multitransaction-by-ids transaction-batch-id
transaction-hashes)]
(rf/reg-event-fx
:wallet/transaction-success
(fn [{:keys [db]} [sent-transactions]]
(let [wallet-transactions (get-in db [:wallet :transactions] {})
transactions (utils/transactions->hash-to-transaction-map sent-transactions)
transaction-ids (->> transactions
vals
(map :hash))]
{:db (-> db
(assoc-in [:wallet :ui :send :just-completed-transaction?] true)
(assoc-in [:wallet :transactions] transaction-details)
(assoc-in [:wallet :ui :send :transaction-ids] transaction-ids))
:fx [;; Remove wallet/stop-and-clean-suggested-routes event when we move to new transaction
;; submission process as the routes as stopped by status-go
[:dispatch
[:wallet/stop-and-clean-suggested-routes]]
[:dispatch
[:wallet/end-transaction-flow]]
(assoc-in [:wallet :ui :send :transaction-ids] transaction-ids)
(assoc-in [:wallet :transactions] (merge wallet-transactions transactions)))
:fx [[:dispatch [:wallet/end-transaction-flow]]
[:dispatch-later
[{:ms 2000
:dispatch [:wallet/stop-and-clean-suggested-routes]}]]
[:dispatch-later
[{:ms 2000
:dispatch [:wallet/clean-just-completed-transaction]}]]]})))
(rf/reg-event-fx
:wallet/transaction-failure
(fn [_ [{:keys [details]}]]
{:fx [[:dispatch [:wallet/end-transaction-flow]]
[:dispatch-later
[{:ms 2000
:dispatch [:wallet/stop-and-clean-suggested-routes]}]]
[:dispatch
[:toasts/upsert
{:id :send-transaction-failure
:type :negative
:text (or details "An error occured")}]]]}))
(rf/reg-event-fx :wallet/clean-just-completed-transaction
(fn [{:keys [db]}]
{:db (update-in db [:wallet :ui :send] dissoc :just-completed-transaction?)}))
@ -609,100 +629,65 @@
[{:ms 20
:dispatch [:wallet/clean-up-transaction-flow]}]]]})))
(rf/reg-event-fx :wallet/send-transaction
(fn [{:keys [db]} [sha3-pwd]]
(let [routes (get-in db [:wallet :ui :send :route])
first-route (first routes)
from-address (get-in db [:wallet :current-viewing-account-address])
transaction-type (get-in db [:wallet :ui :send :tx-type])
multi-transaction-type (if (= :tx/bridge transaction-type)
constants/multi-transaction-type-bridge
constants/multi-transaction-type-send)
token (get-in db [:wallet :ui :send :token])
collectible (get-in db [:wallet :ui :send :collectible])
first-route-from-chain-id (get-in first-route [:from :chain-id])
token-id (if token
(:symbol token)
(get-in collectible [:id :token-id]))
erc20-transfer? (and token (not= token-id "ETH"))
eth-transfer? (and token (not erc20-transfer?))
token-address (cond collectible
(get-in collectible
[:id :contract-id :address])
erc20-transfer?
(get-in token [:balances-per-chain first-route-from-chain-id :address]))
to-address (get-in db [:wallet :ui :send :to-address])
transaction-paths (into []
(mapcat
(fn [route]
(let [approval-required? (:approval-required route)
data (when erc20-transfer?
(native-module/encode-transfer
(address/normalized-hex to-address)
(:amount-in route)))
base-path (utils/transaction-path
{:to-address to-address
:from-address from-address
:route route
:token-address token-address
:token-id-from (if collectible
(utils.hex/number-to-hex
token-id)
token-id)
:data data
:eth-transfer? eth-transfer?})]
(if approval-required?
[(utils/approval-path {:route route
:token-address token-address
:from-address from-address
:to-address to-address})
base-path]
[base-path]))))
routes)
request-params
[(utils/multi-transaction-command
{:from-address from-address
:to-address to-address
:from-asset token-id
:to-asset token-id
:amount-out (if eth-transfer? (:amount-out first-route) "0x0")
:multi-transaction-type multi-transaction-type})
transaction-paths
sha3-pwd]]
(log/info "multi transaction called")
{:json-rpc/call [{:method "wallet_createMultiTransaction"
:params request-params
:on-success (fn [result]
(when result
(rf/dispatch [:wallet/add-authorized-transaction result])
(rf/dispatch [:hide-bottom-sheet])))
(rf/reg-event-fx
:wallet/build-transactions-from-route
(fn [_ [{:keys [request-uuid slippage] :or {slippage constants/default-slippage}}]]
{:json-rpc/call [{:method "wallet_buildTransactionsFromRoute"
:params [{:uuid request-uuid
:slippagePercentage slippage}]
:on-error (fn [error]
(log/error "failed to build transactions from route"
{:event :wallet/build-transactions-from-route
:error error})
(rf/dispatch [:toasts/upsert
{:id :build-transactions-from-route-error
:type :negative
:text (:message error)}]))}]}))
(rf/reg-event-fx
:wallet/prepare-signatures-for-transactions
(fn [{:keys [db]} [type sha3-pwd]]
(let [transaction-for-signing (get-in db [:wallet :ui type :transaction-for-signing])]
{:fx [[:effects.wallet/sign-transaction-hashes
{:hashes (get-in transaction-for-signing [:signingDetails :hashes])
:address (get-in transaction-for-signing [:signingDetails :address])
:password (security/safe-unmask-data sha3-pwd)
:on-success (fn [signatures]
(rf/dispatch [:wallet/send-router-transactions-with-signatures type
signatures]))
:on-error (fn [error]
(log/error "failed to prepare signatures for transactions"
{:event :wallet/prepare-signatures-for-transactions
:error error})
(rf/dispatch [:toasts/upsert
{:id :prepare-signatures-for-transactions-error
:type :negative
:text (:message error)}]))}]]})))
(rf/reg-event-fx
:wallet/send-router-transactions-with-signatures
(fn [{:keys [db]} [type signatures]]
(let [transaction-for-signing (get-in db [:wallet :ui type :transaction-for-signing])
signatures-map (reduce (fn [acc {:keys [message signature]}]
(assoc acc
message
(send-utils/signature-rsv signature)))
{}
signatures)]
{:json-rpc/call [{:method "wallet_sendRouterTransactionsWithSignatures"
:params [{:uuid (get-in transaction-for-signing [:sendDetails :uuid])
:signatures signatures-map}]
:on-success (fn []
(rf/dispatch [:hide-bottom-sheet]))
:on-error (fn [error]
(log/error "failed to send transaction"
{:event :wallet/send-transaction
:error error
:params request-params})
(log/error "failed to send router transactions with signatures"
{:event :wallet/send-router-transactions-with-signatures
:error error})
(rf/dispatch [:toasts/upsert
{:id :send-transaction-error
{:id :send-router-transactions-with-signatures-error
:type :negative
:text (:message error)}]))}]})))
(rf/reg-event-fx :wallet/proceed-with-transactions-signatures
(fn [_ [signatures]]
{:json-rpc/call [{:method "wallet_proceedWithTransactionsSignatures"
:params [signatures]
:on-success (fn [result]
(when result
(rf/dispatch [:wallet/add-authorized-transaction result])
(rf/dispatch [:hide-bottom-sheet])))
:on-error (fn [error]
(log/error "failed to proceed-with-transactions-signatures"
{:event :wallet/proceed-with-transactions-signatures
:error error})
(rf/dispatch [:toasts/upsert
{:id :send-transaction-error
:type :negative
:text (:message error)}]))}]}))
(rf/reg-event-fx
:wallet/select-from-account
(fn [{db :db} [{:keys [address stack-id network-details start-flow?]}]]

View File

@ -575,28 +575,43 @@
:from-locked-amounts {}}}}})
(is (match? expected-db (:db (dispatch [event-id suggested-routes timestamp]))))))
(h/deftest-event :wallet/add-authorized-transaction
(h/deftest-event :wallet/transactions-sent-signal-received
[event-id dispatch]
(let [hashes {:chain-1 ["tx-1" "tx-2" "tx-3"]
:chain-2 ["tx-4" "tx-5"]
:chain-3 ["tx-6" "tx-7" "tx-8" "tx-9"]}
transaction-id "txid-1"
expected-result {:db {:wallet {:ui {:send {:transaction-ids ["tx-1" "tx-2" "tx-3"
"tx-4" "tx-5" "tx-6"
"tx-7" "tx-8" "tx-9"]}}
:transactions (send-utils/map-multitransaction-by-ids
transaction-id
hashes)}}
:fx [[:dispatch
[:wallet/stop-and-clean-suggested-routes]]
[:dispatch [:wallet/end-transaction-flow]]
[:dispatch-later
[{:ms 2000
:dispatch [:wallet/clean-just-completed-transaction]}]]]}]
(let [sent-transactions [{:amount "0x0"
:fromAddress "0x1"
:fromChain 1
:fromToken "SNT"
:hash "0x112233"
:toAddress "0x2"
:toChain 1
:toToken "SNT"}
{:amount "0x0"
:fromAddress "0x1"
:fromChain 1
:fromToken "SNT"
:hash "0x445566"
:toAddress "0x2"
:toChain 2
:toToken "SNT"}]
expected-result {:db {:wallet {:ui {:send {:transaction-ids
["0x112233"
"0x445566"]}
:just-completed-transaction? true}
:transactions [{:status :pending
:id "0x112233"
:chain-id 1}
{:status :pending
:id "0x445566"
:chain-id 2}]}}
:fx [[:dispatch [:wallet/end-transaction-flow]]
[:dispatch-later
[{:ms 2000
:dispatch [:wallet/stop-and-clean-suggested-routes]}]]
[:dispatch-later
[{:ms 2000
:dispatch [:wallet/clean-just-completed-transaction]}]]]}]
(is (match? expected-result
(dispatch [event-id
{:id transaction-id
:hashes hashes}])))))
(dispatch [event-id {:sentTransactions sent-transactions}])))))
(h/deftest-event :wallet/select-from-account
[event-id dispatch]

View File

@ -11,8 +11,7 @@
[status-im.contexts.wallet.send.transaction-confirmation.style :as style]
[status-im.contexts.wallet.send.utils :as send-utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.security.core :as security]))
[utils.re-frame :as rf]))
(defn- transaction-title
[{:keys [token-display-name amount account route to-network image-url transaction-type
@ -224,6 +223,7 @@
bridge-to-chain-id]))
loading-suggested-routes? (rf/sub
[:wallet/wallet-send-loading-suggested-routes?])
transaction-for-signing (rf/sub [:wallet/wallet-send-transaction-for-signing])
from-account-props {:customization-color account-color
:size 32
:emoji (:emoji account)
@ -254,17 +254,21 @@
:transaction-type transaction-type}]
(when (and (not loading-suggested-routes?) route (seq route))
[standard-auth/slide-button
{:keycard-supported? true
:size :size-48
:track-text (if (= transaction-type :tx/bridge)
(i18n/label :t/slide-to-bridge)
(i18n/label :t/slide-to-send))
:container-style {:z-index 2}
{:keycard-supported? (get-in transaction-for-signing
[:signingDetails :signOnKeycard])
:size :size-48
:track-text (if (= transaction-type :tx/bridge)
(i18n/label :t/slide-to-bridge)
(i18n/label :t/slide-to-send))
:container-style {:z-index 2}
:disabled? (not transaction-for-signing)
:customization-color account-color
:on-auth-success #(rf/dispatch
[:wallet/send-transaction
(security/safe-unmask-data %)])
:auth-button-label (i18n/label :t/confirm)}])]
:on-auth-success
(fn [data]
(rf/dispatch
[:wallet/prepare-signatures-for-transactions
:send data]))
:auth-button-label (i18n/label :t/confirm)}])]
:gradient-cover? true
:customization-color (:color account)}
[rn/view

View File

@ -303,3 +303,9 @@
(defn bridge-disabled?
[token-symbol]
(not (constants/bridge-assets token-symbol)))
(defn signature-rsv
[signature]
{:r (subs signature 0 64)
:s (subs signature 64 128)
:v (subs signature 128 130)})

View File

@ -1,14 +1,11 @@
(ns status-im.contexts.wallet.swap.events
(:require [native-module.core :as native-module]
[re-frame.core :as rf]
(:require [re-frame.core :as rf]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.send.utils :as send-utils]
[status-im.contexts.wallet.sheets.network-selection.view :as network-selection]
[status-im.contexts.wallet.swap.utils :as swap-utils]
[taoensso.timbre :as log]
[utils.address :as address]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
[utils.money :as money]
[utils.number :as number]))
@ -142,9 +139,9 @@
:disabledFromChainIDs disabled-from-chain-ids
:disabledToChainIDs disabled-to-chain-ids
:gasFeeMode gas-rates
:fromLockedAmount from-locked-amount}
amount-in (assoc :amountIn amount-in-hex)
amount-out (assoc :amountOut amount-out-hex))]]
:fromLockedAmount from-locked-amount
:amountOut (or amount-out-hex "0x0")}
amount-in (assoc :amountIn amount-in-hex))]]
(when-let [amount (or amount-in amount-out)]
{:db (update-in db
@ -261,150 +258,21 @@
(fn [{:keys [db]}]
{:db (update-in db [:wallet :ui] dissoc :swap)}))
(rf/reg-event-fx :wallet/swap-transaction
(fn [{:keys [db]} [sha3-pwd]]
(let [wallet-address (get-in db
[:wallet
:current-viewing-account-address])
{:keys [asset-to-pay asset-to-receive
swap-proposal network amount
approval-transaction-id
max-slippage]} (get-in db [:wallet :ui :swap])
transactions (get-in db [:wallet :transactions])
approval-transaction (when approval-transaction-id
(get transactions approval-transaction-id))
already-approved? (and approval-transaction
(= (:status approval-transaction)
:confirmed))
approval-required? (and (:approval-required swap-proposal)
(not already-approved?))
multi-transaction-type constants/multi-transaction-type-swap
swap-chain-id (:chain-id network)
token-id-from (:symbol asset-to-pay)
token-id-to (:symbol asset-to-receive)
erc20-transfer? (and asset-to-pay (not= token-id-from "ETH"))
eth-transfer? (and asset-to-pay (not erc20-transfer?))
token-address (when erc20-transfer?
(get-in asset-to-pay
[:balances-per-chain swap-chain-id
:address]))
data (when erc20-transfer?
(native-module/encode-transfer
(address/normalized-hex wallet-address)
(:amount-in swap-proposal)))
transaction-paths (if approval-required?
[(utils/approval-path
{:route swap-proposal
:token-address token-address
:from-address wallet-address
:to-address wallet-address})]
[(utils/transaction-path
{:to-address wallet-address
:from-address wallet-address
:route swap-proposal
:token-address token-address
:token-id-from token-id-from
:token-id-to token-id-to
:data data
:slippage-percentage max-slippage
:eth-transfer? eth-transfer?})])
request-params [(utils/multi-transaction-command
{:from-address wallet-address
:to-address wallet-address
:from-asset token-id-from
:to-asset (if approval-required?
token-id-from
token-id-to)
:amount-out (if eth-transfer?
(:amount-out swap-proposal)
"0x0")
:multi-transaction-type
multi-transaction-type})
transaction-paths
sha3-pwd]]
(log/info "multi transaction called")
{:json-rpc/call [{:method "wallet_createMultiTransaction"
:params request-params
:on-success (fn [result]
(when result
(let [receive-token-decimals (:decimals asset-to-receive)
amount-out (:amount-out swap-proposal)
receive-amount
(when amount-out
(-> amount-out
(number/hex->whole receive-token-decimals)
(money/to-fixed receive-token-decimals)))]
(rf/dispatch [:centralized-metrics/track
(if approval-required?
:metric/swap-approval-execution-start
:metric/swap-transaction-execution-start)
(cond-> {:network swap-chain-id
:pay_token token-id-from}
(not approval-required?)
(assoc :receive_token token-id-to))])
(rf/dispatch [:wallet.swap/add-authorized-transaction
(cond-> {:transaction result
:approval-transaction?
approval-required?}
(not approval-required?)
(assoc :swap-data
{:pay-token-symbol token-id-from
:pay-amount amount
:receive-token-symbol token-id-to
:receive-amount receive-amount
:swap-chain-id swap-chain-id}))])
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:dismiss-modal
(if approval-required?
:screen/wallet.swap-set-spending-cap
:screen/wallet.swap-confirmation)])
(when-not approval-required?
(rf/dispatch [:wallet/end-swap-flow])
(debounce/debounce-and-dispatch
[:toasts/upsert
{:id :swap-transaction-pending
:icon :i/info
:type :neutral
:text (i18n/label :t/swapping-to
{:pay-amount amount
:pay-token-symbol token-id-from
:receive-token-symbol token-id-to
:receive-amount receive-amount})}]
500)))))
:on-error (fn [error]
(rf/dispatch [:centralized-metrics/track
(if approval-required?
:metric/swap-approval-execution-failed
:metric/swap-transaction-execution-failed)
(cond-> {:network swap-chain-id
:error error
:pay_token token-id-from}
(not approval-required?)
(assoc :receive_token token-id-to))])
(log/error "failed swap transaction"
{:event :wallet/swap-transaction
:error error
:params request-params})
(rf/dispatch [:toasts/upsert
{:id :swap-transaction-error
:type :negative
:text (:message error)}]))}]})))
(rf/reg-event-fx :wallet.swap/add-authorized-transaction
(fn [{:keys [db]} [{:keys [transaction swap-data approval-transaction?]}]]
(let [transactions (get-in db [:wallet :transactions] {})
transaction-batch-id (:id transaction)
transaction-hashes (:hashes transaction)
transaction-ids (flatten (vals transaction-hashes))
(fn [{:keys [db]} [{:keys [sent-transactions swap-data approval-transaction?]}]]
(let [wallet-transactions (get-in db [:wallet :transactions] {})
transactions (utils/transactions->hash-to-transaction-map sent-transactions)
transaction-ids (->> transactions
vals
(map :hash))
transaction-id (first transaction-ids)
transaction-details (cond-> (send-utils/map-multitransaction-by-ids transaction-batch-id
transaction-hashes)
transaction-details (cond-> transactions
:always (assoc-in [transaction-id :tx-type] :swap)
swap-data (assoc-in [transaction-id :swap-data] swap-data))
swap-transaction-ids (get-in db [:wallet :swap-transaction-ids])]
{:db (cond-> db
:always (assoc-in [:wallet :transactions]
(merge transactions transaction-details))
(merge wallet-transactions transaction-details))
:always (assoc-in [:wallet :ui :swap :transaction-ids] transaction-ids)
approval-transaction? (assoc-in [:wallet :ui :swap :approval-transaction-id]
transaction-id)
@ -454,7 +322,8 @@
(not transaction-confirmed?)
(assoc :db (update-in db [:wallet :ui :swap] dissoc :approval-transaction-id)))))))
(rf/reg-event-fx :wallet.swap/swap-transaction-update
(rf/reg-event-fx
:wallet.swap/swap-transaction-update
(fn [{:keys [db]} [{:keys [tx-hash status]}]]
(let [{:keys [pay-amount pay-token-symbol
receive-amount receive-token-symbol
@ -485,7 +354,8 @@
:receive-amount receive-amount})
(i18n/label :t/swap-failed))}]]]}))))
(rf/reg-event-fx :wallet.swap/flip-assets
(rf/reg-event-fx
:wallet.swap/flip-assets
(fn [{:keys [db]}]
(let [{:keys [asset-to-pay asset-to-receive
swap-proposal amount network]} (get-in db [:wallet :ui :swap])
@ -519,11 +389,137 @@
:previous_token (:symbol asset-to-receive)
:new_token (:symbol asset-to-pay)}]]]})))
(rf/reg-event-fx :wallet/end-swap-flow
;; TODO(alwx):
(rf/reg-event-fx
:wallet.swap/review-swap
(fn [{:keys [db]}]
(let [launch-screen (get-in db [:wallet :ui :swap :launch-screen])
address (get-in db [:wallet :current-viewing-account-address])]
{:fx [(when (= launch-screen :wallet-stack)
[:dispatch [:wallet/navigate-to-account-within-stack address]])
(let [last-request-uuid (get-in db [:wallet :ui :swap :last-request-uuid])
max-slippage (get-in db [:wallet :ui :swap :max-slippage])]
{:db (-> db
(update-in [:wallet :ui :send] dissoc :transaction-for-signing))
:fx [[:dispatch
[:wallet/build-transactions-from-route
{:request-uuid last-request-uuid
:slippage max-slippage}]]
[:dispatch
[:navigate-to-within-stack
[:screen/wallet.swap-confirmation
:screen/wallet.setup-swap]]]]})))
(defn transaction-approval-required?
[transactions {:keys [swap-proposal approval-transaction-id]}]
(let [approval-transaction (when approval-transaction-id
(get transactions approval-transaction-id))
already-approved? (and approval-transaction
(= (:status approval-transaction)
:confirmed))]
(and (:approval-required swap-proposal)
(not already-approved?))))
(rf/reg-event-fx
:wallet.swap/transaction-success
(fn [{:keys [db]} [sent-transactions]]
(let [transactions (get-in db [:wallet :transactions])
{:keys [swap-proposal
asset-to-pay
asset-to-receive
network
amount]
:as swap} (get-in db [:wallet :ui :swap])
swap-chain-id (:chain-id network)
token-id-from (:symbol asset-to-pay)
token-id-to (:symbol asset-to-receive)
receive-token-decimals (:decimals asset-to-receive)
amount-out (:amount-out swap-proposal)
receive-amount (when amount-out
(-> amount-out
(number/hex->whole receive-token-decimals)
(money/to-fixed receive-token-decimals)))
approval-required? (transaction-approval-required? transactions swap)]
{:fx [[:dispatch
[:centralized-metrics/track
(if approval-required?
:metric/swap-approval-execution-start
:metric/swap-transaction-execution-start)
(cond-> {:network swap-chain-id
:pay_token token-id-from}
(not approval-required?)
(assoc :receive_token token-id-to))]]
[:dispatch
[:wallet.swap/add-authorized-transaction
(cond-> {:sent-transactions sent-transactions
:approval-transaction? approval-required?}
(not approval-required?)
(assoc :swap-data
{:pay-token-symbol token-id-from
:pay-amount amount
:receive-token-symbol token-id-to
:receive-amount receive-amount
:swap-chain-id swap-chain-id}))]]
[:dispatch [:wallet.swap/end-transaction-flow]]
(when-not approval-required?
[:dispatch [:wallet.swap/end-flow]])
(when-not approval-required?
[:dispatch-later
{:ms 500
:dispatch [:toasts/upsert
{:id :swap-transaction-pending
:icon :i/info
:type :neutral
:text (i18n/label :t/swapping-to
{:pay-amount amount
:pay-token-symbol token-id-from
:receive-token-symbol token-id-to
:receive-amount receive-amount})}]}])]})))
(rf/reg-event-fx
:wallet.swap/transaction-failure
(fn [{:keys [db]} [{:keys [details] :as error}]]
(let [transactions (get-in db [:wallet :transactions])
{:keys [asset-to-pay
asset-to-receive
network]
:as swap} (get-in db [:wallet :ui :swap])
swap-chain-id (:chain-id network)
token-id-from (:symbol asset-to-pay)
token-id-to (:symbol asset-to-receive)
approval-required? (transaction-approval-required? transactions swap)]
{:fx [[:centralized-metrics/track
(if approval-required?
:metric/swap-approval-execution-failed
:metric/swap-transaction-execution-failed)
(cond-> {:network swap-chain-id
:error error
:pay_token token-id-from}
(not approval-required?)
(assoc :receive_token token-id-to))]
[:dispatch [:wallet.swap/end-transaction-flow]]
[:dispatch
[:toasts/upsert
{:id :send-transaction-error
:type :negative
:text (or details "An error occured")}]]]})))
(rf/reg-event-fx
:wallet.swap/clean-up-transaction-flow
(fn [{:keys [db]}]
(let [transactions (get-in db [:wallet :transactions])
swap (get-in db [:wallet :ui :swap])
approval-required? (transaction-approval-required? transactions swap)]
{:db (update-in db [:wallet :ui] dissoc :swap)
:fx [[:dispatch
[:dismiss-modal
(if approval-required?
:screen/wallet.swap-set-spending-cap
:screen/wallet.swap-confirmation)]]]})))
(rf/reg-event-fx
:wallet.swap/end-transaction-flow
(fn [{:keys [db]}]
(let [address (get-in db [:wallet :current-viewing-account-address])]
{:fx [[:dispatch [:wallet/navigate-to-account-within-stack address]]
[:dispatch [:wallet/fetch-activities-for-current-account]]
[:dispatch [:wallet/select-account-tab :activity]]]})))
[:dispatch [:wallet/select-account-tab :activity]]
[:dispatch-later
[{:ms 20
:dispatch [:wallet.swap/clean-up-transaction-flow]}]]]})))

View File

@ -12,8 +12,7 @@
[status-im.contexts.wallet.swap.set-spending-cap.style :as style]
[utils.address :as address-utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.security.core :as security]))
[utils.re-frame :as rf]))
(defn- swap-title
[]
@ -221,9 +220,8 @@
(let [loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
swap-proposal (rf/sub [:wallet/swap-proposal-without-fees])
account (rf/sub [:wallet/current-viewing-account])
on-auth-success (rn/use-callback #(rf/dispatch
[:wallet/swap-transaction
(security/safe-unmask-data %)]))]
on-auth-success (rn/use-callback
#(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap %]))]
[standard-auth/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-sign)

View File

@ -359,9 +359,7 @@
(not pay-input-error?))
on-review-swap-press (rn/use-callback
(fn []
(rf/dispatch [:navigate-to-within-stack
[:screen/wallet.swap-confirmation
:screen/wallet.setup-swap]])))
(rf/dispatch [:wallet.swap/review-swap])))
on-press (rn/use-callback
(fn [c]
(let

View File

@ -12,8 +12,7 @@
[status-im.contexts.wallet.swap.swap-confirmation.style :as style]
[utils.address :as address-utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.security.core :as security]))
[utils.re-frame :as rf]))
(defn- on-close-action
[]
@ -165,22 +164,23 @@
(defn- slide-button
[]
(let [loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
swap-proposal (rf/sub [:wallet/swap-proposal-without-fees])
account (rf/sub [:wallet/current-viewing-account])
account-color (:color account)
on-auth-success (rn/use-callback (fn [data]
(rf/dispatch [:wallet/stop-get-swap-proposal])
(rf/dispatch [:wallet/swap-transaction
(security/safe-unmask-data data)])))]
(let [loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
transaction-for-signing (rf/sub [:wallet/swap-transaction-for-signing])
swap-proposal (rf/sub [:wallet/swap-proposal-without-fees])
account (rf/sub [:wallet/current-viewing-account])
account-color (:color account)]
[standard-auth/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-swap)
:container-style {:z-index 2}
:customization-color account-color
:disabled? (or loading-swap-proposal? (not swap-proposal))
:disabled? (or loading-swap-proposal?
(not swap-proposal)
(not transaction-for-signing))
:auth-button-label (i18n/label :t/confirm)
:on-auth-success on-auth-success}]))
:on-auth-success (fn [data]
(rf/dispatch [:wallet/stop-get-swap-proposal])
(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap data]))}]))
(defn footer
[]

View File

@ -1,63 +1,8 @@
(ns status-im.contexts.wallet.wallet-connect.utils.rpc
(:require [oops.core :as oops]
[promesa.core :as promesa]
(:require [promesa.core :as promesa]
[status-im.common.json-rpc.events :as rpc-events]
[status-im.constants :as constants]
[utils.hex :as hex]
[utils.transforms :as transforms]))
(defn wallet-build-transaction
[chain-id tx]
(promesa/let [res (rpc-events/call-async :wallet_buildTransaction true chain-id tx)]
{: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"
true
chain-id
constants/transaction-pending-type-wallet-connect-transfer
(transforms/js-stringify tx-args 0)
signature))
(defn wallet-sign-message
[message address password]
(-> (rpc-events/call-async "wallet_signMessage"
true
message
address
password)
(promesa/then hex/normalize-hex)))
(defn wallet-hash-message-eip-191
[message]
(rpc-events/call-async "wallet_hashMessageEIP191" true message))
(defn wallet-safe-sign-typed-data
[data address password chain-id legacy?]
(rpc-events/call-async "wallet_safeSignTypedDataForDApps"
true
data
address
password
chain-id
legacy?))
(defn wallet-get-suggested-fees
[chain-id]
(-> (rpc-events/call-async "wallet_getSuggestedFees" true chain-id)
(promesa/then transforms/js->clj)))
(defn wallet-disconnect-persisted-session
[topic]
(rpc-events/call-async "wallet_disconnectWalletConnectSession" true topic))

View File

@ -2,9 +2,9 @@
(:require
[native-module.core :as native-module]
[promesa.core :as promesa]
[status-im.contexts.wallet.rpc :as wallet-rpc]
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
data-store]
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
[utils.hex :as hex]
[utils.transforms :as transforms]))
@ -19,6 +19,6 @@
(defn personal-sign
[password address data]
(-> (rpc/wallet-hash-message-eip-191 data)
(promesa/then #(rpc/wallet-sign-message % address password))
(-> (wallet-rpc/hash-message-eip-191 data)
(promesa/then #(wallet-rpc/sign-message % address password))
(promesa/then hex/prefix-hex)))

View File

@ -4,9 +4,10 @@
[native-module.core :as native-module]
[promesa.core :as promesa]
[status-im.constants :as constants]
[status-im.contexts.wallet.rpc :as wallet-rpc]
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
data-store]
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
[status-im.contexts.wallet.wallet-connect.utils.rpc :as wallet-connect-rpc]
[utils.money :as money]
[utils.transforms :as transforms]))
@ -119,16 +120,17 @@
"Formats and builds the incoming transaction, adding the missing properties and returning the final
transaction, along with the transaction hash and the suggested fees"
[tx chain-id tx-priority]
(promesa/let [suggested-fees (rpc/wallet-get-suggested-fees chain-id)
(promesa/let [suggested-fees (wallet-rpc/get-suggested-fees chain-id)
{:keys [tx-args message-to-sign]} (->>
(prepare-transaction-fees tx
tx-priority
suggested-fees)
prepare-transaction-for-rpc
(rpc/wallet-build-transaction chain-id))
estimated-time (rpc/wallet-get-transaction-estimated-time
chain-id
(:maxPriorityFeePerGas suggested-fees))]
(wallet-rpc/build-transaction
chain-id))
estimated-time (wallet-connect-rpc/wallet-get-transaction-estimated-time
chain-id
(:maxPriorityFeePerGas suggested-fees))]
{:tx-args tx-args
:tx-hash message-to-sign
:suggested-fees suggested-fees
@ -137,15 +139,15 @@
(defn sign-transaction
[password address tx-hash tx-args chain-id]
(promesa/let
[signature (rpc/wallet-sign-message tx-hash address password)
raw-tx (rpc/wallet-build-raw-transaction chain-id tx-args signature)]
[signature (wallet-rpc/sign-message tx-hash address password)
raw-tx (wallet-rpc/build-raw-transaction chain-id tx-args signature)]
raw-tx))
(defn send-transaction
[password address tx-hash tx-args chain-id]
(promesa/let
[signature (rpc/wallet-sign-message tx-hash address password)
tx (rpc/wallet-send-transaction-with-signature chain-id
[signature (wallet-rpc/sign-message tx-hash address password)
tx (wallet-rpc/send-transaction-with-signature chain-id
tx-args
signature)]
tx))

View File

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

View File

@ -141,6 +141,11 @@
:<- [:wallet/swap]
:-> :loading-swap-proposal?)
(rf/reg-sub
:wallet/swap-transaction-for-signing
:<- [:wallet/swap]
:-> :transaction-for-signing)
(rf/reg-sub
:wallet/swap-proposal-amount-out
:<- [:wallet/swap-proposal]

View File

@ -210,6 +210,11 @@
:<- [:wallet/wallet-send]
:-> :loading-suggested-routes?)
(rf/reg-sub
:wallet/wallet-send-transaction-for-signing
:<- [:wallet/wallet-send]
:-> :transaction-for-signing)
(rf/reg-sub
:wallet/wallet-send-suggested-routes
:<- [:wallet/wallet-send]