feat(swap): implement network selection drawer (#20368)
This commit is contained in:
parent
99506c810d
commit
2e8776d0a6
|
@ -44,13 +44,14 @@
|
||||||
[:label :string]
|
[:label :string]
|
||||||
[:fiat-value :string]
|
[:fiat-value :string]
|
||||||
[:token-value :string]
|
[:token-value :string]
|
||||||
|
[:container-style {:optional true} [:maybe :map]]
|
||||||
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
|
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
|
||||||
[:state {:optional true} [:enum :pressed :active :disabled :default]]
|
[:state {:optional true} [:enum :pressed :active :disabled :default]]
|
||||||
[:on-press {:optional true} [:maybe fn?]]]]]
|
[:on-press {:optional true} [:maybe fn?]]]]]
|
||||||
:any])
|
:any])
|
||||||
|
|
||||||
(defn- view-internal
|
(defn- view-internal
|
||||||
[{:keys [on-press state customization-color]
|
[{:keys [on-press container-style state customization-color]
|
||||||
:as props
|
:as props
|
||||||
:or {customization-color :blue}}]
|
:or {customization-color :blue}}]
|
||||||
(let [theme (quo.theme/use-theme)
|
(let [theme (quo.theme/use-theme)
|
||||||
|
@ -59,7 +60,8 @@
|
||||||
on-press-out (rn/use-callback #(set-pressed false))
|
on-press-out (rn/use-callback #(set-pressed false))
|
||||||
internal-state (if pressed? :pressed state)]
|
internal-state (if pressed? :pressed state)]
|
||||||
[rn/pressable
|
[rn/pressable
|
||||||
{:style (style/container internal-state customization-color theme)
|
{:style (merge (style/container internal-state customization-color theme)
|
||||||
|
container-style)
|
||||||
:on-press-in (when-not (= state :disabled) on-press-in)
|
:on-press-in (when-not (= state :disabled) on-press-in)
|
||||||
:on-press-out (when-not (= state :disabled) on-press-out)
|
:on-press-out (when-not (= state :disabled) on-press-out)
|
||||||
:on-press (when-not (= state :disabled) on-press)
|
:on-press (when-not (= state :disabled) on-press)
|
||||||
|
|
|
@ -505,6 +505,9 @@
|
||||||
(def ^:const optimism-network-name :optimism)
|
(def ^:const optimism-network-name :optimism)
|
||||||
(def ^:const arbitrum-network-name :arbitrum)
|
(def ^:const arbitrum-network-name :arbitrum)
|
||||||
|
|
||||||
|
(def ^:const layer-1-network 1)
|
||||||
|
(def ^:const layer-2-network 2)
|
||||||
|
|
||||||
(def ^:const default-network-names [mainnet-network-name optimism-network-name arbitrum-network-name])
|
(def ^:const default-network-names [mainnet-network-name optimism-network-name arbitrum-network-name])
|
||||||
|
|
||||||
(def ^:const default-network-count (count default-network-names))
|
(def ^:const default-network-count (count default-network-names))
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
(ns status-im.contexts.wallet.sheets.network-selection.style)
|
||||||
|
|
||||||
|
(defn network-list-container
|
||||||
|
[mainnet?]
|
||||||
|
{:margin-horizontal 8
|
||||||
|
:padding-vertical (when mainnet? 8)})
|
||||||
|
|
||||||
|
(def header-container
|
||||||
|
{:height 62
|
||||||
|
:padding-horizontal 20})
|
||||||
|
|
||||||
|
(def context-tag
|
||||||
|
{:margin-top 4})
|
||||||
|
|
||||||
|
(def divider-label
|
||||||
|
{:padding-top 0
|
||||||
|
:padding-bottom 0})
|
|
@ -0,0 +1,55 @@
|
||||||
|
(ns status-im.contexts.wallet.sheets.network-selection.view
|
||||||
|
(:require [quo.core :as quo]
|
||||||
|
[quo.foundations.resources :as quo.resources]
|
||||||
|
[react-native.core :as rn]
|
||||||
|
[status-im.constants :as constants]
|
||||||
|
[status-im.contexts.wallet.sheets.network-selection.style :as style]
|
||||||
|
[utils.i18n :as i18n]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
|
(defn- network-item
|
||||||
|
[{:keys [network on-select-network]}]
|
||||||
|
(let [{:keys [network-name
|
||||||
|
chain-id]} network
|
||||||
|
{balance-in-crypto :crypto
|
||||||
|
balance-in-fiat :fiat} (rf/sub [:wallet/swap-asset-to-pay-network-balance chain-id])
|
||||||
|
mainnet? (= network-name constants/mainnet-network-name)]
|
||||||
|
[quo/network-list
|
||||||
|
{:label (name network-name)
|
||||||
|
:network-image (quo.resources/get-network network-name)
|
||||||
|
:token-value balance-in-crypto
|
||||||
|
:fiat-value balance-in-fiat
|
||||||
|
:on-press #(on-select-network network)
|
||||||
|
:container-style (style/network-list-container mainnet?)}]))
|
||||||
|
|
||||||
|
(defn view
|
||||||
|
[{:keys [on-select-network]}]
|
||||||
|
(let [token-symbol (rf/sub [:wallet/swap-asset-to-pay-token-symbol])
|
||||||
|
{mainnet-network :mainnet-network
|
||||||
|
layer-2-networks :layer-2-networks} (rf/sub [:wallet/swap-asset-to-pay-networks])
|
||||||
|
render-fn (rn/use-callback (fn [network]
|
||||||
|
[network-item
|
||||||
|
{:network network
|
||||||
|
:on-select-network
|
||||||
|
on-select-network}]))]
|
||||||
|
[:<>
|
||||||
|
[rn/view {:style style/header-container}
|
||||||
|
[quo/text
|
||||||
|
{:size :heading-2
|
||||||
|
:weight :semi-bold}
|
||||||
|
(i18n/label :t/select-network)]
|
||||||
|
[quo/context-tag
|
||||||
|
{:type :token
|
||||||
|
:size 24
|
||||||
|
:token token-symbol
|
||||||
|
:container-style style/context-tag}]]
|
||||||
|
(when mainnet-network
|
||||||
|
[network-item
|
||||||
|
{:network mainnet-network
|
||||||
|
:on-select-network on-select-network}])
|
||||||
|
[quo/divider-label {:container-style style/divider-label}
|
||||||
|
(i18n/label :t/layer-2)]
|
||||||
|
[rn/flat-list
|
||||||
|
{:data (vec layer-2-networks)
|
||||||
|
:render-fn render-fn
|
||||||
|
:scroll-enabled false}]]))
|
|
@ -1,18 +1,35 @@
|
||||||
(ns status-im.contexts.wallet.swap.events
|
(ns status-im.contexts.wallet.swap.events
|
||||||
(:require [re-frame.core :as rf]))
|
(:require [re-frame.core :as rf]
|
||||||
|
[status-im.contexts.wallet.sheets.network-selection.view :as network-selection]))
|
||||||
|
|
||||||
(rf/reg-event-fx :wallet.swap/start
|
(rf/reg-event-fx :wallet.swap/start
|
||||||
(fn [{:keys [_db]}]
|
(fn [{:keys [_db]}]
|
||||||
{:fx [[:dispatch [:open-modal :screen/wallet.swap-select-asset-to-pay]]]}))
|
{:fx [[:dispatch [:open-modal :screen/wallet.swap-select-asset-to-pay]]]}))
|
||||||
|
|
||||||
(rf/reg-event-fx :wallet.swap/select-asset-to-pay
|
(rf/reg-event-fx :wallet.swap/select-asset-to-pay
|
||||||
(fn [{:keys [db]} token]
|
(fn [{:keys [db]} [{:keys [token network]}]]
|
||||||
{:db (assoc-in db [:wallet :ui :swap :asset-to-pay] token)
|
{:db (-> db
|
||||||
:fx [[:dispatch
|
(assoc-in [:wallet :ui :swap :asset-to-pay] token)
|
||||||
[:toasts/upsert
|
(assoc-in [:wallet :ui :swap :network] network))
|
||||||
{:id :swap-error
|
:fx [(if network
|
||||||
:type :negative
|
[:dispatch
|
||||||
:text "Not implemented yet"}]]]}))
|
[:toasts/upsert
|
||||||
|
{:id :swap-error
|
||||||
|
:type :negative
|
||||||
|
:text "Not implemented yet"}]]
|
||||||
|
[:dispatch
|
||||||
|
[:show-bottom-sheet
|
||||||
|
{:content (fn []
|
||||||
|
[network-selection/view
|
||||||
|
{:token-symbol (:symbol token)
|
||||||
|
:on-select-network (fn [network]
|
||||||
|
(rf/dispatch [:hide-bottom-sheet])
|
||||||
|
(rf/dispatch
|
||||||
|
[:wallet.swap/select-asset-to-pay
|
||||||
|
{:token token
|
||||||
|
:network network
|
||||||
|
:stack-id
|
||||||
|
:screen/wallet.swap-select-asset-to-pay}]))}])}]])]}))
|
||||||
|
|
||||||
(rf/reg-event-fx :wallet.swap/clean-asset-to-pay
|
(rf/reg-event-fx :wallet.swap/clean-asset-to-pay
|
||||||
(fn [{:keys [db]}]
|
(fn [{:keys [db]}]
|
||||||
|
|
|
@ -21,9 +21,12 @@
|
||||||
(defn- assets-view
|
(defn- assets-view
|
||||||
[search-text on-change-text]
|
[search-text on-change-text]
|
||||||
(let [on-token-press (fn [token]
|
(let [on-token-press (fn [token]
|
||||||
(rf/dispatch [:wallet.swap/select-asset-to-pay
|
(let [token-networks (:networks token)]
|
||||||
{:token token
|
(rf/dispatch [:wallet.swap/select-asset-to-pay
|
||||||
:stack-id :screen/wallet.swap-select-asset-to-pay}]))]
|
{:token token
|
||||||
|
:network (when (= (count token-networks) 1)
|
||||||
|
(first token-networks))
|
||||||
|
:stack-id :screen/wallet.swap-select-asset-to-pay}])))]
|
||||||
[:<>
|
[:<>
|
||||||
[search-input search-text on-change-text]
|
[search-input search-text on-change-text]
|
||||||
[asset-list/view
|
[asset-list/view
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
status-im.subs.wallet.networks
|
status-im.subs.wallet.networks
|
||||||
status-im.subs.wallet.saved-addresses
|
status-im.subs.wallet.saved-addresses
|
||||||
status-im.subs.wallet.send
|
status-im.subs.wallet.send
|
||||||
|
status-im.subs.wallet.swap
|
||||||
status-im.subs.wallet.wallet
|
status-im.subs.wallet.wallet
|
||||||
status-im.subs.wallet.wallet-connect))
|
status-im.subs.wallet.wallet-connect))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
(ns status-im.subs.wallet.swap
|
||||||
|
(:require [re-frame.core :as rf]
|
||||||
|
[status-im.constants :as constants]
|
||||||
|
[status-im.contexts.wallet.common.utils :as utils]
|
||||||
|
[utils.money :as money]))
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:wallet/swap
|
||||||
|
:<- [:wallet/ui]
|
||||||
|
:-> :swap)
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:wallet/swap-asset-to-pay
|
||||||
|
:<- [:wallet/swap]
|
||||||
|
:-> :asset-to-pay)
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:wallet/swap-asset-to-pay-token-symbol
|
||||||
|
:<- [:wallet/swap-asset-to-pay]
|
||||||
|
:-> :symbol)
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:wallet/swap-asset-to-pay-networks
|
||||||
|
:<- [:wallet/swap-asset-to-pay]
|
||||||
|
(fn [token]
|
||||||
|
(let [{token-networks :networks} token
|
||||||
|
grouped-networks (group-by :layer
|
||||||
|
token-networks)
|
||||||
|
mainnet-network (first (get grouped-networks constants/layer-1-network))
|
||||||
|
layer-2-networks (get grouped-networks constants/layer-2-network)]
|
||||||
|
{:mainnet-network mainnet-network
|
||||||
|
:layer-2-networks layer-2-networks})))
|
||||||
|
|
||||||
|
(rf/reg-sub
|
||||||
|
:wallet/swap-asset-to-pay-network-balance
|
||||||
|
:<- [:wallet/swap-asset-to-pay]
|
||||||
|
:<- [:profile/currency]
|
||||||
|
:<- [:profile/currency-symbol]
|
||||||
|
:<- [:wallet/swap-asset-to-pay-token-symbol]
|
||||||
|
(fn [[token currency currency-symbol token-symbol] [_ chain-id]]
|
||||||
|
(let [{:keys [balances-per-chain
|
||||||
|
decimals]} token
|
||||||
|
balance-for-chain (get balances-per-chain chain-id)
|
||||||
|
total-balance (money/token->unit (:raw-balance balance-for-chain) decimals)
|
||||||
|
fiat-value (utils/calculate-token-fiat-value
|
||||||
|
{:currency currency
|
||||||
|
:balance total-balance
|
||||||
|
:token token})
|
||||||
|
crypto-formatted (utils/get-standard-crypto-format token total-balance)
|
||||||
|
fiat-formatted (utils/get-standard-fiat-format crypto-formatted
|
||||||
|
currency-symbol
|
||||||
|
fiat-value)]
|
||||||
|
{:crypto (str crypto-formatted " " token-symbol)
|
||||||
|
:fiat fiat-formatted})))
|
|
@ -0,0 +1,107 @@
|
||||||
|
(ns status-im.subs.wallet.swap-test
|
||||||
|
(:require
|
||||||
|
[cljs.test :refer [is testing]]
|
||||||
|
[re-frame.db :as rf-db]
|
||||||
|
[status-im.subs.root]
|
||||||
|
[status-im.subs.wallet.collectibles]
|
||||||
|
[test-helpers.unit :as h]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
|
(def networks
|
||||||
|
{:mainnet-network
|
||||||
|
{:full-name "Mainnet"
|
||||||
|
:network-name :mainnet
|
||||||
|
:chain-id 1
|
||||||
|
:related-chain-id 5
|
||||||
|
:layer 1}
|
||||||
|
:layer-2-networks
|
||||||
|
[{:full-name "Optimism"
|
||||||
|
:network-name :optimism
|
||||||
|
:chain-id 10
|
||||||
|
:related-chain-id 420
|
||||||
|
:layer 2}
|
||||||
|
{:full-name "Arbitrum"
|
||||||
|
:network-name :arbitrum
|
||||||
|
:chain-id 42161
|
||||||
|
:related-chain-id 421613
|
||||||
|
:layer 2}]})
|
||||||
|
|
||||||
|
(def swap-data
|
||||||
|
{:asset-to-pay
|
||||||
|
{:description "Status Network Token (SNT)"
|
||||||
|
:decimals 18
|
||||||
|
:symbol "SNT"
|
||||||
|
:name "Status"
|
||||||
|
:total-balance 1
|
||||||
|
:balances-per-chain
|
||||||
|
{1
|
||||||
|
{:raw-balance 1000000000000000000
|
||||||
|
:balance "1"
|
||||||
|
:chain-id 1}
|
||||||
|
10
|
||||||
|
{:raw-balance 0
|
||||||
|
:balance "0"
|
||||||
|
:chain-id 10}
|
||||||
|
42161
|
||||||
|
{:raw-balance 0
|
||||||
|
:balance "0"
|
||||||
|
:chain-id 42161}}
|
||||||
|
:networks (concat [(networks :mainnet-network)] (networks :layer-2-networks))
|
||||||
|
:chain-id 0
|
||||||
|
:market-values-per-currency
|
||||||
|
{:usd
|
||||||
|
{:change-24hour -0.00109422754667007
|
||||||
|
:change-pct-day -5.57352274163899
|
||||||
|
:change-pct-24hour -4.177805426737527
|
||||||
|
:high-day 0.0271858672171352
|
||||||
|
:market-cap 170783296.1155821
|
||||||
|
:has-error false
|
||||||
|
:change-pct-hour -0.0160462113709363
|
||||||
|
:low-day 0.02473516779550377
|
||||||
|
:price 0.0251}}
|
||||||
|
:asset-website-url "https://status.im/"
|
||||||
|
:available-balance 1
|
||||||
|
:token-list-id ""
|
||||||
|
:built-on "ETH"
|
||||||
|
:verified true}
|
||||||
|
:network nil})
|
||||||
|
|
||||||
|
(h/deftest-sub :wallet/swap
|
||||||
|
[sub-name]
|
||||||
|
(testing "Return the wallet/ui/swap node"
|
||||||
|
(swap! rf-db/app-db assoc-in
|
||||||
|
[:wallet :ui :swap]
|
||||||
|
swap-data)
|
||||||
|
(is (match? swap-data (rf/sub [sub-name])))))
|
||||||
|
|
||||||
|
(h/deftest-sub :wallet/swap-asset-to-pay
|
||||||
|
[sub-name]
|
||||||
|
(testing "Return swap asset-to-pay"
|
||||||
|
(swap! rf-db/app-db assoc-in
|
||||||
|
[:wallet :ui :swap]
|
||||||
|
swap-data)
|
||||||
|
(is (match? (swap-data :asset-to-pay) (rf/sub [sub-name])))))
|
||||||
|
|
||||||
|
(h/deftest-sub :wallet/swap-asset-to-pay-token-symbol
|
||||||
|
[sub-name]
|
||||||
|
(testing "Return asset-to-pay token symbol"
|
||||||
|
(swap! rf-db/app-db assoc-in
|
||||||
|
[:wallet :ui :swap]
|
||||||
|
swap-data)
|
||||||
|
(is (match? "SNT" (rf/sub [sub-name])))))
|
||||||
|
|
||||||
|
(h/deftest-sub :wallet/swap-asset-to-pay-networks
|
||||||
|
[sub-name]
|
||||||
|
(testing "Return the available networks for the swap asset-to-pay"
|
||||||
|
(swap! rf-db/app-db assoc-in
|
||||||
|
[:wallet :ui :swap]
|
||||||
|
swap-data)
|
||||||
|
(is (match? networks (rf/sub [sub-name])))))
|
||||||
|
|
||||||
|
(h/deftest-sub :wallet/swap-asset-to-pay-network-balance
|
||||||
|
[sub-name]
|
||||||
|
(testing "Return swap asset-to-pay"
|
||||||
|
(swap! rf-db/app-db assoc-in
|
||||||
|
[:wallet :ui :swap]
|
||||||
|
swap-data)
|
||||||
|
(is (match? {:crypto "1 SNT" :fiat "$0.03"} (rf/sub [sub-name 1])))))
|
|
@ -2627,6 +2627,7 @@
|
||||||
"derivation-path-header": "Derivation path",
|
"derivation-path-header": "Derivation path",
|
||||||
"derivation-path-desc": "Derivation paths are the routes your Status Wallet uses to generate addresses from your private key.",
|
"derivation-path-desc": "Derivation paths are the routes your Status Wallet uses to generate addresses from your private key.",
|
||||||
"select-networks": "Select networks",
|
"select-networks": "Select networks",
|
||||||
|
"select-network": "Select network",
|
||||||
"generating-keypair": "Generating key pair...",
|
"generating-keypair": "Generating key pair...",
|
||||||
"keypair-name": "Key pair name",
|
"keypair-name": "Key pair name",
|
||||||
"keypair-name-description": "Name key pair for your own personal reference",
|
"keypair-name-description": "Name key pair for your own personal reference",
|
||||||
|
|
Loading…
Reference in New Issue