From e4639c153f4ff499fd4aa535fd92ad4291e6644e Mon Sep 17 00:00:00 2001 From: Ulises Manuel <90291778+ulisesmac@users.noreply.github.com> Date: Tue, 23 Jul 2024 16:08:33 -0600 Subject: [PATCH] feat(wallet): Skip From page while sending an asset only owned by one account (#20773) - Update tests - Omit from page while sending a token in home page - Hide send and bridge option for not owned tokens - Fix subscription to return accounts owning an asset --- .../addresses_for_permissions/view.cljs | 2 +- .../wallet/common/token_value/view.cljs | 23 ++++--- src/status_im/contexts/wallet/events.cljs | 19 ++++-- .../wallet/home/tabs/assets/view.cljs | 1 + .../contexts/wallet/send/events.cljs | 60 ++++++++++++------- .../contexts/wallet/send/from/view.cljs | 1 - .../wallet/send/select_address/view.cljs | 4 +- .../wallet/sheets/select_account/view.cljs | 2 +- .../wallet_connect/session_proposal/view.cljs | 2 +- .../subs/community/account_selection.cljs | 4 +- src/status_im/subs/wallet/wallet.cljs | 53 ++++++++++++---- src/status_im/subs/wallet/wallet_test.cljs | 30 +++++++--- 12 files changed, 140 insertions(+), 61 deletions(-) diff --git a/src/status_im/contexts/communities/actions/addresses_for_permissions/view.cljs b/src/status_im/contexts/communities/actions/addresses_for_permissions/view.cljs index 591c89233c..cef25d3846 100644 --- a/src/status_im/contexts/communities/actions/addresses_for_permissions/view.cljs +++ b/src/status_im/contexts/communities/actions/addresses_for_permissions/view.cljs @@ -262,7 +262,7 @@ can-edit-addresses? (rf/sub [:communities/can-edit-shared-addresses? id]) - wallet-accounts (rf/sub [:wallet/operable-accounts-without-watched-accounts]) + wallet-accounts (rf/sub [:wallet/operable-accounts]) joined (rf/sub [:communities/community-joined id]) unmodified-addresses-to-reveal (rf/sub [:communities/addresses-to-reveal id]) [addresses-to-reveal set-addresses-to-reveal] (rn/use-state unmodified-addresses-to-reveal) 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 078eaf5507..0dffb3dc94 100644 --- a/src/status_im/contexts/wallet/common/token_value/view.cljs +++ b/src/status_im/contexts/wallet/common/token_value/view.cljs @@ -16,14 +16,14 @@ :right-icon :i/external}) (defn- action-send - [send-params] + [send-params entry-point] {:icon :i/send :accessibility-label :send :label (i18n/label :t/send) :on-press (fn [] (rf/dispatch [:hide-bottom-sheet]) (rf/dispatch [:wallet/clean-send-data]) - (rf/dispatch [:wallet/set-token-to-send send-params]))}) + (rf/dispatch [:wallet/set-token-to-send send-params entry-point]))}) (defn- action-receive [selected-account?] @@ -66,36 +66,41 @@ :on-press #(js/alert "to be implemented")}) (defn token-value-drawer - [token watch-only?] + [token watch-only? entry-point] (let [token-symbol (:token token) token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered token-symbol])) selected-account? (rf/sub [:wallet/current-viewing-account-address]) + token-owners (rf/sub [:wallet/operable-addresses-with-token-symbol token-symbol]) send-or-bridge-params (if selected-account? {:token token-data :stack-id :screen/wallet.accounts - :start-flow? true} + :start-flow? true + :owners token-owners} {:token-symbol token-symbol :stack-id :wallet-stack - :start-flow? true})] + :start-flow? true + :owners token-owners})] [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) - (action-send send-or-bridge-params) + (when (seq token-owners) + (action-send send-or-bridge-params entry-point)) (action-receive selected-account?) (when (ff/enabled? ::ff/wallet.swap) (action-swap)) - (action-bridge send-or-bridge-params)]))]])) + (when (seq (seq token-owners)) + (action-bridge send-or-bridge-params))]))]])) (defn view - [item _ _ {:keys [watch-only?]}] + [item _ _ {:keys [watch-only? entry-point]}] [quo/token-value (cond-> item (or (not watch-only?) (ff/enabled? ::ff/wallet.long-press-watch-only-asset)) (assoc :on-long-press #(rf/dispatch [:show-bottom-sheet - {:content (fn [] [token-value-drawer item watch-only?]) + {:content (fn [] [token-value-drawer item watch-only? entry-point]) :selected-item (fn [] [quo/token-value item])}])))]) diff --git a/src/status_im/contexts/wallet/events.cljs b/src/status_im/contexts/wallet/events.cljs index 1bcdc760b3..ddd0104d1d 100644 --- a/src/status_im/contexts/wallet/events.cljs +++ b/src/status_im/contexts/wallet/events.cljs @@ -65,10 +65,21 @@ {:db (assoc-in db [:wallet :current-viewing-account-address] address)})) (rf/reg-event-fx :wallet/clean-current-viewing-account - (fn [{:keys [db]}] - (let [just-completed-transaction? (get-in db [:wallet :ui :send :just-completed-transaction?])] - (when-not just-completed-transaction? - {:db (update db :wallet dissoc :current-viewing-account-address)})))) + (fn [{:keys [db]} [ignore-just-completed-transaction?]] + (let [{:keys [entry-point just-completed-transaction?]} (-> db :wallet :ui :send) + entry-point-wallet-home? (= entry-point :wallet-stack)] + {:db (cond-> db + (and (not entry-point) + (not ignore-just-completed-transaction?) + (not just-completed-transaction?)) + (update :wallet dissoc :current-viewing-account-address) + + entry-point-wallet-home? + (update-in [:wallet :ui :send] dissoc :entry-point) + + (and entry-point-wallet-home? + (not just-completed-transaction?)) + (update :wallet dissoc :current-viewing-account-address))}))) (rf/reg-event-fx :wallet/close-account-page (fn [{:keys [db]}] diff --git a/src/status_im/contexts/wallet/home/tabs/assets/view.cljs b/src/status_im/contexts/wallet/home/tabs/assets/view.cljs index 0fd82dacae..4aaf664698 100644 --- a/src/status_im/contexts/wallet/home/tabs/assets/view.cljs +++ b/src/status_im/contexts/wallet/home/tabs/assets/view.cljs @@ -18,4 +18,5 @@ [rn/flat-list {:render-fn token-value/view :data tokens + :render-data {:entry-point :wallet-stack} :content-container-style style/list-container}]))) diff --git a/src/status_im/contexts/wallet/send/events.cljs b/src/status_im/contexts/wallet/send/events.cljs index b2d219b44c..0863879426 100644 --- a/src/status_im/contexts/wallet/send/events.cljs +++ b/src/status_im/contexts/wallet/send/events.cljs @@ -193,25 +193,35 @@ (rf/reg-event-fx :wallet/set-token-to-send - (fn [{:keys [db]} [{:keys [token-symbol token stack-id start-flow?]}]] + (fn [{:keys [db]} [{:keys [token-symbol token stack-id start-flow? owners]} entry-point]] ;; `token` is a map extracted from the sender, but in the wallet home page we don't know the ;; sender yet, so we only provide the `token-symbol`, later in ;; `:wallet/select-from-account` the `token` key will be set. - (let [{token-networks :networks} token - receiver-networks (get-in db [:wallet :ui :send :receiver-networks]) - token-networks-ids (mapv #(:chain-id %) token-networks) - token-not-supported-in-receiver-networks? (not-any? (set receiver-networks) - token-networks-ids)] - (when (or token token-symbol) + (let [{:keys [networks]} token + receiver-networks (get-in db [:wallet :ui :send :receiver-networks]) + token-networks-ids (map :chain-id networks) + unsupported-token? (not-any? (set receiver-networks) token-networks-ids) + unique-owner (when (= (count owners) 1) + (first owners)) + unique-owner-tokens (get-in db [:wallet :accounts unique-owner :tokens]) + token-data (or token + (when (and token-symbol unique-owner) + (some #(when (= (:symbol %) token-symbol) %) + unique-owner-tokens)))] + (when (or token-data token-symbol) {:db (cond-> db - :always (update-in [:wallet :ui :send] dissoc :collectible) - :always (assoc-in - [:wallet :ui :send :token-not-supported-in-receiver-networks?] - token-not-supported-in-receiver-networks?) - token (assoc-in [:wallet :ui :send :token] token) - token (assoc-in [:wallet :ui :send :token-display-name] - (:symbol token)) - token-symbol (assoc-in [:wallet :ui :send :token-symbol] token-symbol)) + :always (update-in [:wallet :ui :send] + #(-> % + (dissoc :collectible) + (assoc :token-not-supported-in-receiver-networks? + unsupported-token?))) + token-symbol (assoc-in [:wallet :ui :send :token-symbol] token-symbol) + token-data (update-in [:wallet :ui :send] + #(assoc % + :token token-data + :token-display-name (:symbol token-data))) + unique-owner (assoc-in [:wallet :current-viewing-account-address] unique-owner) + entry-point (assoc-in [:wallet :ui :send :entry-point] entry-point)) :fx [[:dispatch [:wallet/clean-suggested-routes]] [:dispatch [:wallet/wizard-navigate-forward @@ -225,9 +235,9 @@ (let [{token-networks :networks token-symbol :symbol} token receiver-networks (get-in db [:wallet :ui :send :receiver-networks]) - token-networks-ids (mapv #(:chain-id %) token-networks) - token-not-supported-in-receiver-networks? (not (some (set receiver-networks) - token-networks-ids))] + token-networks-ids (map :chain-id token-networks) + token-not-supported-in-receiver-networks? (not-any? (set receiver-networks) + token-networks-ids)] {:db (-> db (assoc-in [:wallet :ui :send :token] token) (assoc-in [:wallet :ui :send :token-display-name] token-symbol) @@ -256,7 +266,9 @@ (rf/reg-event-fx :wallet/set-collectible-to-send (fn [{db :db} [{:keys [collectible current-screen start-flow?]}]] - (let [collection-data (:collection-data collectible) + (let [viewing-account? (some? (-> db :wallet :current-viewing-account-address)) + entry-point (when-not viewing-account? :wallet-stack) + collection-data (:collection-data collectible) collectible-data (:collectible-data collectible) contract-type (:contract-type collectible) tx-type (if (= contract-type constants/wallet-contract-type-erc-1155) @@ -271,6 +283,7 @@ collectible (str (:name collection-data) " #" collectible-id)) + owner-address (-> collectible :ownership first :address) collectible-tx (-> db (update-in [:wallet :ui :send] dissoc :token) (assoc-in [:wallet :ui :send :collectible] collectible) @@ -278,7 +291,14 @@ (assoc-in [:wallet :ui :send :tx-type] tx-type)) recipient-set? (-> db :wallet :ui :send :recipient)] {:db (cond-> collectible-tx - one-collectible? (assoc-in [:wallet :ui :send :amount] 1)) + :always + (assoc-in [:wallet :ui :send :entry-point] entry-point) + + (not viewing-account?) + (assoc-in [:wallet :current-viewing-account-address] owner-address) + + one-collectible? + (assoc-in [:wallet :ui :send :amount] 1)) :fx [(when (and one-collectible? recipient-set?) [:dispatch [:wallet/get-suggested-routes {:amount 1}]]) [:dispatch diff --git a/src/status_im/contexts/wallet/send/from/view.cljs b/src/status_im/contexts/wallet/send/from/view.cljs index 43fc1b78a9..8dc110291a 100644 --- a/src/status_im/contexts/wallet/send/from/view.cljs +++ b/src/status_im/contexts/wallet/send/from/view.cljs @@ -42,7 +42,6 @@ {:on-press #(rf/dispatch [:navigate-back]) :margin-top (safe-area/get-top) :switcher-type :select-account}]} - [quo/page-top {:title (i18n/label :t/from-label) :title-accessibility-label :title-label}] diff --git a/src/status_im/contexts/wallet/send/select_address/view.cljs b/src/status_im/contexts/wallet/send/select_address/view.cljs index 8e7d0ca2ac..b16770b34e 100644 --- a/src/status_im/contexts/wallet/send/select_address/view.cljs +++ b/src/status_im/contexts/wallet/send/select_address/view.cljs @@ -177,7 +177,9 @@ (rf/dispatch [:wallet/clean-selected-collectible]) (rf/dispatch [:wallet/clean-send-address]) (rf/dispatch [:wallet/clean-disabled-from-networks]) - (rf/dispatch [:wallet/select-address-tab nil])) + (rf/dispatch [:wallet/select-address-tab nil]) + (rf/dispatch [:wallet/clean-current-viewing-account + :ignore-just-complete-transaction])) on-change-tab #(rf/dispatch [:wallet/select-address-tab %]) input-value (reagent/atom "") input-focused? (reagent/atom false)] diff --git a/src/status_im/contexts/wallet/sheets/select_account/view.cljs b/src/status_im/contexts/wallet/sheets/select_account/view.cljs index df468a6222..8f3da1294c 100644 --- a/src/status_im/contexts/wallet/sheets/select_account/view.cljs +++ b/src/status_im/contexts/wallet/sheets/select_account/view.cljs @@ -20,7 +20,7 @@ (defn view [] (let [selected-account-address (rf/sub [:wallet/current-viewing-account-address]) - accounts (rf/sub [:wallet/operable-accounts-without-watched-accounts])] + accounts (rf/sub [:wallet/operable-accounts])] [:<> [quo/drawer-top {:title (i18n/label :t/select-account)}] [gesture/flat-list diff --git a/src/status_im/contexts/wallet/wallet_connect/session_proposal/view.cljs b/src/status_im/contexts/wallet/wallet_connect/session_proposal/view.cljs index 42231f81d1..8e321bc067 100644 --- a/src/status_im/contexts/wallet/wallet_connect/session_proposal/view.cljs +++ b/src/status_im/contexts/wallet/wallet_connect/session_proposal/view.cljs @@ -70,7 +70,7 @@ (defn- accounts-list [] - (let [accounts (rf/sub [:wallet/operable-accounts-without-watched-accounts]) + (let [accounts (rf/sub [:wallet/operable-accounts]) selected-address (rf/sub [:wallet-connect/current-proposal-address])] [rn/view {:style style/account-switcher-list} (for [{:keys [address] :as account} accounts] diff --git a/src/status_im/subs/community/account_selection.cljs b/src/status_im/subs/community/account_selection.cljs index a4220067ef..8bc3bbb5ae 100644 --- a/src/status_im/subs/community/account_selection.cljs +++ b/src/status_im/subs/community/account_selection.cljs @@ -53,7 +53,7 @@ (re-frame/reg-sub :communities/accounts-to-reveal (fn [[_ community-id]] - [(re-frame/subscribe [:wallet/operable-accounts-without-watched-accounts]) + [(re-frame/subscribe [:wallet/operable-accounts]) (re-frame/subscribe [:communities/addresses-to-reveal community-id])]) (fn [[accounts addresses] _] (filter #(contains? addresses (:address %)) @@ -61,7 +61,7 @@ (re-frame/reg-sub :communities/airdrop-account (fn [[_ community-id]] - [(re-frame/subscribe [:wallet/operable-accounts-without-watched-accounts]) + [(re-frame/subscribe [:wallet/operable-accounts]) (re-frame/subscribe [:communities/airdrop-address community-id])]) (fn [[accounts airdrop-address] _] (->> accounts diff --git a/src/status_im/subs/wallet/wallet.cljs b/src/status_im/subs/wallet/wallet.cljs index bebb790b90..e9501df6ee 100644 --- a/src/status_im/subs/wallet/wallet.cljs +++ b/src/status_im/subs/wallet/wallet.cljs @@ -134,10 +134,12 @@ (:chain-id %)))) (map :chain-id) set)] - (assoc token - :networks (network-utils/network-list token networks) - :available-balance (utils/calculate-total-token-balance token) - :total-balance (utils/calculate-total-token-balance token enabled-from-chain-ids))))) + (some-> token + (assoc :networks (network-utils/network-list token networks) + :available-balance (utils/calculate-total-token-balance token) + :total-balance (utils/calculate-total-token-balance + token + enabled-from-chain-ids)))))) (rf/reg-sub :wallet/wallet-send-token-symbol @@ -464,22 +466,47 @@ keep-operable-accounts) (rf/reg-sub - :wallet/operable-accounts-without-watched-accounts + :wallet/operable-accounts :<- [:wallet/accounts-without-watched-accounts] keep-operable-accounts) +(rf/reg-sub + :wallet/operable-addresses-tokens-with-positive-balance + :<- [:wallet/operable-accounts] + (fn [accounts] + (let [positive-balance-in-any-chain? (fn [{:keys [balances-per-chain]}] + (->> balances-per-chain + (map (comp :raw-balance val)) + (some pos?)))] + (as-> accounts $ + (group-by :address $) + (update-vals $ #(filter positive-balance-in-any-chain? (:tokens (first %)))))))) + (rf/reg-sub :wallet/accounts-with-current-asset - :<- [:wallet/operable-accounts-without-watched-accounts] + :<- [:wallet/operable-accounts] + :<- [:wallet/operable-addresses-tokens-with-positive-balance] :<- [:wallet/wallet-send-token-symbol] :<- [:wallet/wallet-send-token] - (fn [[accounts token-symbol token]] - (let [asset-symbol (or token-symbol (:symbol token))] - (if asset-symbol - (filter (fn [account] - (some #(= (:symbol %) asset-symbol) (:tokens account))) - accounts) - accounts)))) + (fn [[accounts addresses-tokens token-symbol token]] + (if-let [asset-symbol (or token-symbol (:symbol token))] + (let [addresses-with-asset (as-> addresses-tokens $ + (update-vals $ #(set (map :symbol %))) + (keep (fn [[address token-symbols]] + (when (token-symbols asset-symbol) address)) + $) + (set $))] + (filter #(addresses-with-asset (:address %)) accounts)) + accounts))) + +(rf/reg-sub + :wallet/operable-addresses-with-token-symbol + :<- [:wallet/operable-addresses-tokens-with-positive-balance] + (fn [addresses-tokens [_ token-symbol]] + (keep (fn [[address tokens]] + (some #(when (= (:symbol %) token-symbol) address) + tokens)) + addresses-tokens))) (rf/reg-sub :wallet/account-tab diff --git a/src/status_im/subs/wallet/wallet_test.cljs b/src/status_im/subs/wallet/wallet_test.cljs index 5893fb6b62..571f6981ba 100644 --- a/src/status_im/subs/wallet/wallet_test.cljs +++ b/src/status_im/subs/wallet/wallet_test.cljs @@ -13,16 +13,22 @@ {:before #(reset! rf-db/app-db {})}) (def ^:private accounts-with-tokens - {:0x1 {:tokens [{:symbol "ETH"} {:symbol "SNT"}] + {:0x1 {:tokens [{:symbol "ETH" + :balances-per-chain {1 {:raw-balance "100"}}} + {:symbol "SNT" + :balances-per-chain {1 {:raw-balance "100"}}}] :network-preferences-names #{} :customization-color nil :operable? true - :operable :fully} - :0x2 {:tokens [{:symbol "SNT"}] + :operable :fully + :address "0x1"} + :0x2 {:tokens [{:symbol "SNT" + :balances-per-chain {1 {:raw-balance "200"}}}] :network-preferences-names #{} :customization-color nil :operable? true - :operable :partially}}) + :operable :partially + :address "0x2"}}) (def tokens-0x1 [{:decimals 1 @@ -495,11 +501,15 @@ (assoc-in [:wallet :ui :send :token-symbol] "ETH"))) (let [result (rf/sub [sub-name])] (is (match? result - [{:tokens [{:symbol "ETH"} {:symbol "SNT"}] + [{:tokens [{:symbol "ETH" + :balances-per-chain {1 {:raw-balance "100"}}} + {:symbol "SNT" + :balances-per-chain {1 {:raw-balance "100"}}}] :network-preferences-names #{} :customization-color nil :operable? true - :operable :fully}])))) + :operable :fully + :address "0x1"}])))) (testing "returns the accounts list with the current asset using token" (swap! rf-db/app-db @@ -508,11 +518,15 @@ (assoc-in [:wallet :ui :send :token] {:symbol "ETH"}))) (let [result (rf/sub [sub-name])] (is (match? result - [{:tokens [{:symbol "ETH"} {:symbol "SNT"}] + [{:tokens [{:symbol "ETH" + :balances-per-chain {1 {:raw-balance "100"}}} + {:symbol "SNT" + :balances-per-chain {1 {:raw-balance "100"}}}] :network-preferences-names #{} :customization-color nil :operable? true - :operable :fully}])))) + :operable :fully + :address "0x1"}])))) (testing "returns the full accounts list with the current asset using token-symbol if each account has the asset"