Skip to content

Commit

Permalink
fix(wallet)_: Send flow for collectibles (#21871)
Browse files Browse the repository at this point in the history
This commit fixes

- the send flow for collectibles (ERC721 and ERC1155)
- picking the right balance of the ERC1155 in the send flow from the account page, based on the account viewing by the user
- the balance of ERC1155 is sometimes incorrect if the collectible is present in more than one account of the user

Signed-off-by: Mohamed Javid <[email protected]>
  • Loading branch information
smohamedjavid authored Jan 2, 2025
1 parent c6ff909 commit baf3b8c
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 66 deletions.
5 changes: 3 additions & 2 deletions src/status_im/contexts/wallet/collectible/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down
23 changes: 16 additions & 7 deletions src/status_im/contexts/wallet/collectible/utils.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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))
16 changes: 10 additions & 6 deletions src/status_im/contexts/wallet/collectible/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,23 @@

(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
{:container-style style/send-button
: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
Expand Down
1 change: 1 addition & 0 deletions src/status_im/contexts/wallet/data_store.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
7 changes: 4 additions & 3 deletions src/status_im/contexts/wallet/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down
70 changes: 43 additions & 27 deletions src/status_im/contexts/wallet/send/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand All @@ -283,37 +289,46 @@
: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))))
(:name collectible-data)

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 collectible 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
Expand Down Expand Up @@ -673,11 +688,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)]
Expand All @@ -704,7 +720,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
Expand Down
14 changes: 8 additions & 6 deletions src/status_im/contexts/wallet/send/events_test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
48 changes: 33 additions & 15 deletions src/status_im/contexts/wallet/send/from/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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}]]))
11 changes: 11 additions & 0 deletions src/status_im/subs/wallet/wallet.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down

0 comments on commit baf3b8c

Please sign in to comment.