Wallet: loading networks (#18491)

Wallet: loading networks
This commit is contained in:
Omar Basem 2024-01-17 13:57:02 +04:00 committed by GitHub
parent 02b8d2140a
commit 19aa78cc81
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 127 additions and 149 deletions

View File

@ -219,7 +219,8 @@
(def regx-community-universal-link #"((^https?://status.app/)|(^status-app://))c/([\x00-\x7F]+)$") (def regx-community-universal-link #"((^https?://status.app/)|(^status-app://))c/([\x00-\x7F]+)$")
(def regx-deep-link #"((^ethereum:.*)|(^status-app://[\x00-\x7F]+$))") (def regx-deep-link #"((^ethereum:.*)|(^status-app://[\x00-\x7F]+$))")
(def regx-ens #"^(?=.{5,255}$)([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$") (def regx-ens #"^(?=.{5,255}$)([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$")
(def regx-address #"^0x[a-fA-F0-9]{40}$") (def regx-multichain-address #"^(?:(?:eth:|arb1:|opt:)(?=:|))*0x[0-9a-fA-F]{40}$")
(def regx-address-contains #"(?i)0x[a-fA-F0-9]{40}") (def regx-address-contains #"(?i)0x[a-fA-F0-9]{40}")
(def regx-starts-with-uuid #"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}") (def regx-starts-with-uuid #"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")
(def regx-full-or-partial-address #"^0x[a-fA-F0-9]{1,40}$") (def regx-full-or-partial-address #"^0x[a-fA-F0-9]{1,40}$")

View File

@ -8,13 +8,16 @@
[status-im.config :as config] [status-im.config :as config]
[status-im.contexts.profile.utils :as profile.utils] [status-im.contexts.profile.utils :as profile.utils]
[status-im.contexts.wallet.account.tabs.about.style :as style] [status-im.contexts.wallet.account.tabs.about.style :as style]
[status-im.contexts.wallet.common.utils :as utils]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn about-options (defn about-options
[] []
(let [{:keys [address] :as account} (rf/sub [:wallet/current-viewing-account]) (let [{:keys [address] :as account} (rf/sub [:wallet/current-viewing-account])
share-title (str (:name account) " " (i18n/label :t/address))] networks (rf/sub [:wallet/network-preference-details])
share-title (str (:name account) " " (i18n/label :t/address))
multichain-address (utils/get-multichain-address networks address)]
[quo/action-drawer [quo/action-drawer
[[{:icon :i/link [[{:icon :i/link
:accessibility-label :view-on-eth :accessibility-label :view-on-eth
@ -44,7 +47,7 @@
:accessibility-label :copy-address :accessibility-label :copy-address
:label (i18n/label :t/copy-address) :label (i18n/label :t/copy-address)
:on-press (fn [] :on-press (fn []
(clipboard/set-string address) (clipboard/set-string multichain-address)
(rf/dispatch [:toasts/upsert (rf/dispatch [:toasts/upsert
{:type :positive {:type :positive
:text (i18n/label :t/address-copied)}]))} :text (i18n/label :t/address-copied)}]))}
@ -59,15 +62,17 @@
(js/setTimeout (js/setTimeout
#(share/open #(share/open
(if platform/ios? (if platform/ios?
{:activityItemSources [{:placeholderItem {:type "text" {:activityItemSources [{:placeholderItem {:type "text"
:content address} :content
:item {:default {:type "text" multichain-address}
:content :item {:default
address}} {:type "text"
:content
multichain-address}}
:linkMetadata {:title share-title}}]} :linkMetadata {:title share-title}}]}
{:title share-title {:title share-title
:subject share-title :subject share-title
:message address})) :message multichain-address}))
600))}]]])) 600))}]]]))
(defn view (defn view

View File

@ -10,6 +10,7 @@
[react-native.platform :as platform] [react-native.platform :as platform]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im.contexts.wallet.common.sheets.account-options.style :as style] [status-im.contexts.wallet.common.sheets.account-options.style :as style]
[status-im.contexts.wallet.common.utils :as utils]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
@ -31,7 +32,10 @@
(defn- options (defn- options
[{:keys [theme show-account-selector? options-height]}] [{:keys [theme show-account-selector? options-height]}]
(let [{:keys [name color emoji address watch-only?]} (rf/sub [:wallet/current-viewing-account]) (let [{:keys [name color emoji address watch-only?]} (rf/sub [:wallet/current-viewing-account])
network-preference-details (rf/sub [:wallet/network-preference-details])] network-preference-details (rf/sub [:wallet/network-preference-details])
multichain-address (utils/get-multichain-address
network-preference-details
address)]
[rn/view [rn/view
{:on-layout #(reset! options-height (oops/oget % "nativeEvent.layout.height")) {:on-layout #(reset! options-height (oops/oget % "nativeEvent.layout.height"))
:style (when show-account-selector? style/options-container)} :style (when show-account-selector? style/options-container)}
@ -72,7 +76,7 @@
(rf/dispatch [:toasts/upsert (rf/dispatch [:toasts/upsert
{:type :positive {:type :positive
:text (i18n/label :t/address-copied)}]) :text (i18n/label :t/address-copied)}])
(clipboard/set-string address))} (clipboard/set-string multichain-address))}
{:icon :i/share {:icon :i/share
:accessibility-label :share-account :accessibility-label :share-account
:label (i18n/label :t/share-account)} :label (i18n/label :t/share-account)}

View File

@ -202,3 +202,15 @@
:customization-color color :customization-color color
:values {:crypto-value crypto-value :values {:crypto-value crypto-value
:fiat-value fiat-value}})) :fiat-value fiat-value}}))
(defn get-multichain-address
[networks address]
(str (->> networks
(map #(str (:short-name %) ":"))
(clojure.string/join ""))
address))
(defn split-prefix-and-address
[input-string]
(let [split-result (string/split input-string #"0x")]
[(first split-result) (str "0x" (second split-result))]))

View File

@ -2,4 +2,4 @@
(:require [status-im.constants :as constants])) (:require [status-im.constants :as constants]))
(defn ens-name? [s] (re-find constants/regx-ens s)) (defn ens-name? [s] (re-find constants/regx-ens s))
(defn eth-address? [s] (re-find constants/regx-address s)) (defn eth-address? [s] (re-find constants/regx-multichain-address s))

View File

@ -2,11 +2,10 @@
(:require (:require
[camel-snake-kebab.core :as csk] [camel-snake-kebab.core :as csk]
[camel-snake-kebab.extras :as cske] [camel-snake-kebab.extras :as cske]
[native-module.core :as native-module]
[status-im.constants :as constants] [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.send.utils :as send-utils]
[taoensso.timbre :as log] [taoensso.timbre :as log]
[utils.address :as address]
[utils.money :as money] [utils.money :as money]
[utils.number] [utils.number]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
@ -42,23 +41,32 @@
(update-in [:wallet :ui :send] dissoc :route) (update-in [:wallet :ui :send] dissoc :route)
(update-in [:wallet :ui :send] dissoc :loading-suggested-routes?))})) (update-in [:wallet :ui :send] dissoc :loading-suggested-routes?))}))
(rf/reg-event-fx :wallet/select-send-account-address
(fn [{:keys [db]} [{:keys [address stack-id]}]]
{:db (-> db
(assoc-in [:wallet :ui :send :send-account-address] address)
(update-in [:wallet :ui :send] dissoc :to-address))
:fx [[:navigate-to-within-stack [:wallet-select-asset stack-id]]]}))
(rf/reg-event-fx :wallet/clean-send-address (rf/reg-event-fx :wallet/clean-send-address
(fn [{:keys [db]}] (fn [{:keys [db]}]
{:db (update-in db [:wallet :ui :send] dissoc :recipient :to-address)})) {:db (update-in db [:wallet :ui :send] dissoc :recipient :to-address)}))
(rf/reg-event-fx :wallet/select-send-address (rf/reg-event-fx :wallet/select-send-address
(fn [{:keys [db]} [{:keys [address token recipient stack-id]}]] (fn [{:keys [db]} [{:keys [address token recipient stack-id]}]]
{:db (-> db (let [[prefix to-address] (utils/split-prefix-and-address address)]
(assoc-in [:wallet :ui :send :recipient] (or recipient address)) {:db (-> db
(assoc-in [:wallet :ui :send :to-address] address)) (assoc-in [:wallet :ui :send :recipient] (or recipient address))
:fx [[:navigate-to-within-stack (assoc-in [:wallet :ui :send :to-address] to-address)
(if token [:wallet-send-input-amount stack-id] [:wallet-select-asset stack-id])]]})) (assoc-in [:wallet :ui :send :address-prefix] prefix))
:fx [[:navigate-to-within-stack
(if token
[:wallet-send-input-amount stack-id]
[:wallet-select-asset stack-id])]]})))
(rf/reg-event-fx :wallet/send-select-token (rf/reg-event-fx :wallet/send-select-token
(fn [{:keys [db]} [{:keys [token stack-id]}]] (fn [{:keys [db]} [{:keys [token stack-id]}]]
{:db (-> db {:db (assoc-in db [:wallet :ui :send :token] token)
(update-in [:wallet :ui :send] dissoc :collectible)
(assoc-in [:wallet :ui :send :token] token))
:fx [[:navigate-to-within-stack [:wallet-send-input-amount stack-id]]]})) :fx [[:navigate-to-within-stack [:wallet-send-input-amount stack-id]]]}))
(rf/reg-event-fx :wallet/send-select-token-drawer (rf/reg-event-fx :wallet/send-select-token-drawer
@ -69,15 +77,6 @@
(fn [{:keys [db]}] (fn [{:keys [db]}]
{:db (assoc-in db [:wallet :ui :send :token] nil)})) {:db (assoc-in db [:wallet :ui :send :token] nil)}))
(rf/reg-event-fx :wallet/send-select-collectible
(fn [{:keys [db]} [{:keys [collectible stack-id]}]]
{:db (-> db
(update-in [:wallet :ui :send] dissoc :token)
(assoc-in [:wallet :ui :send :collectible] collectible)
(assoc-in [:wallet :ui :send :amount] 1))
:fx [[:dispatch [:wallet/get-suggested-routes 1]]
[:navigate-to-within-stack [:wallet-transaction-confirmation stack-id]]]}))
(rf/reg-event-fx :wallet/send-select-amount (rf/reg-event-fx :wallet/send-select-amount
(fn [{:keys [db]} [{:keys [amount stack-id]}]] (fn [{:keys [db]} [{:keys [amount stack-id]}]]
{:db (assoc-in db [:wallet :ui :send :amount] amount) {:db (assoc-in db [:wallet :ui :send :amount] amount)
@ -87,25 +86,18 @@
(fn [{:keys [db now]} [amount]] (fn [{:keys [db now]} [amount]]
(let [wallet-address (get-in db [:wallet :current-viewing-account-address]) (let [wallet-address (get-in db [:wallet :current-viewing-account-address])
token (get-in db [:wallet :ui :send :token]) token (get-in db [:wallet :ui :send :token])
collectible (get-in db [:wallet :ui :send :collectible]) account-address (get-in db [:wallet :ui :send :send-account-address])
to-address (get-in db [:wallet :ui :send :to-address]) to-address (or account-address (get-in db [:wallet :ui :send :to-address]))
token-decimal (when token (:decimals token)) token-decimal (:decimals token)
token-id (if token token-id (:symbol token)
(:symbol token) network-preferences []
(str (get-in collectible [:id :contract-id :address])
":"
(get-in collectible [:id :token-id])))
network-preferences (if token [] [(get-in collectible [:id :contract-id :chain-id])])
gas-rates constants/gas-rate-medium gas-rates constants/gas-rate-medium
amount-in (send-utils/amount-in-hex amount (if token token-decimal 0)) amount-in (send-utils/amount-in-hex amount token-decimal)
from-address wallet-address from-address wallet-address
disabled-from-chain-ids [] disabled-from-chain-ids []
disabled-to-chain-ids [] disabled-to-chain-ids []
from-locked-amount {} from-locked-amount {}
transaction-type (if token request-params [constants/send-type-transfer
constants/send-type-transfer
constants/send-type-erc-721-transfer)
request-params [transaction-type
from-address from-address
to-address to-address
amount-in amount-in
@ -142,46 +134,21 @@
:fx [[:dispatch [:navigate-to :wallet-transaction-progress]]]}))) :fx [[:dispatch [:navigate-to :wallet-transaction-progress]]]})))
(defn- transaction-bridge (defn- transaction-bridge
[{:keys [from-address from-chain-id to-address token-id token-address route data eth-transfer?]}] [{:keys [from-address to-address route]}]
(let [{:keys [bridge-name amount-out gas-amount (let [{:keys [from bridge-name amount-out gas-amount gas-fees]} route
gas-fees]} route {:keys [gas-price max-fee-per-gas-medium max-priority-fee-per-gas]} gas-fees]
eip-1559-enabled? (:eip-1559-enabled gas-fees) [{:BridgeName bridge-name
{:keys [gas-price max-fee-per-gas-medium :ChainID (:chain-id from)
max-priority-fee-per-gas]} gas-fees :TransferTx {:From from-address
transfer-tx (cond-> {:From from-address :To to-address
:To (or token-address to-address) :Gas (money/to-hex gas-amount)
:Gas (money/to-hex gas-amount) :GasPrice (money/to-hex (money/->wei :gwei gas-price))
:Value (when eth-transfer? amount-out) :Value amount-out
:Nonce nil :Nonce nil
:Input "" :MaxFeePerGas (money/to-hex (money/->wei :gwei max-fee-per-gas-medium))
:Data (or data "0x")} :MaxPriorityFeePerGas (money/to-hex (money/->wei :gwei max-priority-fee-per-gas))
eip-1559-enabled? (assoc :TxType "0x02" :Input ""
:MaxFeePerGas :Data "0x"}}]))
(money/to-hex
(money/->wei
:gwei
max-fee-per-gas-medium))
:MaxPriorityFeePerGas
(money/to-hex
(money/->wei
:gwei
max-priority-fee-per-gas)))
(not eip-1559-enabled?) (assoc :TxType "0x00"
:GasPrice (money/to-hex
(money/->wei
:gwei
gas-price))))]
[(cond-> {:BridgeName bridge-name
:ChainID from-chain-id}
(= bridge-name constants/bridge-name-erc-721-transfer)
(assoc :ERC721TransferTx
(assoc transfer-tx
:Recipient to-address
:TokenID token-id))
(= bridge-name constants/bridge-name-transfer)
(assoc :TransferTx transfer-tx))]))
(defn- multi-transaction-command (defn- multi-transaction-command
[{:keys [from-address to-address from-asset to-asset amount-out transfer-type] [{:keys [from-address to-address from-asset to-asset amount-out transfer-type]
@ -195,53 +162,27 @@
(rf/reg-event-fx :wallet/send-transaction (rf/reg-event-fx :wallet/send-transaction
(fn [{:keys [db]} [sha3-pwd]] (fn [{:keys [db]} [sha3-pwd]]
(let [route (get-in db [:wallet :ui :send :route]) (let [route (get-in db [:wallet :ui :send :route])
from-address (get-in db [:wallet :current-viewing-account-address]) from-address (get-in db [:wallet :current-viewing-account-address])
token (get-in db [:wallet :ui :send :token]) to-address (get-in db [:wallet :ui :send :to-address])
collectible (get-in db [:wallet :ui :send :collectible]) token (get-in db [:wallet :ui :send :token])
from-chain-id (get-in route [:from :chain-id]) token-id (:symbol token)
token-id (if token request-params [(multi-transaction-command {:from-address from-address
(:symbol token) :to-address to-address
(get-in collectible [:id :token-id])) :from-asset token-id
erc20-transfer? (and token (not= token-id "ETH")) :to-asset token-id
eth-transfer? (and token (not erc20-transfer?)) :amount-out (:amount-out route)})
token-address (cond collectible (transaction-bridge {:to-address to-address
(get-in collectible :from-address from-address
[:id :contract-id :address]) :route route})
erc20-transfer? sha3-pwd]]
(get-in token [:balances-per-chain from-chain-id :address]))
to-address (get-in db [:wallet :ui :send :to-address])
data (when erc20-transfer?
(native-module/encode-transfer (address/normalized-hex to-address)
(:amount-out route)))
request-params [(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 route) "0x0")})
(transaction-bridge {:to-address to-address
:from-address from-address
:route route
:from-chain-id from-chain-id
:token-address token-address
:token-id (when collectible
(money/to-hex (js/parseInt token-id)))
:data data
:eth-transfer? eth-transfer?})
sha3-pwd]]
{:json-rpc/call [{:method "wallet_createMultiTransaction" {:json-rpc/call [{:method "wallet_createMultiTransaction"
:params request-params :params request-params
:on-success (fn [result] :on-success (fn [result]
(rf/dispatch [:hide-bottom-sheet]) (rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:wallet/add-authorized-transaction result]) (rf/dispatch [:wallet/add-authorized-transaction result]))
(rf/dispatch [:wallet/clean-scanned-address])
(rf/dispatch [:wallet/clean-local-suggestions])
(rf/dispatch [:wallet/clean-send-address])
(rf/dispatch [:wallet/select-address-tab nil]))
:on-error (fn [error] :on-error (fn [error]
(log/error "failed to send transaction" (log/error "failed to send transaction"
{:event :wallet/send-transaction {:event :wallet/send-transaction
:error error :error error
:params request-params}))}]}))) :params request-params}))}]})))

View File

@ -53,6 +53,13 @@
(normalize-input current v) (normalize-input current v)
current)) current))
(defn- find-affordable-networks
[{:keys [balances-per-chain]} input-value]
(->> balances-per-chain
(filter (fn [[_ {:keys [balance]}]]
(>= (js/parseFloat balance) input-value)))
(map first)))
(defn- f-view-internal (defn- f-view-internal
[{:keys [rate limit]}] [{:keys [rate limit]}]
(let [bottom (safe-area/get-bottom) (let [bottom (safe-area/get-bottom)
@ -142,9 +149,10 @@
:on-change-text (fn [text] :on-change-text (fn [text]
(handle-on-change text))}] (handle-on-change text))}]
[routes/view [routes/view
{:amount amount {:amount amount
:routes suggested-routes :routes suggested-routes
:networks (:networks token)}] :loading-networks (find-affordable-networks token @input-value)
:networks (:networks token)}]
[quo/bottom-actions [quo/bottom-actions
{:actions :1-action {:actions :1-action
:button-one-label (i18n/label :t/confirm) :button-one-label (i18n/label :t/confirm)

View File

@ -14,11 +14,13 @@
{:amount amount {:amount amount
:network from-network :network from-network
:status status}] :status status}]
[quo/network-link (if (= status :default)
{:shape :linear [quo/network-link
:source from-network {:shape :linear
:destination to-network :source from-network
:container-style style/network-link}] :destination to-network
:container-style style/network-link}]
[rn/view {:style {:width 73}}])
[quo/network-bridge [quo/network-bridge
{:amount amount {:amount amount
:network to-network :network to-network
@ -26,12 +28,12 @@
:container-style {:right 12}}]]) :container-style {:right 12}}]])
(defn view (defn view
[{:keys [amount routes]}] [{:keys [amount routes loading-networks]}]
(let [loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?]) (let [loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
candidates (:candidates routes)] candidates (:candidates routes)]
(if (and (not loading-suggested-routes?) (not-empty candidates)) (if (or (and (not-empty loading-networks) loading-suggested-routes?) (not-empty candidates))
[rn/flat-list [rn/flat-list
{:data candidates {:data (if loading-suggested-routes? loading-networks candidates)
:content-container-style style/routes-container :content-container-style style/routes-container
:header [rn/view {:style style/routes-header-container} :header [rn/view {:style style/routes-header-container}
[quo/section-label [quo/section-label
@ -40,15 +42,17 @@
[quo/section-label [quo/section-label
{:section (i18n/label :t/to-label) {:section (i18n/label :t/to-label)
:container-style (style/section-label 64)}]] :container-style (style/section-label 64)}]]
:render-fn (fn [route] :render-fn (fn [item]
[route-item [route-item
{:amount amount {:amount amount
:status :default :status (if loading-suggested-routes? :loading :default)
:from-network (utils/id->network (get-in route [:from :chain-id])) :from-network (if loading-suggested-routes?
:to-network (utils/id->network (get-in route (utils/id->network item)
[:to :chain-id]))}])}] (utils/id->network (get-in item [:from :chain-id])))
:to-network (if loading-suggested-routes?
(utils/id->network item)
(utils/id->network (get-in item
[:to :chain-id])))}])}]
[rn/view {:style style/empty-container} [rn/view {:style style/empty-container}
(if loading-suggested-routes? (when (and (not (nil? candidates)) (not loading-suggested-routes?))
[rn/activity-indicator] [quo/text (i18n/label :t/no-routes-found)])])))
(when (not (nil? candidates))
[quo/text (i18n/label :t/no-routes-found)]))])))

View File

@ -38,8 +38,8 @@
(rn/dismiss-keyboard!) (rn/dismiss-keyboard!)
(rf/dispatch [:open-modal :scan-address])) (rf/dispatch [:open-modal :scan-address]))
:ens-regex constants/regx-ens :ens-regex constants/regx-ens
:address-regex constants/regx-address
:scanned-value (or (when recipient-plain-address? send-address) scanned-address) :scanned-value (or (when recipient-plain-address? send-address) scanned-address)
:address-regex constants/regx-multichain-address
:on-detect-address #(debounce/debounce-and-dispatch :on-detect-address #(debounce/debounce-and-dispatch
[:wallet/validate-address %] [:wallet/validate-address %]
300) 300)
@ -48,8 +48,6 @@
[:wallet/find-ens text contacts chain-id cb] [:wallet/find-ens text contacts chain-id cb]
300)) 300))
:on-change-text (fn [text] :on-change-text (fn [text]
(when-not (= scanned-address text)
(rf/dispatch [:wallet/clean-scanned-address]))
(when (empty? text) (when (empty? text)
(rf/dispatch [:wallet/clean-local-suggestions])) (rf/dispatch [:wallet/clean-local-suggestions]))
(reset! input-value text)) (reset! input-value text))

View File

@ -43,6 +43,11 @@
:<- [:wallet/wallet-send] :<- [:wallet/wallet-send]
:-> :to-address) :-> :to-address)
(rf/reg-sub
:wallet/wallet-send-address-prefix
:<- [:wallet/wallet-send]
:-> :address-prefix)
(rf/reg-sub (rf/reg-sub
:wallet/wallet-send-route :wallet/wallet-send-route
:<- [:wallet/wallet-send] :<- [:wallet/wallet-send]