parent
02b8d2140a
commit
19aa78cc81
|
@ -219,7 +219,8 @@
|
|||
(def regx-community-universal-link #"((^https?://status.app/)|(^status-app://))c/([\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-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-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}$")
|
||||
|
|
|
@ -8,13 +8,16 @@
|
|||
[status-im.config :as config]
|
||||
[status-im.contexts.profile.utils :as profile.utils]
|
||||
[status-im.contexts.wallet.account.tabs.about.style :as style]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn about-options
|
||||
[]
|
||||
(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
|
||||
[[{:icon :i/link
|
||||
:accessibility-label :view-on-eth
|
||||
|
@ -44,7 +47,7 @@
|
|||
:accessibility-label :copy-address
|
||||
:label (i18n/label :t/copy-address)
|
||||
:on-press (fn []
|
||||
(clipboard/set-string address)
|
||||
(clipboard/set-string multichain-address)
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:type :positive
|
||||
:text (i18n/label :t/address-copied)}]))}
|
||||
|
@ -59,15 +62,17 @@
|
|||
(js/setTimeout
|
||||
#(share/open
|
||||
(if platform/ios?
|
||||
{:activityItemSources [{:placeholderItem {:type "text"
|
||||
:content address}
|
||||
:item {:default {:type "text"
|
||||
:content
|
||||
address}}
|
||||
{:activityItemSources [{:placeholderItem {:type "text"
|
||||
:content
|
||||
multichain-address}
|
||||
:item {:default
|
||||
{:type "text"
|
||||
:content
|
||||
multichain-address}}
|
||||
:linkMetadata {:title share-title}}]}
|
||||
{:title share-title
|
||||
:subject share-title
|
||||
:message address}))
|
||||
:message multichain-address}))
|
||||
600))}]]]))
|
||||
|
||||
(defn view
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
[react-native.platform :as platform]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.wallet.common.sheets.account-options.style :as style]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
|
@ -31,7 +32,10 @@
|
|||
(defn- options
|
||||
[{:keys [theme show-account-selector? options-height]}]
|
||||
(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
|
||||
{:on-layout #(reset! options-height (oops/oget % "nativeEvent.layout.height"))
|
||||
:style (when show-account-selector? style/options-container)}
|
||||
|
@ -72,7 +76,7 @@
|
|||
(rf/dispatch [:toasts/upsert
|
||||
{:type :positive
|
||||
:text (i18n/label :t/address-copied)}])
|
||||
(clipboard/set-string address))}
|
||||
(clipboard/set-string multichain-address))}
|
||||
{:icon :i/share
|
||||
:accessibility-label :share-account
|
||||
:label (i18n/label :t/share-account)}
|
||||
|
|
|
@ -202,3 +202,15 @@
|
|||
:customization-color color
|
||||
:values {:crypto-value crypto-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))]))
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
(:require [status-im.constants :as constants]))
|
||||
|
||||
(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))
|
||||
|
|
|
@ -2,11 +2,10 @@
|
|||
(:require
|
||||
[camel-snake-kebab.core :as csk]
|
||||
[camel-snake-kebab.extras :as cske]
|
||||
[native-module.core :as native-module]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
[utils.money :as money]
|
||||
[utils.number]
|
||||
[utils.re-frame :as rf]))
|
||||
|
@ -42,23 +41,32 @@
|
|||
(update-in [:wallet :ui :send] dissoc :route)
|
||||
(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
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui :send] dissoc :recipient :to-address)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/select-send-address
|
||||
(fn [{:keys [db]} [{:keys [address token recipient stack-id]}]]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :recipient] (or recipient address))
|
||||
(assoc-in [:wallet :ui :send :to-address] address))
|
||||
:fx [[:navigate-to-within-stack
|
||||
(if token [:wallet-send-input-amount stack-id] [:wallet-select-asset stack-id])]]}))
|
||||
(let [[prefix to-address] (utils/split-prefix-and-address address)]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :recipient] (or recipient address))
|
||||
(assoc-in [:wallet :ui :send :to-address] to-address)
|
||||
(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
|
||||
(fn [{:keys [db]} [{:keys [token stack-id]}]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :collectible)
|
||||
(assoc-in [:wallet :ui :send :token] token))
|
||||
{:db (assoc-in db [:wallet :ui :send :token] token)
|
||||
:fx [[:navigate-to-within-stack [:wallet-send-input-amount stack-id]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/send-select-token-drawer
|
||||
|
@ -69,15 +77,6 @@
|
|||
(fn [{:keys [db]}]
|
||||
{: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
|
||||
(fn [{:keys [db]} [{:keys [amount stack-id]}]]
|
||||
{:db (assoc-in db [:wallet :ui :send :amount] amount)
|
||||
|
@ -87,25 +86,18 @@
|
|||
(fn [{:keys [db now]} [amount]]
|
||||
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
|
||||
token (get-in db [:wallet :ui :send :token])
|
||||
collectible (get-in db [:wallet :ui :send :collectible])
|
||||
to-address (get-in db [:wallet :ui :send :to-address])
|
||||
token-decimal (when token (:decimals token))
|
||||
token-id (if token
|
||||
(:symbol token)
|
||||
(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])])
|
||||
account-address (get-in db [:wallet :ui :send :send-account-address])
|
||||
to-address (or account-address (get-in db [:wallet :ui :send :to-address]))
|
||||
token-decimal (:decimals token)
|
||||
token-id (:symbol token)
|
||||
network-preferences []
|
||||
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
|
||||
disabled-from-chain-ids []
|
||||
disabled-to-chain-ids []
|
||||
from-locked-amount {}
|
||||
transaction-type (if token
|
||||
constants/send-type-transfer
|
||||
constants/send-type-erc-721-transfer)
|
||||
request-params [transaction-type
|
||||
request-params [constants/send-type-transfer
|
||||
from-address
|
||||
to-address
|
||||
amount-in
|
||||
|
@ -142,46 +134,21 @@
|
|||
:fx [[:dispatch [:navigate-to :wallet-transaction-progress]]]})))
|
||||
|
||||
(defn- transaction-bridge
|
||||
[{:keys [from-address from-chain-id to-address token-id token-address route data eth-transfer?]}]
|
||||
(let [{:keys [bridge-name amount-out gas-amount
|
||||
gas-fees]} route
|
||||
eip-1559-enabled? (:eip-1559-enabled gas-fees)
|
||||
{:keys [gas-price max-fee-per-gas-medium
|
||||
max-priority-fee-per-gas]} gas-fees
|
||||
transfer-tx (cond-> {:From from-address
|
||||
:To (or token-address to-address)
|
||||
:Gas (money/to-hex gas-amount)
|
||||
:Value (when eth-transfer? amount-out)
|
||||
:Nonce nil
|
||||
:Input ""
|
||||
:Data (or data "0x")}
|
||||
eip-1559-enabled? (assoc :TxType "0x02"
|
||||
:MaxFeePerGas
|
||||
(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))]))
|
||||
[{:keys [from-address to-address route]}]
|
||||
(let [{:keys [from bridge-name amount-out gas-amount gas-fees]} route
|
||||
{:keys [gas-price max-fee-per-gas-medium max-priority-fee-per-gas]} gas-fees]
|
||||
[{:BridgeName bridge-name
|
||||
:ChainID (:chain-id from)
|
||||
:TransferTx {:From from-address
|
||||
:To to-address
|
||||
:Gas (money/to-hex gas-amount)
|
||||
:GasPrice (money/to-hex (money/->wei :gwei gas-price))
|
||||
:Value amount-out
|
||||
:Nonce nil
|
||||
:MaxFeePerGas (money/to-hex (money/->wei :gwei max-fee-per-gas-medium))
|
||||
:MaxPriorityFeePerGas (money/to-hex (money/->wei :gwei max-priority-fee-per-gas))
|
||||
:Input ""
|
||||
:Data "0x"}}]))
|
||||
|
||||
(defn- multi-transaction-command
|
||||
[{:keys [from-address to-address from-asset to-asset amount-out transfer-type]
|
||||
|
@ -195,53 +162,27 @@
|
|||
|
||||
(rf/reg-event-fx :wallet/send-transaction
|
||||
(fn [{:keys [db]} [sha3-pwd]]
|
||||
(let [route (get-in db [:wallet :ui :send :route])
|
||||
from-address (get-in db [:wallet :current-viewing-account-address])
|
||||
token (get-in db [:wallet :ui :send :token])
|
||||
collectible (get-in db [:wallet :ui :send :collectible])
|
||||
from-chain-id (get-in 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 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]]
|
||||
(let [route (get-in db [:wallet :ui :send :route])
|
||||
from-address (get-in db [:wallet :current-viewing-account-address])
|
||||
to-address (get-in db [:wallet :ui :send :to-address])
|
||||
token (get-in db [:wallet :ui :send :token])
|
||||
token-id (:symbol token)
|
||||
request-params [(multi-transaction-command {:from-address from-address
|
||||
:to-address to-address
|
||||
:from-asset token-id
|
||||
:to-asset token-id
|
||||
:amount-out (:amount-out route)})
|
||||
(transaction-bridge {:to-address to-address
|
||||
:from-address from-address
|
||||
:route route})
|
||||
sha3-pwd]]
|
||||
{:json-rpc/call [{:method "wallet_createMultiTransaction"
|
||||
:params request-params
|
||||
:on-success (fn [result]
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(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]))
|
||||
(rf/dispatch [:wallet/add-authorized-transaction result]))
|
||||
:on-error (fn [error]
|
||||
(log/error "failed to send transaction"
|
||||
{:event :wallet/send-transaction
|
||||
:error error
|
||||
:params request-params}))}]})))
|
||||
|
||||
|
|
|
@ -53,6 +53,13 @@
|
|||
(normalize-input current v)
|
||||
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
|
||||
[{:keys [rate limit]}]
|
||||
(let [bottom (safe-area/get-bottom)
|
||||
|
@ -142,9 +149,10 @@
|
|||
:on-change-text (fn [text]
|
||||
(handle-on-change text))}]
|
||||
[routes/view
|
||||
{:amount amount
|
||||
:routes suggested-routes
|
||||
:networks (:networks token)}]
|
||||
{:amount amount
|
||||
:routes suggested-routes
|
||||
:loading-networks (find-affordable-networks token @input-value)
|
||||
:networks (:networks token)}]
|
||||
[quo/bottom-actions
|
||||
{:actions :1-action
|
||||
:button-one-label (i18n/label :t/confirm)
|
||||
|
|
|
@ -14,11 +14,13 @@
|
|||
{:amount amount
|
||||
:network from-network
|
||||
:status status}]
|
||||
[quo/network-link
|
||||
{:shape :linear
|
||||
:source from-network
|
||||
:destination to-network
|
||||
:container-style style/network-link}]
|
||||
(if (= status :default)
|
||||
[quo/network-link
|
||||
{:shape :linear
|
||||
:source from-network
|
||||
:destination to-network
|
||||
:container-style style/network-link}]
|
||||
[rn/view {:style {:width 73}}])
|
||||
[quo/network-bridge
|
||||
{:amount amount
|
||||
:network to-network
|
||||
|
@ -26,12 +28,12 @@
|
|||
:container-style {:right 12}}]])
|
||||
|
||||
(defn view
|
||||
[{:keys [amount routes]}]
|
||||
[{:keys [amount routes loading-networks]}]
|
||||
(let [loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-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
|
||||
{:data candidates
|
||||
{:data (if loading-suggested-routes? loading-networks candidates)
|
||||
:content-container-style style/routes-container
|
||||
:header [rn/view {:style style/routes-header-container}
|
||||
[quo/section-label
|
||||
|
@ -40,15 +42,17 @@
|
|||
[quo/section-label
|
||||
{:section (i18n/label :t/to-label)
|
||||
:container-style (style/section-label 64)}]]
|
||||
:render-fn (fn [route]
|
||||
:render-fn (fn [item]
|
||||
[route-item
|
||||
{:amount amount
|
||||
:status :default
|
||||
:from-network (utils/id->network (get-in route [:from :chain-id]))
|
||||
:to-network (utils/id->network (get-in route
|
||||
[:to :chain-id]))}])}]
|
||||
:status (if loading-suggested-routes? :loading :default)
|
||||
:from-network (if loading-suggested-routes?
|
||||
(utils/id->network item)
|
||||
(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}
|
||||
(if loading-suggested-routes?
|
||||
[rn/activity-indicator]
|
||||
(when (not (nil? candidates))
|
||||
[quo/text (i18n/label :t/no-routes-found)]))])))
|
||||
(when (and (not (nil? candidates)) (not loading-suggested-routes?))
|
||||
[quo/text (i18n/label :t/no-routes-found)])])))
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
(rn/dismiss-keyboard!)
|
||||
(rf/dispatch [:open-modal :scan-address]))
|
||||
:ens-regex constants/regx-ens
|
||||
:address-regex constants/regx-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
|
||||
[:wallet/validate-address %]
|
||||
300)
|
||||
|
@ -48,8 +48,6 @@
|
|||
[:wallet/find-ens text contacts chain-id cb]
|
||||
300))
|
||||
:on-change-text (fn [text]
|
||||
(when-not (= scanned-address text)
|
||||
(rf/dispatch [:wallet/clean-scanned-address]))
|
||||
(when (empty? text)
|
||||
(rf/dispatch [:wallet/clean-local-suggestions]))
|
||||
(reset! input-value text))
|
||||
|
|
|
@ -43,6 +43,11 @@
|
|||
:<- [:wallet/wallet-send]
|
||||
:-> :to-address)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-address-prefix
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :address-prefix)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-route
|
||||
:<- [:wallet/wallet-send]
|
||||
|
|
Loading…
Reference in New Issue