Skip to content

Commit

Permalink
[#21557] feat: show from account page in swap flow (#21611)
Browse files Browse the repository at this point in the history
* [#21557] feat: show from account page in swap flow

* [#21557] feat: add disabled state to account-item

* [#21557] fix: apply suggestion

* [#21557] fix: add format address util and rename screen

* [#21557] fix: check and count account with token balance

* [#21557] fix: check for root screen
  • Loading branch information
mohsen-ghafouri authored Nov 22, 2024
1 parent 26ae330 commit 21c2a52
Show file tree
Hide file tree
Showing 12 changed files with 242 additions and 41 deletions.
2 changes: 1 addition & 1 deletion src/quo/components/list_items/account/schema.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
[:map
[:type {:optional true}
[:enum :default :tag :action :balance-neutral :balance-negative :balance-positive]]
[:state {:optional true} [:enum :default :selected :active]]
[:state {:optional true} [:enum :default :selected :active :disabled]]
[:blur? {:optional true} [:maybe :boolean]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:on-press {:optional true} [:maybe fn?]]
Expand Down
3 changes: 2 additions & 1 deletion src/quo/components/list_items/account/style.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
:else :transparent))

(defn container
[props]
[{:keys [state] :as props}]
{:height 56
:border-radius 12
:background-color (background-color props)
:flex-direction :row
:align-items :center
:opacity (if (= state :disabled) 0.3 1)
:padding-horizontal 12
:padding-vertical 6
:justify-content :space-between})
Expand Down
1 change: 1 addition & 0 deletions src/quo/components/list_items/account/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
:pressed? pressed?})
:on-press-in on-press-in
:on-press on-press
:disabled (= state :disabled)
:on-press-out on-press-out
:accessibility-label :container}
[account-view props]
Expand Down
26 changes: 25 additions & 1 deletion src/status_im/contexts/wallet/common/utils.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@

(defn token-balance-display-for-network
"Formats a token balance for a specific chain and rounds it to a specified number of decimals.
If the balance is less than the smallest representable value based on rounding decimals,
If the balance is less than the smallest representable value based on rounding decimals,
a threshold value is displayed instead."
[token chain-id rounding-decimals]
(let [token-decimals (:decimals token)
Expand Down Expand Up @@ -548,3 +548,27 @@
(:less-than-three-minutes constants/wallet-transaction-estimation) "1-3"
(:less-than-five-minutes constants/wallet-transaction-estimation) "3-5"
">5"))

(defn get-accounts-with-token-balance
[accounts token]
(let [operable-account (filter :operable? (vals accounts))
positive-balance-in-any-chain? (fn [{:keys [balances-per-chain]}]
(->> balances-per-chain
(map (comp :raw-balance val))
(some pos?)))
addresses-tokens-with-positive-balance (as-> operable-account $
(group-by :address $)
(update-vals $
#(filter positive-balance-in-any-chain?
(:tokens (first %)))))]
(if-let [asset-symbol (:symbol token)]
(let [addresses-with-asset (as-> addresses-tokens-with-positive-balance $
(update-vals $ #(set (map :symbol %)))
(keep (fn [[address token-symbols]]
(when (token-symbols asset-symbol) address))
$)
(set $))]
(filter #(addresses-with-asset (:address %)) operable-account))
(filter (fn [{:keys [tokens]}]
(some positive-balance-in-any-chain? tokens))
operable-account))))
9 changes: 9 additions & 0 deletions src/status_im/contexts/wallet/common/utils/networks.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
[utils.number]))

(def ^:private last-comma-followed-by-text-to-end-regex #",\s(?=[^,]+$)")
(def ^:private max-network-prefixes 2)

(def id->network
{constants/ethereum-mainnet-chain-id constants/mainnet-network-name
Expand Down Expand Up @@ -185,3 +186,11 @@
:related-chain-id related-chain-id
:layer layer)))
(sort-by (juxt :layer :short-name))))

(defn format-address
[address network-preferences]
(let [short-names (map network->short-name network-preferences)
prefix (when (<= (count short-names) max-network-prefixes)
(short-names->network-preference-prefix short-names))
transformed-address (str prefix address)]
transformed-address))
65 changes: 65 additions & 0 deletions src/status_im/contexts/wallet/common/utils_test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -269,3 +269,68 @@
expected "0"]
(is (= (utils/token-balance-display-for-network token chain-id rounding-decimals)
expected)))))

(def mock-accounts
{:0xfc6327a092f6232e158a0dd1d6d967a2e1c65cd5
{:address "0xfc6327a092f6232e158a0dd1d6d967a2e1c65cd5"
:operable? true
:tokens [{:symbol "ETH"
:balances-per-chain {1 {:raw-balance 1000000
:balance 1.0}}}
{:symbol "USDC"
:balances-per-chain {1 {:raw-balance 0
:balance 0}}}]}
:0xbce36f66a8cd99f1d6489cb9585146e3f3b893be
{:address "0xbce36f66a8cd99f1d6489cb9585146e3f3b893be"
:operable? true
:tokens [{:symbol "ETH"
:balances-per-chain {1 {:raw-balance 0
:balance 0}}}]}})

(deftest get-accounts-with-token-balance-test
(testing "Positive token balance for a specific token"
(let [accounts mock-accounts
token {:symbol "ETH"}
expected [{:address "0xfc6327a092f6232e158a0dd1d6d967a2e1c65cd5"
:operable? true
:tokens [{:symbol "ETH"
:balances-per-chain {1 {:raw-balance 1000000
:balance 1.0}}}
{:symbol "USDC"
:balances-per-chain {1 {:raw-balance 0
:balance 0}}}]}]]
(is (= (utils/get-accounts-with-token-balance accounts token)
expected))))

(testing "No token symbol provided, return all tokens with positive balance"
(let [accounts mock-accounts
token {}
expected [{:address "0xfc6327a092f6232e158a0dd1d6d967a2e1c65cd5"
:operable? true
:tokens [{:symbol "ETH"
:balances-per-chain {1 {:raw-balance 1000000
:balance 1.0}}}
{:symbol "USDC"
:balances-per-chain {1 {:raw-balance 0
:balance 0}}}]}]]
(is (= (utils/get-accounts-with-token-balance accounts token)
expected))))

(testing "No matching token found for a specific token"
(let [accounts mock-accounts
token {:symbol "DAI"}
expected []]
(is (= (utils/get-accounts-with-token-balance accounts token)
expected))))

(testing "No operable accounts"
(let [accounts {:0xfc6327a092f6232e158a0dd1d6d967a2e1c65cd5
{:address "0xfc6327a092f6232e158a0dd1d6d967a2e1c65cd5"
:operable? false
:tokens [{:symbol "ETH"
:balances-per-chain {1 {:raw-balance 1000000
:balance 1.0}}}]}}
token {}
expected []]
(is (= (utils/get-accounts-with-token-balance accounts token)
expected)))))
81 changes: 51 additions & 30 deletions src/status_im/contexts/wallet/swap/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,23 @@
[utils.number :as number]))

(rf/reg-event-fx :wallet.swap/start
(fn [{:keys [db]} [{:keys [network asset-to-receive open-new-screen?] :as data}]]
(fn [{:keys [db]} [{:keys [network asset-to-receive open-new-screen? from-account] :as data}]]
(let [{:keys [wallet]} db
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
view-id (:view-id db)
account (swap-utils/wallet-account wallet)
root-screen? (or (= view-id :wallet-stack) (nil? view-id))
account (or from-account (swap-utils/wallet-account wallet))
asset-to-pay (if (get-in data [:asset-to-pay :networks])
(:asset-to-pay data)
(swap-utils/select-asset-to-pay-by-symbol
{:wallet wallet
:account account
:test-networks-enabled? test-networks-enabled?
:token-symbol (get-in data [:asset-to-pay :symbol])}))
multi-account-balance? (-> (utils/get-accounts-with-token-balance (:accounts wallet)
asset-to-pay)
(count)
(> 1))
network' (or network
(swap-utils/select-network asset-to-pay))
start-point (if open-new-screen? :action-menu :swap-button)]
Expand All @@ -35,34 +40,38 @@
(assoc-in [:wallet :ui :swap :network] network')
(assoc-in [:wallet :ui :swap :launch-screen] view-id)
(assoc-in [:wallet :ui :swap :start-point] start-point))
:fx (if network'
[[:dispatch [:wallet/switch-current-viewing-account (:address account)]]
[:dispatch
(if open-new-screen?
[:open-modal :screen/wallet.setup-swap]
[:navigate-to-within-stack
[:screen/wallet.setup-swap :screen/wallet.swap-select-asset-to-pay]])]
[:dispatch
[:centralized-metrics/track :metric/swap-start
{:network (:chain-id network)
:pay_token (:symbol asset-to-pay)
:receive_token (:symbol asset-to-receive)
:start_point start-point
:launch_screen view-id}]]
[:dispatch [:wallet.swap/set-default-slippage]]]
[[:dispatch
[:show-bottom-sheet
{:content (fn []
[network-selection/view
{:token-symbol (:symbol asset-to-pay)
:on-select-network (fn [network]
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch
[:wallet.swap/start
{:asset-to-pay asset-to-pay
:asset-to-receive asset-to-receive
:network network
:open-new-screen? open-new-screen?}]))}])}]]])})))
:fx (if (and multi-account-balance? root-screen? (not from-account))
[[:dispatch [:open-modal :screen/wallet.swap-select-account]]]
(if network'
[[:dispatch [:wallet/switch-current-viewing-account (:address account)]]
[:dispatch
(if open-new-screen?
[:open-modal :screen/wallet.setup-swap]
[:navigate-to-within-stack
[:screen/wallet.setup-swap :screen/wallet.swap-select-asset-to-pay]])]
[:dispatch
[:centralized-metrics/track :metric/swap-start
{:network (:chain-id network)
:pay_token (:symbol asset-to-pay)
:receive_token (:symbol asset-to-receive)
:start_point start-point
:launch_screen view-id}]]
[:dispatch [:wallet.swap/set-default-slippage]]]
[[:dispatch
[:show-bottom-sheet
{:content (fn []
[network-selection/view
{:token-symbol (:symbol asset-to-pay)
:on-select-network (fn [network]
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch
[:wallet.swap/start
{:asset-to-pay asset-to-pay
:asset-to-receive asset-to-receive
:network network
:open-new-screen?
open-new-screen?
:from-account from-account}]))}])}]]]))})))

(rf/reg-event-fx :wallet.swap/select-asset-to-pay
(fn [{:keys [db]} [{:keys [token]}]]
Expand Down Expand Up @@ -527,3 +536,15 @@
[:dispatch [:wallet/navigate-to-account-within-stack address]])
[:dispatch [:wallet/fetch-activities-for-current-account]]
[:dispatch [:wallet/select-account-tab :activity]]]})))

(rf/reg-event-fx :wallet.swap/start-from-account
(fn [{:keys [db]} [account]]
(let [asset-to-pay (get-in db [:wallet :ui :swap :asset-to-pay])
asset-to-receive (get-in db [:wallet :ui :swap :asset-to-receive])]
{:fx [[:dispatch [:dismiss-modal :screen/wallet.swap-select-account]]
[:dispatch
[:wallet.swap/start
{:asset-to-pay asset-to-pay
:asset-to-receive asset-to-receive
:open-new-screen? true
:from-account account}]]]})))
7 changes: 7 additions & 0 deletions src/status_im/contexts/wallet/swap/select_account/style.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
(ns status-im.contexts.wallet.swap.select-account.style)

(def accounts-list
{:padding-bottom 12})

(def accounts-list-container
{:padding-horizontal 8})
52 changes: 52 additions & 0 deletions src/status_im/contexts/wallet/swap/select_account/view.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
(ns status-im.contexts.wallet.swap.select-account.view
(:require
[quo.core :as quo]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.common.events-helper :as events-helper]
[status-im.common.floating-button-page.view :as floating-button-page]
[status-im.contexts.wallet.swap.select-account.style :as style]
[utils.i18n :as i18n]
[utils.money :as money]
[utils.re-frame :as rf]))

(defn- on-account-press
[account]
(rf/dispatch [:wallet.swap/start-from-account account]))

(defn- render-fn
[item _ _]
(let [has-balance (money/above-zero? (:asset-pay-balance item))]
[quo/account-item
{:type (if has-balance :tag :default)
:on-press #(on-account-press item)
:state (if has-balance :default :disabled)
:token-props {:symbol (:asset-pay-symbol item)
:value (:asset-pay-balance item)}
:account-props (assoc item
:address (:formatted-address item)
:full-address? true)}]))

(defn- on-close
[]
(rf/dispatch [:wallet/clean-current-viewing-account])
(events-helper/navigate-back))

(defn view
[]
(let [accounts (rf/sub [:wallet/accounts-with-balances])]
[floating-button-page/view
{:footer-container-padding 0
:header [quo/page-nav
{:margin-top (safe-area/get-top)
:icon-name :i/close
:on-press on-close}]}
[quo/page-top
{:title (i18n/label :t/from-label)
:title-accessibility-label :title-label}]
[rn/flat-list
{:style style/accounts-list
:content-container-style style/accounts-list-container
:data accounts
:render-fn render-fn
:shows-horizontal-scroll-indicator false}]]))
7 changes: 7 additions & 0 deletions src/status_im/navigation/screens.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
[status-im.contexts.wallet.send.send-amount.view :as wallet-send-input-amount]
[status-im.contexts.wallet.send.transaction-confirmation.view :as wallet-transaction-confirmation]
[status-im.contexts.wallet.send.transaction-progress.view :as wallet-transaction-progress]
[status-im.contexts.wallet.swap.select-account.view :as wallet-swap-select-account]
[status-im.contexts.wallet.swap.select-asset-to-pay.view :as wallet-swap-select-asset-to-pay]
[status-im.contexts.wallet.swap.set-spending-cap.view :as wallet-swap-set-spending-cap]
[status-im.contexts.wallet.swap.setup-swap.view :as wallet-swap-setup-swap]
Expand Down Expand Up @@ -635,6 +636,12 @@
:insets {:top? true}}
:component wallet-swap-select-asset-to-pay/view}

{:name :screen/wallet.swap-select-account
:metrics {:track? true}
:options {:modalPresentationStyle :overCurrentContext
:insets {:bottom? true}}
:component wallet-swap-select-account/view}

{:name :screen/wallet.setup-swap
:metrics {:track? true
:alias-id :wallet-swap.input-amount-to-swap}
Expand Down
9 changes: 1 addition & 8 deletions src/status_im/subs/wallet/networks.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
[utils.money :as money]
[utils.number :as number]))

(def max-network-prefixes 2)

(re-frame/reg-sub
:wallet/networks
:<- [:wallet]
Expand Down Expand Up @@ -53,12 +51,7 @@
(re-frame/reg-sub
:wallet/account-address
(fn [_ [_ address network-preferences]]
(let [short-names (map network-utils/network->short-name network-preferences)
prefix (when (<= (count short-names) max-network-prefixes)
(network-utils/short-names->network-preference-prefix
short-names))
transformed-address (str prefix address)]
transformed-address)))
(network-utils/format-address address network-preferences)))

(re-frame/reg-sub
:wallet/network-values
Expand Down
Loading

0 comments on commit 21c2a52

Please sign in to comment.