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
This commit is contained in:
Ulises Manuel 2024-07-23 16:08:33 -06:00 committed by GitHub
parent 8597b899bd
commit e4639c153f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 140 additions and 61 deletions

View File

@ -262,7 +262,7 @@
can-edit-addresses? (rf/sub [:communities/can-edit-shared-addresses? id]) 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]) joined (rf/sub [:communities/community-joined id])
unmodified-addresses-to-reveal (rf/sub [:communities/addresses-to-reveal 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) [addresses-to-reveal set-addresses-to-reveal] (rn/use-state unmodified-addresses-to-reveal)

View File

@ -16,14 +16,14 @@
:right-icon :i/external}) :right-icon :i/external})
(defn- action-send (defn- action-send
[send-params] [send-params entry-point]
{:icon :i/send {:icon :i/send
:accessibility-label :send :accessibility-label :send
:label (i18n/label :t/send) :label (i18n/label :t/send)
:on-press (fn [] :on-press (fn []
(rf/dispatch [:hide-bottom-sheet]) (rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:wallet/clean-send-data]) (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 (defn- action-receive
[selected-account?] [selected-account?]
@ -66,36 +66,41 @@
:on-press #(js/alert "to be implemented")}) :on-press #(js/alert "to be implemented")})
(defn token-value-drawer (defn token-value-drawer
[token watch-only?] [token watch-only? entry-point]
(let [token-symbol (:token token) (let [token-symbol (:token token)
token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered
token-symbol])) token-symbol]))
selected-account? (rf/sub [:wallet/current-viewing-account-address]) 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? send-or-bridge-params (if selected-account?
{:token token-data {:token token-data
:stack-id :screen/wallet.accounts :stack-id :screen/wallet.accounts
:start-flow? true} :start-flow? true
:owners token-owners}
{:token-symbol token-symbol {:token-symbol token-symbol
:stack-id :wallet-stack :stack-id :wallet-stack
:start-flow? true})] :start-flow? true
:owners token-owners})]
[quo/action-drawer [quo/action-drawer
[(cond->> [(when (ff/enabled? ::ff/wallet.assets-modal-manage-tokens) [(cond->> [(when (ff/enabled? ::ff/wallet.assets-modal-manage-tokens)
(action-manage-tokens watch-only?)) (action-manage-tokens watch-only?))
(when (ff/enabled? ::ff/wallet.assets-modal-hide) (when (ff/enabled? ::ff/wallet.assets-modal-hide)
(action-hide))] (action-hide))]
(not watch-only?) (concat [(action-buy) (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?) (action-receive selected-account?)
(when (ff/enabled? ::ff/wallet.swap) (action-swap)) (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 (defn view
[item _ _ {:keys [watch-only?]}] [item _ _ {:keys [watch-only? entry-point]}]
[quo/token-value [quo/token-value
(cond-> item (cond-> item
(or (not watch-only?) (ff/enabled? ::ff/wallet.long-press-watch-only-asset)) (or (not watch-only?) (ff/enabled? ::ff/wallet.long-press-watch-only-asset))
(assoc :on-long-press (assoc :on-long-press
#(rf/dispatch #(rf/dispatch
[:show-bottom-sheet [: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])}])))]) :selected-item (fn [] [quo/token-value item])}])))])

View File

@ -65,10 +65,21 @@
{:db (assoc-in db [:wallet :current-viewing-account-address] address)})) {:db (assoc-in db [:wallet :current-viewing-account-address] address)}))
(rf/reg-event-fx :wallet/clean-current-viewing-account (rf/reg-event-fx :wallet/clean-current-viewing-account
(fn [{:keys [db]}] (fn [{:keys [db]} [ignore-just-completed-transaction?]]
(let [just-completed-transaction? (get-in db [:wallet :ui :send :just-completed-transaction?])] (let [{:keys [entry-point just-completed-transaction?]} (-> db :wallet :ui :send)
(when-not just-completed-transaction? entry-point-wallet-home? (= entry-point :wallet-stack)]
{:db (update db :wallet dissoc :current-viewing-account-address)})))) {: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 (rf/reg-event-fx :wallet/close-account-page
(fn [{:keys [db]}] (fn [{:keys [db]}]

View File

@ -18,4 +18,5 @@
[rn/flat-list [rn/flat-list
{:render-fn token-value/view {:render-fn token-value/view
:data tokens :data tokens
:render-data {:entry-point :wallet-stack}
:content-container-style style/list-container}]))) :content-container-style style/list-container}])))

View File

@ -193,25 +193,35 @@
(rf/reg-event-fx (rf/reg-event-fx
:wallet/set-token-to-send :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 ;; `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 ;; sender yet, so we only provide the `token-symbol`, later in
;; `:wallet/select-from-account` the `token` key will be set. ;; `:wallet/select-from-account` the `token` key will be set.
(let [{token-networks :networks} token (let [{:keys [networks]} token
receiver-networks (get-in db [:wallet :ui :send :receiver-networks]) receiver-networks (get-in db [:wallet :ui :send :receiver-networks])
token-networks-ids (mapv #(:chain-id %) token-networks) token-networks-ids (map :chain-id networks)
token-not-supported-in-receiver-networks? (not-any? (set receiver-networks) unsupported-token? (not-any? (set receiver-networks) token-networks-ids)
token-networks-ids)] unique-owner (when (= (count owners) 1)
(when (or token token-symbol) (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 {:db (cond-> db
:always (update-in [:wallet :ui :send] dissoc :collectible) :always (update-in [:wallet :ui :send]
:always (assoc-in #(-> %
[:wallet :ui :send :token-not-supported-in-receiver-networks?] (dissoc :collectible)
token-not-supported-in-receiver-networks?) (assoc :token-not-supported-in-receiver-networks?
token (assoc-in [:wallet :ui :send :token] token) unsupported-token?)))
token (assoc-in [:wallet :ui :send :token-display-name] token-symbol (assoc-in [:wallet :ui :send :token-symbol] token-symbol)
(:symbol token)) token-data (update-in [:wallet :ui :send]
token-symbol (assoc-in [:wallet :ui :send :token-symbol] token-symbol)) #(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]] :fx [[:dispatch [:wallet/clean-suggested-routes]]
[:dispatch [:dispatch
[:wallet/wizard-navigate-forward [:wallet/wizard-navigate-forward
@ -225,9 +235,9 @@
(let [{token-networks :networks (let [{token-networks :networks
token-symbol :symbol} token token-symbol :symbol} token
receiver-networks (get-in db [:wallet :ui :send :receiver-networks]) receiver-networks (get-in db [:wallet :ui :send :receiver-networks])
token-networks-ids (mapv #(:chain-id %) token-networks) token-networks-ids (map :chain-id token-networks)
token-not-supported-in-receiver-networks? (not (some (set receiver-networks) token-not-supported-in-receiver-networks? (not-any? (set receiver-networks)
token-networks-ids))] token-networks-ids)]
{:db (-> db {:db (-> db
(assoc-in [:wallet :ui :send :token] token) (assoc-in [:wallet :ui :send :token] token)
(assoc-in [:wallet :ui :send :token-display-name] token-symbol) (assoc-in [:wallet :ui :send :token-display-name] token-symbol)
@ -256,7 +266,9 @@
(rf/reg-event-fx (rf/reg-event-fx
:wallet/set-collectible-to-send :wallet/set-collectible-to-send
(fn [{db :db} [{:keys [collectible current-screen start-flow?]}]] (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) collectible-data (:collectible-data collectible)
contract-type (:contract-type collectible) contract-type (:contract-type collectible)
tx-type (if (= contract-type constants/wallet-contract-type-erc-1155) tx-type (if (= contract-type constants/wallet-contract-type-erc-1155)
@ -271,6 +283,7 @@
collectible collectible
(str (:name collection-data) " #" collectible-id)) (str (:name collection-data) " #" collectible-id))
owner-address (-> collectible :ownership first :address)
collectible-tx (-> db collectible-tx (-> db
(update-in [:wallet :ui :send] dissoc :token) (update-in [:wallet :ui :send] dissoc :token)
(assoc-in [:wallet :ui :send :collectible] collectible) (assoc-in [:wallet :ui :send :collectible] collectible)
@ -278,7 +291,14 @@
(assoc-in [:wallet :ui :send :tx-type] tx-type)) (assoc-in [:wallet :ui :send :tx-type] tx-type))
recipient-set? (-> db :wallet :ui :send :recipient)] recipient-set? (-> db :wallet :ui :send :recipient)]
{:db (cond-> collectible-tx {: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?) :fx [(when (and one-collectible? recipient-set?)
[:dispatch [:wallet/get-suggested-routes {:amount 1}]]) [:dispatch [:wallet/get-suggested-routes {:amount 1}]])
[:dispatch [:dispatch

View File

@ -42,7 +42,6 @@
{:on-press #(rf/dispatch [:navigate-back]) {:on-press #(rf/dispatch [:navigate-back])
:margin-top (safe-area/get-top) :margin-top (safe-area/get-top)
:switcher-type :select-account}]} :switcher-type :select-account}]}
[quo/page-top [quo/page-top
{:title (i18n/label :t/from-label) {:title (i18n/label :t/from-label)
:title-accessibility-label :title-label}] :title-accessibility-label :title-label}]

View File

@ -177,7 +177,9 @@
(rf/dispatch [:wallet/clean-selected-collectible]) (rf/dispatch [:wallet/clean-selected-collectible])
(rf/dispatch [:wallet/clean-send-address]) (rf/dispatch [:wallet/clean-send-address])
(rf/dispatch [:wallet/clean-disabled-from-networks]) (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 %]) on-change-tab #(rf/dispatch [:wallet/select-address-tab %])
input-value (reagent/atom "") input-value (reagent/atom "")
input-focused? (reagent/atom false)] input-focused? (reagent/atom false)]

View File

@ -20,7 +20,7 @@
(defn view (defn view
[] []
(let [selected-account-address (rf/sub [:wallet/current-viewing-account-address]) (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)}] [quo/drawer-top {:title (i18n/label :t/select-account)}]
[gesture/flat-list [gesture/flat-list

View File

@ -70,7 +70,7 @@
(defn- accounts-list (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])] selected-address (rf/sub [:wallet-connect/current-proposal-address])]
[rn/view {:style style/account-switcher-list} [rn/view {:style style/account-switcher-list}
(for [{:keys [address] :as account} accounts] (for [{:keys [address] :as account} accounts]

View File

@ -53,7 +53,7 @@
(re-frame/reg-sub :communities/accounts-to-reveal (re-frame/reg-sub :communities/accounts-to-reveal
(fn [[_ community-id]] (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])]) (re-frame/subscribe [:communities/addresses-to-reveal community-id])])
(fn [[accounts addresses] _] (fn [[accounts addresses] _]
(filter #(contains? addresses (:address %)) (filter #(contains? addresses (:address %))
@ -61,7 +61,7 @@
(re-frame/reg-sub :communities/airdrop-account (re-frame/reg-sub :communities/airdrop-account
(fn [[_ community-id]] (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])]) (re-frame/subscribe [:communities/airdrop-address community-id])])
(fn [[accounts airdrop-address] _] (fn [[accounts airdrop-address] _]
(->> accounts (->> accounts

View File

@ -134,10 +134,12 @@
(:chain-id %)))) (:chain-id %))))
(map :chain-id) (map :chain-id)
set)] set)]
(assoc token (some-> token
:networks (network-utils/network-list token networks) (assoc :networks (network-utils/network-list token networks)
:available-balance (utils/calculate-total-token-balance token) :available-balance (utils/calculate-total-token-balance token)
:total-balance (utils/calculate-total-token-balance token enabled-from-chain-ids))))) :total-balance (utils/calculate-total-token-balance
token
enabled-from-chain-ids))))))
(rf/reg-sub (rf/reg-sub
:wallet/wallet-send-token-symbol :wallet/wallet-send-token-symbol
@ -464,22 +466,47 @@
keep-operable-accounts) keep-operable-accounts)
(rf/reg-sub (rf/reg-sub
:wallet/operable-accounts-without-watched-accounts :wallet/operable-accounts
:<- [:wallet/accounts-without-watched-accounts] :<- [:wallet/accounts-without-watched-accounts]
keep-operable-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 (rf/reg-sub
:wallet/accounts-with-current-asset :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-symbol]
:<- [:wallet/wallet-send-token] :<- [:wallet/wallet-send-token]
(fn [[accounts token-symbol token]] (fn [[accounts addresses-tokens token-symbol token]]
(let [asset-symbol (or token-symbol (:symbol token))] (if-let [asset-symbol (or token-symbol (:symbol token))]
(if asset-symbol (let [addresses-with-asset (as-> addresses-tokens $
(filter (fn [account] (update-vals $ #(set (map :symbol %)))
(some #(= (:symbol %) asset-symbol) (:tokens account))) (keep (fn [[address token-symbols]]
accounts) (when (token-symbols asset-symbol) address))
accounts)))) $)
(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 (rf/reg-sub
:wallet/account-tab :wallet/account-tab

View File

@ -13,16 +13,22 @@
{:before #(reset! rf-db/app-db {})}) {:before #(reset! rf-db/app-db {})})
(def ^:private accounts-with-tokens (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 #{} :network-preferences-names #{}
:customization-color nil :customization-color nil
:operable? true :operable? true
:operable :fully} :operable :fully
:0x2 {:tokens [{:symbol "SNT"}] :address "0x1"}
:0x2 {:tokens [{:symbol "SNT"
:balances-per-chain {1 {:raw-balance "200"}}}]
:network-preferences-names #{} :network-preferences-names #{}
:customization-color nil :customization-color nil
:operable? true :operable? true
:operable :partially}}) :operable :partially
:address "0x2"}})
(def tokens-0x1 (def tokens-0x1
[{:decimals 1 [{:decimals 1
@ -495,11 +501,15 @@
(assoc-in [:wallet :ui :send :token-symbol] "ETH"))) (assoc-in [:wallet :ui :send :token-symbol] "ETH")))
(let [result (rf/sub [sub-name])] (let [result (rf/sub [sub-name])]
(is (match? result (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 #{} :network-preferences-names #{}
:customization-color nil :customization-color nil
:operable? true :operable? true
:operable :fully}])))) :operable :fully
:address "0x1"}]))))
(testing "returns the accounts list with the current asset using token" (testing "returns the accounts list with the current asset using token"
(swap! rf-db/app-db (swap! rf-db/app-db
@ -508,11 +518,15 @@
(assoc-in [:wallet :ui :send :token] {:symbol "ETH"}))) (assoc-in [:wallet :ui :send :token] {:symbol "ETH"})))
(let [result (rf/sub [sub-name])] (let [result (rf/sub [sub-name])]
(is (match? result (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 #{} :network-preferences-names #{}
:customization-color nil :customization-color nil
:operable? true :operable? true
:operable :fully}])))) :operable :fully
:address "0x1"}]))))
(testing (testing
"returns the full accounts list with the current asset using token-symbol if each account has the asset" "returns the full accounts list with the current asset using token-symbol if each account has the asset"