From aa4871e4888d9cf487bc926600a976c4752536e9 Mon Sep 17 00:00:00 2001 From: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com> Date: Thu, 26 Dec 2024 16:41:43 +0530 Subject: [PATCH] fix(wallet)_: Send flow for collectibles Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com> --- .../contexts/wallet/collectible/events.cljs | 5 +- .../contexts/wallet/collectible/utils.cljs | 23 ++++-- .../contexts/wallet/collectible/view.cljs | 16 +++-- src/status_im/contexts/wallet/data_store.cljs | 1 + src/status_im/contexts/wallet/events.cljs | 7 +- .../contexts/wallet/send/events.cljs | 72 ++++++++++++------- .../contexts/wallet/send/events_test.cljs | 14 ++-- .../contexts/wallet/send/from/view.cljs | 48 +++++++++---- src/status_im/subs/wallet/wallet.cljs | 11 +++ 9 files changed, 131 insertions(+), 66 deletions(-) diff --git a/src/status_im/contexts/wallet/collectible/events.cljs b/src/status_im/contexts/wallet/collectible/events.cljs index 219a27540ad..2d01997f248 100644 --- a/src/status_im/contexts/wallet/collectible/events.cljs +++ b/src/status_im/contexts/wallet/collectible/events.cljs @@ -254,7 +254,6 @@ ownership-status (get ownership-status-by-address owner-address) collectibles (->> collectibles data-store/rpc->collectibles - (map #(update % :ownership distinct)) vec) pending-requests (dec (get-in db [:wallet :ui :collectibles :pending-requests])) ;; check if collectibles are updating (never fetched and cached before) for this address @@ -323,7 +322,9 @@ (merge-with keep-not-empty-value c collectible) - (update c :ownership distinct))] + (update c + :ownership + collectible-utils/remove-duplicates-in-ownership))] (if collectible {:db (assoc-in db [:wallet :ui :collectible :details] merged-collectible)} (log/error "failed to get collectible details" diff --git a/src/status_im/contexts/wallet/collectible/utils.cljs b/src/status_im/contexts/wallet/collectible/utils.cljs index 9ba524eda30..f6d2bcb411a 100644 --- a/src/status_im/contexts/wallet/collectible/utils.cljs +++ b/src/status_im/contexts/wallet/collectible/utils.cljs @@ -5,13 +5,11 @@ [taoensso.timbre :as log])) (defn collectible-balance - [collectible] - (let [balance (-> collectible - :ownership - first - :balance - js/parseInt)] - (if (js/Number.isNaN balance) 0 balance))) + ([{:keys [ownership]} address] + (let [balance (some #(when (= address (:address %)) + (js/parseInt (:balance %))) + ownership)] + (if (js/Number.isNaN balance) 0 balance)))) (def supported-collectible-types #{"image/jpeg" @@ -69,3 +67,14 @@ contract-address (-> id :contract-id :address) token-id (-> id :token-id)] (str chain-id contract-address token-id))) + +(defn remove-duplicates-in-ownership + [ownership] + (->> ownership + (reduce (fn [acc {:keys [address timestamp] :as owner}] + (let [existing-owner (get acc address)] + (if (or (nil? existing-owner) (> timestamp (:timestamp existing-owner))) + (assoc acc address owner) + acc))) + {}) + vals)) diff --git a/src/status_im/contexts/wallet/collectible/view.cljs b/src/status_im/contexts/wallet/collectible/view.cljs index 30e8e97712f..e10d8fc03f1 100644 --- a/src/status_im/contexts/wallet/collectible/view.cljs +++ b/src/status_im/contexts/wallet/collectible/view.cljs @@ -38,7 +38,15 @@ (defn cta-buttons [{:keys [chain-id token-id contract-address collectible watch-only?]}] - (let [theme (quo.theme/use-theme)] + (let [theme (quo.theme/use-theme) + on-press-send (rn/use-callback + (fn [] + (rf/dispatch [:wallet/clean-send-data]) + (rf/dispatch + [:wallet/set-collectible-to-send + {:collectible collectible + :start-flow? true + :current-screen :screen/wallet.collectible}])))] [rn/view {:style style/buttons-container} (when-not watch-only? [quo/button @@ -46,11 +54,7 @@ :type :outline :size 40 :icon-left :i/send - :on-press #(rf/dispatch - [:wallet/set-collectible-to-send - {:collectible collectible - :start-flow? true - :current-screen :screen/wallet.collectible}])} + :on-press on-press-send} (i18n/label :t/send)]) [quo/button {:container-style style/opensea-button diff --git a/src/status_im/contexts/wallet/data_store.cljs b/src/status_im/contexts/wallet/data_store.cljs index e17bed38c95..302a60f5007 100644 --- a/src/status_im/contexts/wallet/data_store.cljs +++ b/src/status_im/contexts/wallet/data_store.cljs @@ -289,6 +289,7 @@ [collectibles] (->> collectibles (cske/transform-keys transforms/->kebab-case-keyword) + (map #(update % :ownership collectible-utils/remove-duplicates-in-ownership)) (map #(assoc % :unique-id (collectible-utils/get-collectible-unique-id %))) vec)) diff --git a/src/status_im/contexts/wallet/events.cljs b/src/status_im/contexts/wallet/events.cljs index db34ec30ada..903687c733d 100644 --- a/src/status_im/contexts/wallet/events.cljs +++ b/src/status_im/contexts/wallet/events.cljs @@ -78,15 +78,16 @@ (rf/reg-event-fx :wallet/clean-current-viewing-account (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)] + (let [{:keys [entry-point just-completed-transaction? + collectible-multiple-owners?]} (-> 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? + (and entry-point-wallet-home? (not collectible-multiple-owners?)) (update-in [:wallet :ui :send] dissoc :entry-point) (and entry-point-wallet-home? diff --git a/src/status_im/contexts/wallet/send/events.cljs b/src/status_im/contexts/wallet/send/events.cljs index cbf1fd7e512..e7c1f673aa8 100644 --- a/src/status_im/contexts/wallet/send/events.cljs +++ b/src/status_im/contexts/wallet/send/events.cljs @@ -120,12 +120,13 @@ :wallet/select-send-address (fn [{:keys [db]} [{:keys [address recipient stack-id start-flow?]}]] (let [[_ to-address] (utils/split-prefix-and-address address) + sender (get-in db [:wallet :current-viewing-account-address]) collectible-tx? (send-utils/tx-type-collectible? (-> db :wallet :ui :send :tx-type)) collectible (when collectible-tx? (-> db :wallet :ui :send :collectible)) one-collectible? (when collectible-tx? - (= (collectible.utils/collectible-balance collectible) 1))] + (= (collectible.utils/collectible-balance collectible sender) 1))] {:db (-> db (assoc-in [:wallet :ui :send :recipient] (or recipient address)) (assoc-in [:wallet :ui :send :to-address] to-address)) @@ -180,7 +181,6 @@ (:chain-id (first networks-with-balance))) network-details)) network)] - (println multi-account-balance? "43247329479847392") (when (or token-data token-symbol) {:db (cond-> db network (update-in [:wallet :ui :send] @@ -257,16 +257,22 @@ {:db (update-in db [:wallet :ui :send] dissoc :token :token-display-name :tx-type)})) (rf/reg-event-fx :wallet/clean-selected-collectible - (fn [{:keys [db]}] - (let [transaction-type (get-in db [:wallet :ui :send :tx-type])] - {:db (update-in db - [:wallet :ui :send] - dissoc - :collectible - :token-display-name - :amount - (when (send-utils/tx-type-collectible? transaction-type) - :tx-type))}))) + (fn [{:keys [db]} [{:keys [ignore-entry-point?]}]] + (let [entry-point-wallet-home? (= (get-in db [:wallet :ui :send :entry-point]) :wallet-stack) + multiple-owners? (get-in db [:wallet :ui :send :collectible-multiple-owners?]) + transaction-type (get-in db [:wallet :ui :send :tx-type])] + (when (or ignore-entry-point? + (and entry-point-wallet-home? (not multiple-owners?)) + (not entry-point-wallet-home?)) + {:db (update-in db + [:wallet :ui :send] + dissoc + :collectible + :collectible-multiple-owners? + :token-display-name + :amount + (when (send-utils/tx-type-collectible? transaction-type) + :tx-type))})))) (rf/reg-event-fx :wallet/set-collectible-to-send @@ -283,7 +289,10 @@ :tx/collectible-erc-1155 :tx/collectible-erc-721) collectible-id (get-in collectible [:id :token-id]) - one-collectible? (= (collectible.utils/collectible-balance collectible) 1) + single-owner? (-> collectible :ownership count (= 1)) + owner-address (-> collectible :ownership first :address) + one-collectible? (when single-owner? + (= (collectible.utils/collectible-balance collectible owner-address) 1)) token-display-name (cond (and collectible (not (string/blank? (:name collectible-data)))) @@ -291,29 +300,37 @@ collectible (str (:name collection-data) " #" collectible-id)) - owner-address (-> db :wallet :current-viewing-account-address) collectible-tx (-> db (update-in [:wallet :ui :send] dissoc :token) + (assoc-in [:wallet :ui :send :entry-point] entry-point) (assoc-in [:wallet :ui :send :collectible] collectible) + (assoc-in [:wallet :ui :send :collectible-multiple-owners?] + (not single-owner?)) (assoc-in [:wallet :ui :send :token-display-name] token-display-name) (assoc-in [:wallet :ui :send :tx-type] tx-type)) recipient-set? (-> db :wallet :ui :send :recipient)] {:db (cond-> collectible-tx - :always - (assoc-in [:wallet :ui :send :entry-point] entry-point) - (not viewing-account?) + (and (not viewing-account?) single-owner?) (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/start-get-suggested-routes {:amount 1}]]) - [:dispatch - [:wallet/wizard-navigate-forward - {:current-screen current-screen - :start-flow? start-flow? - :flow-id :wallet-send-flow}]]]}))) + :fx (if + ;; If the is present in multiple accounts, the user will be taken to select the address + ;; to send from + (and (not viewing-account?) (not single-owner?)) + [[:dispatch [:open-modal :screen/wallet.select-from]]] + + + [(when (and one-collectible? recipient-set?) + [:dispatch [:wallet/start-get-suggested-routes {:amount 1}]]) + + [:dispatch + [:wallet/wizard-navigate-forward + {:current-screen current-screen + :start-flow? start-flow? + :flow-id :wallet-send-flow}]]])}))) (rf/reg-event-fx :wallet/set-collectible-amount-to-send @@ -673,11 +690,12 @@ (fn [{db :db} [{:keys [address stack-id network-details network start-flow?] :as params}]] (let [{:keys [token-symbol tx-type]} (-> db :wallet :ui :send) + collectible-tx? (send-utils/tx-type-collectible? tx-type) token (when token-symbol ;; When this flow has started in the wallet home page, we ;; know the token or collectible to send, but we don't know - ;; from which account, so we extract the token data from the - ;; picked account. + ;; from which account, so we extract the token data from + ;; the picked account. (let [token (utils/get-token-from-account db token-symbol address)] @@ -704,7 +722,7 @@ network (assoc-in [:wallet :ui :send :network] network) token-symbol (assoc-in [:wallet :ui :send :token] token) bridge-tx? (assoc-in [:wallet :ui :send :to-address] address)) - :fx (if (some? network) + :fx (if (or (some? network) collectible-tx?) [[:dispatch [:wallet/switch-current-viewing-account address]] [:dispatch [:wallet/wizard-navigate-forward diff --git a/src/status_im/contexts/wallet/send/events_test.cljs b/src/status_im/contexts/wallet/send/events_test.cljs index 574bb002279..4a18589c75b 100644 --- a/src/status_im/contexts/wallet/send/events_test.cljs +++ b/src/status_im/contexts/wallet/send/events_test.cljs @@ -321,9 +321,10 @@ :start-flow? start-flow? :flow-id :wallet-send-flow}]]]}] (reset! rf-db/app-db - {:wallet {:ui {:send {:other-props :value - :tx-type tx-type - :collectible collectible}}} + {:wallet {:current-viewing-account-address "0x01" + :ui {:send {:other-props :value + :tx-type tx-type + :collectible collectible}}} :profile/profile {:test-networks-enabled? testnet-enabled?}}) (is (match? expected-result (dispatch [event-id @@ -347,9 +348,10 @@ :start-flow? start-flow? :flow-id :wallet-send-flow}]]]}] (reset! rf-db/app-db - {:wallet {:ui {:send {:other-props :value - :tx-type tx-type - :collectible collectible}}} + {:wallet {:current-viewing-account-address "0x01" + :ui {:send {:other-props :value + :tx-type tx-type + :collectible collectible}}} :profile/profile {:test-networks-enabled? testnet-enabled?}}) (is (match? expected-result (dispatch [event-id diff --git a/src/status_im/contexts/wallet/send/from/view.cljs b/src/status_im/contexts/wallet/send/from/view.cljs index 37fb2639870..0296dffd5e8 100644 --- a/src/status_im/contexts/wallet/send/from/view.cljs +++ b/src/status_im/contexts/wallet/send/from/view.cljs @@ -5,40 +5,56 @@ [react-native.core :as rn] [react-native.safe-area :as safe-area] [status-im.common.floating-button-page.view :as floating-button-page] + [status-im.contexts.wallet.collectible.utils :as collectible-utils] [status-im.contexts.wallet.common.account-switcher.view :as account-switcher] [status-im.contexts.wallet.send.from.style :as style] + [status-im.setup.hot-reload :as hot-reload] [utils.i18n :as i18n] [utils.money :as money] [utils.re-frame :as rf])) (defn- on-account-press - [address network-details] + [address network-details collectible-tx?] (rf/dispatch [:wallet/select-from-account {:address address :network-details network-details :stack-id :screen/wallet.select-from - :start-flow? true}])) + :start-flow? (not collectible-tx?)}])) + +(defn- on-close + [] + (rf/dispatch [:wallet/clean-selected-collectible {:ignore-entry-point? true}]) + (rf/dispatch [:wallet/clean-current-viewing-account])) (defn- render-fn - [item _ _ {:keys [network-details]}] - (let [has-balance (money/above-zero? (string/replace-first (:asset-pay-balance item) "<" ""))] + [item _ _ {:keys [network-details collectible-tx? collectible]}] + (let [account-address (:address item) + balance (if collectible-tx? + (collectible-utils/collectible-balance collectible account-address) + (string/replace-first (:asset-pay-balance item) "<" "")) + has-balance? (money/above-zero? balance) + asset-symbol (if collectible-tx? "" (:asset-pay-symbol item)) + asset-value (if collectible-tx? (str balance) (:asset-pay-balance item))] [quo/account-item - {:type (if has-balance :tag :default) - :on-press #(on-account-press (:address item) network-details) - :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)}])) + {:type (if has-balance? :tag :default) + :on-press #(on-account-press account-address network-details collectible-tx?) + :state (if has-balance? :default :disabled) + :token-props {:symbol asset-symbol + :value asset-value} + :account-props item}])) (defn view [] - (let [token-symbol (rf/sub [:wallet/send-token-symbol]) + (let [collectible-tx? (rf/sub [:wallet/send-tx-type-collectible?]) + token-symbol (rf/sub [:wallet/send-token-symbol]) token (rf/sub [:wallet/token-by-symbol-from-first-available-account-with-balance token-symbol]) - accounts (rf/sub [:wallet/accounts-with-balances token]) + collectible (rf/sub [:wallet/wallet-send-collectible]) + accounts (if collectible-tx? + (rf/sub [:wallet/operable-accounts]) + (rf/sub [:wallet/accounts-with-balances token])) network-details (rf/sub [:wallet/network-details])] + (hot-reload/use-safe-unmount on-close) [floating-button-page/view {:footer-container-padding 0 :header [account-switcher/view @@ -52,6 +68,8 @@ {:style style/accounts-list :content-container-style style/accounts-list-container :data accounts - :render-data {:network-details network-details} + :render-data {:network-details network-details + :collectible-tx? collectible-tx? + :collectible collectible} :render-fn render-fn :shows-horizontal-scroll-indicator false}]])) diff --git a/src/status_im/subs/wallet/wallet.cljs b/src/status_im/subs/wallet/wallet.cljs index e62ce1fc177..e92c1193941 100644 --- a/src/status_im/subs/wallet/wallet.cljs +++ b/src/status_im/subs/wallet/wallet.cljs @@ -167,6 +167,11 @@ :<- [:wallet/wallet-send] :-> :enough-assets?) +(rf/reg-sub + :wallet/wallet-send-collectible + :<- [:wallet/wallet-send] + :-> :collectible) + (rf/reg-sub :wallet/wallet-send-token :<- [:wallet/wallet-send] @@ -235,6 +240,12 @@ :<- [:wallet/wallet-send] :-> :tx-type) +(rf/reg-sub + :wallet/send-tx-type-collectible? + :<- [:wallet/wallet-send-tx-type] + (fn [tx-type] + (send-utils/tx-type-collectible? tx-type))) + (rf/reg-sub :wallet/keypairs :<- [:wallet]