From f539bb5ca28e248686c4b2533ffc8ed83be44db1 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 30 Sep 2024 10:44:25 +0200 Subject: [PATCH] Swap flows (launch from home / launch from account) (#21269) * Swap flows (launch from home / launch from account) * Fixes * Lint fix --- .../wallet/common/token_value/view.cljs | 81 +++++++++---------- .../contexts/wallet/swap/events.cljs | 43 ++++++---- .../wallet/swap/select_asset_to_pay/view.cljs | 4 +- src/status_im/contexts/wallet/swap/utils.cljs | 61 +++++++++++--- 4 files changed, 119 insertions(+), 70 deletions(-) diff --git a/src/status_im/contexts/wallet/common/token_value/view.cljs b/src/status_im/contexts/wallet/common/token_value/view.cljs index e61af5ccb5..f698712230 100644 --- a/src/status_im/contexts/wallet/common/token_value/view.cljs +++ b/src/status_im/contexts/wallet/common/token_value/view.cljs @@ -1,6 +1,5 @@ (ns status-im.contexts.wallet.common.token-value.view (:require [quo.core :as quo] - [status-im.common.not-implemented :as not-implemented] [status-im.contexts.wallet.send.utils :as send-utils] [status-im.contexts.wallet.sheets.buy-token.view :as buy-token] [status-im.feature-flags :as ff] @@ -18,15 +17,15 @@ :right-icon :i/external}) (defn- action-send - [send-params entry-point] + [{:keys [disabled?] :as params} entry-point] {:icon :i/send :accessibility-label :send :label (i18n/label :t/send) - :disabled? (:disabled? send-params) + :disabled? disabled? :on-press (fn [] (rf/dispatch [:hide-bottom-sheet]) (rf/dispatch [:wallet/clean-send-data]) - (rf/dispatch [:wallet/set-token-to-send send-params entry-point]))}) + (rf/dispatch [:wallet/set-token-to-send params entry-point]))}) (defn- action-receive [selected-account?] @@ -38,21 +37,25 @@ #(rf/dispatch [:open-modal :screen/share-shell {:initial-tab :wallet}]))}) (defn- action-bridge - [bridge-params] + [{:keys [bridge-disabled?] :as params}] {:icon :i/bridge :accessibility-label :bridge :label (i18n/label :t/bridge) - :disabled? (:bridge-disabled? bridge-params) + :disabled? bridge-disabled? :on-press (fn [] (rf/dispatch [:hide-bottom-sheet]) - (rf/dispatch [:wallet/bridge-select-token bridge-params]))}) + (rf/dispatch [:wallet/bridge-select-token params]))}) (defn- action-swap - [] + [{:keys [token token-symbol]}] {:icon :i/swap :accessibility-label :swap :label (i18n/label :t/swap) - :on-press #(not-implemented/alert)}) + :on-press (fn [] + (rf/dispatch [:hide-bottom-sheet]) + (rf/dispatch [:wallet.swap/start + {:asset-to-pay (or token {:symbol token-symbol}) + :open-new-screen? true}]))}) (defn- action-manage-tokens [watch-only?] @@ -71,47 +74,37 @@ (defn token-value-drawer [token watch-only? entry-point] - (let [token-symbol (:token token) - token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered - {:query token-symbol}])) - fiat-unformatted-value (get-in token [:values :fiat-unformatted-value]) - has-balance? (money/greater-than fiat-unformatted-value (money/bignumber "0")) - selected-account? (rf/sub [:wallet/current-viewing-account-address]) - token-owners (rf/sub [:wallet/operable-addresses-with-token-symbol token-symbol]) - send-params (if selected-account? - {:token token-data - :stack-id :screen/wallet.accounts - :disabled? (not has-balance?) - :start-flow? true + (let [token-symbol (:token token) + token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered + {:query token-symbol}])) + selected-account (rf/sub [:wallet/current-viewing-account-address]) + token-owners (rf/sub [:wallet/operable-addresses-with-token-symbol token-symbol]) + params (cond-> {:start-flow? true :owners token-owners} - {:token-symbol token-symbol - :stack-id :wallet-stack - :start-flow? true - :owners token-owners}) - bridge-params (if selected-account? - {:token token-data - :bridge-disabled? (or (not has-balance?) - (send-utils/bridge-disabled? token-symbol)) - :stack-id :screen/wallet.accounts - :start-flow? true - :owners token-owners} - {:token-symbol token-symbol - :bridge-disabled? (send-utils/bridge-disabled? token-symbol) - :stack-id :wallet-stack - :start-flow? true - :owners token-owners})] + selected-account + (assoc :token token-data + :stack-id :screen/wallet.accounts + :has-balance? (-> (get-in token [:values :fiat-unformatted-value]) + (money/greater-than (money/bignumber "0")))) + (not selected-account) + (assoc :token-symbol token-symbol + :stack-id :wallet-stack))] [quo/action-drawer [(cond->> [(when (ff/enabled? ::ff/wallet.assets-modal-manage-tokens) (action-manage-tokens watch-only?)) (when (ff/enabled? ::ff/wallet.assets-modal-hide) (action-hide))] - (not watch-only?) (concat [(action-buy) - (when (seq token-owners) - (action-send send-params entry-point)) - (action-receive selected-account?) - (when (ff/enabled? ::ff/wallet.swap) (action-swap)) - (when (seq (seq token-owners)) - (action-bridge bridge-params))]))]])) + (not watch-only?) + (concat [(action-buy) + (when (seq token-owners) + (action-send params entry-point)) + (action-receive selected-account) + (when (ff/enabled? ::ff/wallet.swap) + (action-swap params)) + (when (seq token-owners) + (action-bridge (assoc params + :bridge-disabled? + (send-utils/bridge-disabled? token-symbol))))]))]])) (defn view [item _ _ {:keys [watch-only? entry-point]}] diff --git a/src/status_im/contexts/wallet/swap/events.cljs b/src/status_im/contexts/wallet/swap/events.cljs index a2bfdb2f20..57ced08ace 100644 --- a/src/status_im/contexts/wallet/swap/events.cljs +++ b/src/status_im/contexts/wallet/swap/events.cljs @@ -14,22 +14,36 @@ [utils.number :as number])) (rf/reg-event-fx :wallet.swap/start - (fn [{:keys [db]} [{:keys [asset-to-pay asset-to-receive network]}]] - (let [asset-to-receive' (or asset-to-receive - (swap-utils/select-asset-to-receive - (:wallet db) - (:profile/profile db) - asset-to-pay)) - network' (or network - (swap-utils/select-network asset-to-pay))] + (fn [{:keys [db]} [{:keys [network open-new-screen?] :as data}]] + (let [{:keys [wallet]} db + test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?]) + 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])})) + asset-to-receive (or (:asset-to-receive data) + (swap-utils/select-default-asset-to-receive + {:wallet wallet + :account account + :test-networks-enabled? test-networks-enabled? + :asset-to-pay asset-to-pay})) + network' (or network + (swap-utils/select-network asset-to-pay))] {:db (-> db (assoc-in [:wallet :ui :swap :asset-to-pay] asset-to-pay) - (assoc-in [:wallet :ui :swap :asset-to-receive] asset-to-receive') + (assoc-in [:wallet :ui :swap :asset-to-receive] asset-to-receive) (assoc-in [:wallet :ui :swap :network] network')) :fx (if network' - [[:dispatch - [:navigate-to-within-stack - [:screen/wallet.setup-swap :screen/wallet.swap-select-asset-to-pay]]] + [[:dispatch [:wallet/switch-current-viewing-account (:address account)]] + [:dispatch + (if open-new-screen? + [:navigate-to :screen/wallet.setup-swap] + [:navigate-to-within-stack + [:screen/wallet.setup-swap :screen/wallet.swap-select-asset-to-pay]])] [:dispatch [:wallet.swap/set-default-slippage]]] [[:dispatch [:show-bottom-sheet @@ -41,8 +55,9 @@ (rf/dispatch [:wallet.swap/start {:asset-to-pay asset-to-pay - :asset-to-receive asset-to-receive' - :network network}]))}])}]]])}))) + :asset-to-receive asset-to-receive + :network network + :open-new-screen? open-new-screen?}]))}])}]]])}))) (rf/reg-event-fx :wallet.swap/select-asset-to-pay (fn [{:keys [db]} [{:keys [token]}]] diff --git a/src/status_im/contexts/wallet/swap/select_asset_to_pay/view.cljs b/src/status_im/contexts/wallet/swap/select_asset_to_pay/view.cljs index a6937bfd17..16c3c8b3bd 100644 --- a/src/status_im/contexts/wallet/swap/select_asset_to_pay/view.cljs +++ b/src/status_im/contexts/wallet/swap/select_asset_to_pay/view.cljs @@ -21,7 +21,9 @@ (defn- assets-view [search-text on-change-text] (let [on-token-press (fn [token] - (rf/dispatch [:wallet.swap/start {:asset-to-pay token}]))] + (rf/dispatch [:wallet.swap/start + {:asset-to-pay token + :open-new-screen? false}]))] [:<> [search-input search-text on-change-text] [asset-list/view diff --git a/src/status_im/contexts/wallet/swap/utils.cljs b/src/status_im/contexts/wallet/swap/utils.cljs index f9c97a38e8..171c77021d 100644 --- a/src/status_im/contexts/wallet/swap/utils.cljs +++ b/src/status_im/contexts/wallet/swap/utils.cljs @@ -30,22 +30,61 @@ :else (i18n/label :t/something-went-wrong-please-try-again-later))) -(defn select-asset-to-receive - [wallet profile asset-to-pay] - (let [wallet-address (get-in wallet [:current-viewing-account-address]) - account (-> wallet - :accounts - vals - (utils/get-account-by-address wallet-address)) - test-networks-enabled? (get profile :test-networks-enabled?) - networks (-> (get-in wallet - [:wallet :networks (if test-networks-enabled? :test :prod)]) - (network-utils/sorted-networks-with-details))] +(defn- first-operable-account + [accounts] + (->> accounts + vals + (remove :watch-only?) + (filter :operable?) + (sort-by :position) + first)) + +(defn wallet-account + "Picks the account that's gonna be used for the swap operation. + It's gonna be either the preselected account defined by + `[:wallet :current-viewing-account-address]` in `db` + or the first operable account." + [wallet] + (if-let [wallet-address (get wallet :current-viewing-account-address)] + (-> wallet + :accounts + vals + (utils/get-account-by-address wallet-address)) + (-> wallet :accounts first-operable-account))) + +(defn select-asset-to-pay-by-symbol + "Selects an asset to pay by token symbol. + It's used for cases when only token symbol is available and the information + about token needs to be extracted from the database. + That happens when token is being selected on the home screen and + it basically indicates that no account pre-selection was made." + [{:keys [wallet account test-networks-enabled? token-symbol]}] + (let [networks (-> (get-in wallet [:networks (if test-networks-enabled? :test :prod)]) + (network-utils/sorted-networks-with-details)) + token (->> account + :tokens + (filter #(= token-symbol (:symbol %))) + first)] + (assoc token :networks (network-utils/network-list token networks)))) + +(defn select-default-asset-to-receive + "Selects an asset to receive if it was not provided explicitly. + The principle of how the asset is being selected is simple: we get the + whole list, remove the currently selected `asset-to-pay` from it, and choose + the first one of what's left." + [{:keys [wallet account test-networks-enabled? asset-to-pay]}] + (let [networks (-> (get-in wallet [:networks (if test-networks-enabled? :test :prod)]) + (network-utils/sorted-networks-with-details))] (->> (utils/tokens-with-balance (:tokens account) networks nil) (remove #(= (:symbol %) (:symbol asset-to-pay))) first))) (defn select-network + "Chooses the network. + Usually user needs to do the selection first and if the selection was done + then the list of networks for the defined token will always contain + one entry. Otherwise `nil` will be returned from here which will serve + as an indicator that the network selector needs to be displayed." [{:keys [networks]}] (when (= (count networks) 1) (first networks)))