From ab73c7e56a3f60026be43a2b8241b8edb102dd69 Mon Sep 17 00:00:00 2001 From: Brian Sztamfater Date: Fri, 9 Feb 2024 13:43:14 -0300 Subject: [PATCH] feat: show estimated fees when calculating route (#18309) Signed-off-by: Brian Sztamfater --- .../components/settings/data_item/view.cljs | 2 +- .../contexts/wallet/common/utils.cljs | 2 +- .../contexts/wallet/common/utils/send.cljs | 18 ++++++ .../wallet/common/utils/send_test.cljs | 22 ++++++++ .../send/input_amount/component_spec.cljs | 16 +++++- .../wallet/send/input_amount/style.cljs | 23 ++++++++ .../wallet/send/input_amount/view.cljs | 56 ++++++++++++++++++- src/status_im/subs/wallet/wallet.cljs | 16 ++++++ translations/en.json | 3 +- 9 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 src/status_im/contexts/wallet/common/utils/send.cljs create mode 100644 src/status_im/contexts/wallet/common/utils/send_test.cljs diff --git a/src/quo/components/settings/data_item/view.cljs b/src/quo/components/settings/data_item/view.cljs index 4f9e491467..452a7bb424 100644 --- a/src/quo/components/settings/data_item/view.cljs +++ b/src/quo/components/settings/data_item/view.cljs @@ -121,7 +121,7 @@ {:accessibility-label :data-item :disabled (not icon-right?) :on-press on-press - :style (merge container-style (style/container size card? blur? theme))} + :style (merge (style/container size card? blur? theme) container-style)} [left-side props] (when (and (= :default status) (not= :small size)) [right-side diff --git a/src/status_im/contexts/wallet/common/utils.cljs b/src/status_im/contexts/wallet/common/utils.cljs index 351a0e416d..01e4073d16 100644 --- a/src/status_im/contexts/wallet/common/utils.cljs +++ b/src/status_im/contexts/wallet/common/utils.cljs @@ -218,7 +218,7 @@ (defn get-standard-fiat-format [crypto-value currency-symbol fiat-value] (if (string/includes? crypto-value "<") - "<$0.01" + (str "<" currency-symbol "0.01") (prettify-balance currency-symbol fiat-value))) (defn prettify-percentage-change diff --git a/src/status_im/contexts/wallet/common/utils/send.cljs b/src/status_im/contexts/wallet/common/utils/send.cljs new file mode 100644 index 0000000000..025b9a1a85 --- /dev/null +++ b/src/status_im/contexts/wallet/common/utils/send.cljs @@ -0,0 +1,18 @@ +(ns status-im.contexts.wallet.common.utils.send + (:require [utils.money :as money])) + +(defn calculate-gas-fee + [data] + (let [gas-amount (money/bignumber (get data :gas-amount)) + gas-fees (get data :gas-fees) + eip1559-enabled? (get gas-fees :eip1559-enabled) + billion (money/bignumber "1000000000")] + (if eip1559-enabled? + (let [base-fee (money/bignumber (get gas-fees :base-fee)) + priority-fee (money/bignumber (get gas-fees :max-priority-fee-per-gas)) + fee-with-tip (money/bignumber (money/add base-fee priority-fee)) + total-gas-fee (money/mul gas-amount fee-with-tip)] + (money/with-precision (money/div total-gas-fee billion) 10)) + (let [gas-price (money/bignumber (get gas-fees :gas-price)) + total-gas-fee (money/mul gas-amount gas-price)] + (money/with-precision (money/div total-gas-fee billion) 10))))) diff --git a/src/status_im/contexts/wallet/common/utils/send_test.cljs b/src/status_im/contexts/wallet/common/utils/send_test.cljs new file mode 100644 index 0000000000..5a499d2cd3 --- /dev/null +++ b/src/status_im/contexts/wallet/common/utils/send_test.cljs @@ -0,0 +1,22 @@ +(ns status-im.contexts.wallet.common.utils.send-test + (:require [cljs.test :refer [deftest is testing]] + [status-im.contexts.wallet.common.utils.send :as utils] + [utils.money :as money])) + +(deftest test-calculate-gas-fee + (testing "Test calculate-gas-fee function with EIP-1559 enabled" + (let [data-eip1559-enabled {:gas-amount "23487" + :gas-fees {:base-fee "32.325296406" + :max-priority-fee-per-gas "0.011000001" + :eip1559-enabled true}} + expected-eip1559-enabled-result (money/bignumber 0.0007594826)] + (is (money/equal-to (utils/calculate-gas-fee data-eip1559-enabled) + expected-eip1559-enabled-result))) + + (testing "Test calculate-gas-fee function with EIP-1559 disabled" + (let [data-eip1559-disabled {:gas-amount "23487" + :gas-fees {:gas-price "32.375609968" + :eip1559-enabled false}} + expected-eip1559-disabled-result (money/bignumber 0.000760406)] + (is (money/equal-to (utils/calculate-gas-fee data-eip1559-disabled) + expected-eip1559-disabled-result)))))) diff --git a/src/status_im/contexts/wallet/send/input_amount/component_spec.cljs b/src/status_im/contexts/wallet/send/input_amount/component_spec.cljs index a2ce5e84e2..ebccde8117 100644 --- a/src/status_im/contexts/wallet/send/input_amount/component_spec.cljs +++ b/src/status_im/contexts/wallet/send/input_amount/component_spec.cljs @@ -43,10 +43,22 @@ :total-balance 100 :market-values-per-currency {:usd {:price 10}}} :wallet/wallet-send-loading-suggested-routes? false - :wallet/wallet-send-route {:route []} + :wallet/wallet-send-route {:from {:chainid 1 + :native-currency-symbol "ETH"} + :to {:chain-id 1 + :native-currency-symbol "ETH"} + :gas-amount "23487" + :gas-fees {:base-fee "32.325296406" + :max-priority-fee-per-gas "0.011000001" + :eip1559-enabled true}} :wallet/wallet-send-suggested-routes {:candidates []} :wallet/wallet-send-selected-networks [] - :navigation/current-screen-id :wallet-send-input-amount}) + :navigation/current-screen-id :wallet-send-input-amount + :wallet/wallet-send-to-address "0x04371e2d9d66b82f056bc128064" + :profile/currency-symbol "$" + :wallet/token-by-symbol {:symbol :eth + :total-balance 100 + :market-values-per-currency {:usd {:price 10}}}}) (defn- render [component] diff --git a/src/status_im/contexts/wallet/send/input_amount/style.cljs b/src/status_im/contexts/wallet/send/input_amount/style.cljs index 0f9b1d2971..724a723c0f 100644 --- a/src/status_im/contexts/wallet/send/input_amount/style.cljs +++ b/src/status_im/contexts/wallet/send/input_amount/style.cljs @@ -10,3 +10,26 @@ (defn keyboard-container [bottom] {:padding-bottom bottom}) + +(def estimated-fees-container + {:height 48 + :width "100%" + :flex-direction :row + :align-items :center + :padding-horizontal 20 + :padding-top 8}) + +(def estimated-fees-content-container + {:align-items :center + :height 40}) + +(def fees-data-item + {:flex 1 + :height 40 + :margin-horizontal 16 + :background-color :transparent}) + +(def amount-data-item + {:flex 1 + :height 40 + :background-color :transparent}) diff --git a/src/status_im/contexts/wallet/send/input_amount/view.cljs b/src/status_im/contexts/wallet/send/input_amount/view.cljs index 7236cdb6b4..da3315b20c 100644 --- a/src/status_im/contexts/wallet/send/input_amount/view.cljs +++ b/src/status_im/contexts/wallet/send/input_amount/view.cljs @@ -8,8 +8,10 @@ [reagent.core :as reagent] [status-im.contexts.wallet.common.account-switcher.view :as account-switcher] [status-im.contexts.wallet.common.utils :as utils] + [status-im.contexts.wallet.common.utils.send :as send-utils] [status-im.contexts.wallet.send.input-amount.style :as style] [status-im.contexts.wallet.send.routes.view :as routes] + [utils.address :as address] [utils.debounce :as debounce] [utils.i18n :as i18n] [utils.re-frame :as rf])) @@ -90,6 +92,34 @@ (let [size (count s)] (str (subs s 0 (dec idx)) (subs s idx size)))) +(defn- estimated-fees + [{:keys [loading-suggested-routes? fees amount receiver]}] + [rn/view {:style style/estimated-fees-container} + [rn/view {:style style/estimated-fees-content-container} + [quo/button + {:icon-only? true + :type :outline + :size 32 + :inner-style {:opacity 1} + :accessibility-label :advanced-button + :disabled? loading-suggested-routes? + :on-press #(js/alert "Not implemented yet")} + :i/advanced]] + [quo/data-item + {:container-style style/fees-data-item + :label :none + :status (if loading-suggested-routes? :loading :default) + :size :small + :title (i18n/label :t/fees) + :subtitle fees}] + [quo/data-item + {:container-style style/amount-data-item + :label :none + :status (if loading-suggested-routes? :loading :default) + :size :small + :title (i18n/label :t/user-gets {:name receiver}) + :subtitle amount}]]) + (defn- f-view-internal ;; crypto-decimals, limit-crypto and initial-crypto-currency? args are needed ;; for component tests only @@ -169,6 +199,7 @@ loading-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?]) suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes]) route (rf/sub [:wallet/wallet-send-route]) + to-address (rf/sub [:wallet/wallet-send-to-address]) on-confirm (or default-on-confirm handle-on-confirm) crypto-decimals (or default-crypto-decimals (utils/get-crypto-decimals-count token)) @@ -184,7 +215,24 @@ (empty? @input-value) (<= input-num-value 0) (> input-num-value current-limit)) - amount-text (str @input-value " " token-symbol)] + amount-text (str @input-value " " token-symbol) + native-currency-symbol (when-not confirm-disabled? + (get-in route [:from :native-currency-symbol])) + native-token (when native-currency-symbol + (rf/sub [:wallet/token-by-symbol native-currency-symbol])) + fee-in-native-token (when-not confirm-disabled? (send-utils/calculate-gas-fee route)) + fee-in-crypto-formatted (when fee-in-native-token + (utils/get-standard-crypto-format native-token + fee-in-native-token)) + fee-in-fiat (when-not confirm-disabled? + (utils/token-fiat-value fiat-currency + fee-in-native-token + native-token)) + currency-symbol (rf/sub [:profile/currency-symbol]) + fee-formatted (when fee-in-fiat + (utils/get-standard-fiat-format fee-in-crypto-formatted + currency-symbol + fee-in-fiat))] (rn/use-effect (fn [] (let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!)) @@ -226,6 +274,12 @@ :token token :input-value @input-value :fetch-routes #(fetch-routes % current-limit)}] + (when (or loading-routes? route) + [estimated-fees + {:loading-suggested-routes? loading-routes? + :fees fee-formatted + :amount amount-text + :receiver (address/get-shortened-key to-address)}]) [quo/bottom-actions {:actions :one-action :button-one-label (i18n/label :t/confirm) diff --git a/src/status_im/subs/wallet/wallet.cljs b/src/status_im/subs/wallet/wallet.cljs index 334e6cbe2a..53f70d1814 100644 --- a/src/status_im/subs/wallet/wallet.cljs +++ b/src/status_im/subs/wallet/wallet.cljs @@ -160,6 +160,22 @@ sorted-tokens)] filtered-tokens))) +(rf/reg-sub + :wallet/token-by-symbol + :<- [:wallet/current-viewing-account] + :<- [:wallet/network-details] + (fn [[account networks] [_ token-symbol]] + (let [tokens (map (fn [token] + (assoc token + :networks (utils/network-list token networks) + :total-balance (utils/total-token-units-in-all-chains token) + :total-balance-fiat (utils/calculate-balance-for-token token))) + (:tokens account)) + token (first (filter #(= (string/lower-case (:symbol %)) + (string/lower-case token-symbol)) + tokens))] + token))) + (rf/reg-sub :wallet/accounts-without-current-viewing-account :<- [:wallet/accounts] diff --git a/translations/en.json b/translations/en.json index 26ecbb5163..c6d13c4c74 100644 --- a/translations/en.json +++ b/translations/en.json @@ -2493,5 +2493,6 @@ "confirm-the-position": "Confirm the position of certain words in your recovery phrase", "do-not-cheat": "Don't try to cheat", "do-not-cheat-description": "These 12 words give access to all of your funds so it is important that you write them in the correct order, take it seriously.", - "see-recovery-phrase-again": "See recovery phrase again" + "see-recovery-phrase-again": "See recovery phrase again", + "fees": "Fees" }