feat(swap): fetch swap proposals (#21040)
Signed-off-by: Brian Sztamfater <brian@status.im>
This commit is contained in:
parent
40f98f8238
commit
c861d95d69
|
@ -7,6 +7,7 @@
|
|||
[:map {:closed true}
|
||||
[:action? {:optional true} [:maybe boolean?]]
|
||||
[:text {:optional true} [:maybe string?]]
|
||||
[:container-style {:optional true} [:maybe :map]]
|
||||
[:button-text {:optional true} [:maybe string?]]
|
||||
[:on-button-press {:optional true} [:maybe fn?]]]]]
|
||||
:any])
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
(ns quo.components.banners.alert-banner.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(def container
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:height 50
|
||||
:padding-horizontal 20
|
||||
:padding-vertical 12})
|
||||
(defn container
|
||||
[container-style]
|
||||
(merge
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:height 50
|
||||
:padding-horizontal 20
|
||||
:padding-vertical 12}
|
||||
container-style))
|
||||
|
||||
(defn label
|
||||
[theme]
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
[schema.core :as schema]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [action? text button-text on-button-press]}]
|
||||
[{:keys [action? text button-text container-style on-button-press]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/view
|
||||
{:accessibility-label :alert-banner}
|
||||
[linear-gradient/linear-gradient
|
||||
{:style style/container
|
||||
{:style (style/container container-style)
|
||||
:start {:x 0 :y 0}
|
||||
:end {:x 0 :y 1}
|
||||
:colors [(colors/theme-colors
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
[:subtitle-type {:optional true} [:maybe [:enum :default :icon :network :account :editable]]]
|
||||
[:size {:optional true} [:maybe [:enum :default :small :large]]]
|
||||
[:title :string]
|
||||
[:subtitle {:optional true} [:maybe :string]]
|
||||
[:subtitle {:optional true} [:maybe [:or :string :double]]]
|
||||
[:custom-subtitle {:optional true} [:maybe fn?]]
|
||||
[:icon {:optional true} [:maybe :keyword]]
|
||||
[:emoji {:optional true} [:maybe :string]]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
(ns quo.components.wallet.swap-input.style
|
||||
(:require [quo.foundations.colors :as colors]
|
||||
[quo.foundations.shadows :as shadows]
|
||||
[quo.foundations.typography :as typography]))
|
||||
|
||||
(defn- border-color
|
||||
|
@ -11,11 +12,13 @@
|
|||
(colors/theme-colors colors/neutral-5 colors/neutral-90 theme))
|
||||
|
||||
(defn content
|
||||
[theme]
|
||||
{:border-width 1
|
||||
:border-radius 16
|
||||
:border-color (border-color theme)
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)})
|
||||
[typing? theme]
|
||||
(merge
|
||||
{:border-width 1
|
||||
:border-radius 16
|
||||
:border-color (border-color theme)
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)}
|
||||
(when typing? (shadows/get 1 theme))))
|
||||
|
||||
(defn row-1
|
||||
[loading?]
|
||||
|
|
|
@ -19,13 +19,15 @@
|
|||
[:props
|
||||
[:map {:closed true}
|
||||
[:type {:optional true} [:maybe [:enum :pay :receive]]]
|
||||
[:status {:optional true} [:maybe [:enum :default :disabled :loading]]]
|
||||
[:status {:optional true} [:maybe [:enum :default :typing :disabled :loading]]]
|
||||
[:token {:optional true} [:maybe :string]]
|
||||
[:value {:optional true} [:maybe :string]]
|
||||
[:default-value {:optional true} [:maybe :string]]
|
||||
[:currency-symbol {:optional true} [:maybe :string]]
|
||||
[:fiat-value {:optional true} [:maybe :string]]
|
||||
[:show-approval-label? {:optional true} [:maybe :boolean]]
|
||||
[:auto-focus? {:optional true} [:maybe :boolean]]
|
||||
[:input-disabled? {:optional true} [:maybe :boolean]]
|
||||
[:error? {:optional true} [:maybe :boolean]]
|
||||
[:show-keyboard? {:optional true} [:maybe :boolean]]
|
||||
[:approval-label-props {:optional true} [:maybe approval-label.schema/?schema]]
|
||||
|
@ -33,6 +35,7 @@
|
|||
[:on-change-text {:optional true} [:maybe fn?]]
|
||||
[:enable-swap? {:optional true} [:maybe :boolean]]
|
||||
[:on-swap-press {:optional true} [:maybe fn?]]
|
||||
[:on-input-focus {:optional true} [:maybe fn?]]
|
||||
[:on-token-press {:optional true} [:maybe fn?]]
|
||||
[:on-max-press {:optional true} [:maybe fn?]]
|
||||
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
|
||||
|
@ -41,13 +44,14 @@
|
|||
|
||||
(defn view-internal
|
||||
[{:keys [type status token value fiat-value show-approval-label? error? network-tag-props
|
||||
approval-label-props default-value enable-swap?
|
||||
approval-label-props default-value auto-focus? input-disabled? enable-swap?
|
||||
currency-symbol on-change-text show-keyboard?
|
||||
container-style on-swap-press on-token-press on-max-press]}]
|
||||
container-style on-swap-press on-token-press on-max-press on-input-focus]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
pay? (= type :pay)
|
||||
disabled? (= status :disabled)
|
||||
loading? (= status :loading)
|
||||
typing? (= status :typing)
|
||||
controlled-input? (some? value)
|
||||
input-ref (rn/use-ref-atom nil)
|
||||
set-input-ref (rn/use-callback (fn [ref] (reset! input-ref ref)) [])
|
||||
|
@ -58,7 +62,7 @@
|
|||
[rn/view
|
||||
{:style container-style
|
||||
:accessibility-label :swap-input}
|
||||
[rn/view {:style (style/content theme)}
|
||||
[rn/view {:style (style/content typing? theme)}
|
||||
[rn/view
|
||||
{:style (style/row-1 loading?)}
|
||||
[rn/pressable {:on-press on-token-press}
|
||||
|
@ -78,7 +82,9 @@
|
|||
colors/neutral-50
|
||||
theme)
|
||||
:keyboard-type :numeric
|
||||
:auto-focus true
|
||||
:editable (not input-disabled?)
|
||||
:auto-focus auto-focus?
|
||||
:on-focus on-input-focus
|
||||
:on-change-text on-change-text
|
||||
:show-soft-input-on-focus show-keyboard?
|
||||
:default-value default-value
|
||||
|
|
|
@ -551,6 +551,7 @@
|
|||
(def ^:const send-type-bridge 5)
|
||||
(def ^:const send-type-erc-721-transfer 6)
|
||||
(def ^:const send-type-erc-1155-transfer 7)
|
||||
(def ^:const send-type-swap 8)
|
||||
|
||||
(def ^:const multi-transaction-type-send 0)
|
||||
(def ^:const multi-transaction-type-approve 1)
|
||||
|
@ -596,3 +597,5 @@
|
|||
:color :blue
|
||||
:contract-address "0xdef171fe48cf0115b1d80b88dc8eab59176fee57"
|
||||
:terms-and-conditions-url "https://files.paraswap.io/tos_v4.pdf"})
|
||||
|
||||
(def ^:const token-for-fees-symbol "ETH")
|
||||
|
|
|
@ -518,23 +518,29 @@
|
|||
|
||||
(rf/reg-event-fx
|
||||
:wallet/handle-suggested-routes
|
||||
(fn [_ [data]]
|
||||
(if-let [{:keys [code details]} (-> data :ErrorResponse)]
|
||||
(let [error-message (if (= code "0") "An error occurred" details)]
|
||||
(log/error "failed to get suggested routes (async)"
|
||||
{:event :wallet/handle-suggested-routes
|
||||
:error error-message})
|
||||
{:fx [[:dispatch [:wallet/suggested-routes-error error-message]]]})
|
||||
(let [best-routes-fix (comp ->old-route-paths
|
||||
remove-invalid-bonder-fees-routes
|
||||
remove-multichain-routes)
|
||||
candidates-fix (comp ->old-route-paths
|
||||
remove-invalid-bonder-fees-routes)
|
||||
routes (-> data
|
||||
(data-store/rpc->suggested-routes)
|
||||
(update :best best-routes-fix)
|
||||
(update :candidates candidates-fix))]
|
||||
{:fx [[:dispatch [:wallet/suggested-routes-success routes]]]}))))
|
||||
(fn [{:keys [db]} [data]]
|
||||
(let [swap? (get-in db [:wallet :ui :swap])
|
||||
{:keys [code details] :as error-response} (-> data :ErrorResponse)]
|
||||
(if (and (not swap?) error-response)
|
||||
(let [error-message (if (= code "0") "An error occurred" details)]
|
||||
(log/error "failed to get suggested routes (async)"
|
||||
{:event :wallet/handle-suggested-routes
|
||||
:error error-message})
|
||||
{:fx [(if swap?
|
||||
[:dispatch [:wallet/swap-proposal-error error-message]]
|
||||
[:dispatch [:wallet/suggested-routes-error error-message]])]})
|
||||
(let [best-routes-fix (comp ->old-route-paths
|
||||
remove-invalid-bonder-fees-routes
|
||||
remove-multichain-routes)
|
||||
candidates-fix (comp ->old-route-paths
|
||||
remove-invalid-bonder-fees-routes)
|
||||
routes (-> data
|
||||
(data-store/rpc->suggested-routes)
|
||||
(update :best best-routes-fix)
|
||||
(update :candidates candidates-fix))]
|
||||
{:fx [(if swap?
|
||||
[:dispatch [:wallet/swap-proposal-success routes]]
|
||||
[:dispatch [:wallet/suggested-routes-success routes]])]})))))
|
||||
|
||||
(rf/reg-event-fx :wallet/add-authorized-transaction
|
||||
(fn [{:keys [db]} [transaction]]
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
(ns status-im.contexts.wallet.swap.events
|
||||
(:require [re-frame.core :as rf]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[status-im.contexts.wallet.sheets.network-selection.view :as network-selection]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.number]))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/start
|
||||
|
@ -14,7 +16,9 @@
|
|||
(assoc-in [:wallet :ui :swap :asset-to-pay] token)
|
||||
(assoc-in [:wallet :ui :swap :network] network))
|
||||
:fx (if network
|
||||
[[:dispatch [:navigate-to :screen/wallet.swap-propasal]]
|
||||
[[:dispatch
|
||||
[:navigate-to-within-stack
|
||||
[:screen/wallet.setup-swap :screen/wallet.swap-select-asset-to-pay]]]
|
||||
[:dispatch [:wallet.swap/set-default-slippage]]]
|
||||
[[:dispatch
|
||||
[:show-bottom-sheet
|
||||
|
@ -30,10 +34,6 @@
|
|||
:stack-id
|
||||
:screen/wallet.swap-select-asset-to-pay}]))}])}]]])}))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/clean-asset-to-pay
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui :swap] dissoc :asset-to-pay)}))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/set-default-slippage
|
||||
(fn [{:keys [db]}]
|
||||
{:db
|
||||
|
@ -47,18 +47,113 @@
|
|||
(fn [{:keys [db]} [{:keys [token]}]]
|
||||
{:db (assoc-in db [:wallet :ui :swap :asset-to-receive] token)}))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/set-pay-amount
|
||||
(fn [{:keys [db]} [amount]]
|
||||
{:db (assoc-in db [:wallet :ui :swap :pay-amount] amount)}))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/set-swap-proposal
|
||||
(fn [{:keys [db]} [swap-proposal]]
|
||||
{:db (assoc-in db [:wallet :ui :swap :swap-proposal] swap-proposal)}))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/set-provider
|
||||
(fn [{:keys [db]}]
|
||||
{:db (assoc-in db [:wallet :ui :swap :providers] [constants/swap-default-provider])}))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/recalculate-fees
|
||||
(fn [{:keys [db]} [loading-fees?]]
|
||||
{:db (assoc-in db [:wallet :ui :swap :loading-fees?] loading-fees?)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/start-get-swap-proposal
|
||||
(fn [{:keys [db]} [{:keys [amount-in amount-out]}]]
|
||||
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
|
||||
{:keys [asset-to-pay asset-to-receive
|
||||
network]} (get-in db [:wallet :ui :swap])
|
||||
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
networks ((if test-networks-enabled? :test :prod)
|
||||
(get-in db [:wallet :networks]))
|
||||
network-chain-ids (map :chain-id networks)
|
||||
pay-token-decimal (:decimals asset-to-pay)
|
||||
pay-token-id (:symbol asset-to-pay)
|
||||
receive-token-id (:symbol asset-to-receive)
|
||||
receive-token-decimals (:decimals asset-to-receive)
|
||||
gas-rates constants/gas-rate-medium
|
||||
amount-in-hex (if amount-in
|
||||
(send-utils/amount-in-hex amount-in pay-token-decimal)
|
||||
0)
|
||||
amount-out-hex (when amount-out
|
||||
(send-utils/amount-in-hex amount-out receive-token-decimals))
|
||||
to-address wallet-address
|
||||
from-address wallet-address
|
||||
swap-chain-id (:chain-id network)
|
||||
disabled-to-chain-ids (filter #(not= % swap-chain-id) network-chain-ids)
|
||||
disabled-from-chain-ids (filter #(not= % swap-chain-id) network-chain-ids)
|
||||
from-locked-amount {}
|
||||
send-type constants/send-type-swap
|
||||
request-uuid (str (random-uuid))
|
||||
params [(cond->
|
||||
{:uuid request-uuid
|
||||
:sendType send-type
|
||||
:addrFrom from-address
|
||||
:addrTo to-address
|
||||
:tokenID pay-token-id
|
||||
:toTokenID receive-token-id
|
||||
:disabledFromChainIDs disabled-from-chain-ids
|
||||
:disabledToChainIDs disabled-to-chain-ids
|
||||
:gasFeeMode gas-rates
|
||||
:fromLockedAmount from-locked-amount}
|
||||
amount-in (assoc :amountIn amount-in-hex)
|
||||
amount-out (assoc :amountOut amount-out-hex))]]
|
||||
(when-let [amount (or amount-in amount-out)]
|
||||
{:db (update-in db
|
||||
[:wallet :ui :swap]
|
||||
#(-> %
|
||||
(assoc
|
||||
:last-request-uuid request-uuid
|
||||
:amount amount
|
||||
:loading-swap-proposal? true)
|
||||
(dissoc :error-response)))
|
||||
:json-rpc/call [{:method "wallet_getSuggestedRoutesV2Async"
|
||||
:params params
|
||||
:on-error (fn [error]
|
||||
(rf/dispatch [:wallet/swap-proposal-error error])
|
||||
(log/error "failed to get suggested routes (async)"
|
||||
{:event :wallet/start-get-swap-proposal
|
||||
:error (:message error)
|
||||
:params params}))}]}))))
|
||||
|
||||
(rf/reg-event-fx :wallet/swap-proposal-success
|
||||
(fn [{:keys [db]} [swap-proposal]]
|
||||
(let [last-request-uuid (get-in db [:wallet :ui :swap :last-request-uuid])
|
||||
request-uuid (:uuid swap-proposal)
|
||||
best-routes (:best swap-proposal)
|
||||
error-response (:error-response swap-proposal)]
|
||||
(when (= request-uuid last-request-uuid)
|
||||
{:db (update-in db
|
||||
[:wallet :ui :swap]
|
||||
assoc
|
||||
:swap-proposal (first best-routes)
|
||||
:error-response (when (empty? best-routes) error-response)
|
||||
:loading-swap-proposal? false)}))))
|
||||
|
||||
(rf/reg-event-fx :wallet/swap-proposal-error
|
||||
(fn [{:keys [db]} [error-message]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :swap] dissoc :route :swap-proposal)
|
||||
(assoc-in [:wallet :ui :swap :loading-swap-proposal?] false)
|
||||
(assoc-in [:wallet :ui :swap :error-response] error-message))
|
||||
:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :swap-proposal-error
|
||||
:type :negative
|
||||
:text error-message}]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/stop-get-swap-proposal
|
||||
(fn []
|
||||
{:json-rpc/call [{:method "wallet_stopSuggestedRoutesV2AsyncCalcualtion"
|
||||
:params []
|
||||
:on-error (fn [error]
|
||||
(log/error "failed to stop fetching swap proposals"
|
||||
{:event :wallet/stop-get-swap-proposal
|
||||
:error error}))}]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-swap-proposal
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db
|
||||
[:wallet :ui :swap]
|
||||
dissoc
|
||||
:last-request-uuid
|
||||
:swap-proposal
|
||||
:error-response
|
||||
:loading-swap-proposal?)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-swap
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui] dissoc :swap)}))
|
||||
|
|
|
@ -18,22 +18,6 @@
|
|||
:value search-text
|
||||
:on-change-text on-change-text}]])
|
||||
|
||||
(def dummy-swap-proposal
|
||||
{:from {:chain-id 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}
|
||||
:estimated-time 3
|
||||
:receive-amount "99.98"
|
||||
:pay-token {:symbol "SNT"
|
||||
:address "0x432492384728934239789"}
|
||||
:receive-token {:symbol "USDT"
|
||||
:address "0x432492384728934239789"}})
|
||||
|
||||
(defn- assets-view
|
||||
[search-text on-change-text]
|
||||
(let [on-token-press (fn [token]
|
||||
|
@ -44,10 +28,8 @@
|
|||
:network (when (= (count token-networks) 1)
|
||||
(first token-networks))
|
||||
:stack-id :screen/wallet.swap-select-asset-to-pay}])
|
||||
(rf/dispatch [:wallet.swap/select-asset-to-receive {:token asset-to-receive}])
|
||||
(rf/dispatch [:wallet.swap/set-pay-amount 100])
|
||||
(rf/dispatch [:wallet.swap/set-swap-proposal dummy-swap-proposal])
|
||||
(rf/dispatch [:wallet.swap/set-provider])))]
|
||||
(rf/dispatch [:wallet.swap/select-asset-to-receive
|
||||
{:token asset-to-receive}])))]
|
||||
[:<>
|
||||
[search-input search-text on-change-text]
|
||||
[asset-list/view
|
||||
|
@ -59,7 +41,7 @@
|
|||
(let [[search-text set-search-text] (rn/use-state "")
|
||||
on-change-text #(set-search-text %)
|
||||
on-close (fn []
|
||||
(rf/dispatch [:wallet.swap/clean-asset-to-pay])
|
||||
(rf/dispatch [:wallet/clean-swap])
|
||||
(rf/dispatch [:navigate-back]))]
|
||||
[rn/safe-area-view {:style style/container}
|
||||
[account-switcher/view
|
||||
|
|
|
@ -22,14 +22,19 @@
|
|||
:height 36
|
||||
:background-color :transparent})
|
||||
|
||||
(def swap-order-button
|
||||
{:margin-top -9
|
||||
(defn swap-order-button
|
||||
[approval-required?]
|
||||
{:margin-top (if approval-required? 3 -9)
|
||||
:z-index 2
|
||||
:align-self :center})
|
||||
|
||||
(def receive-token-swap-input-container
|
||||
{:margin-top -9})
|
||||
(defn receive-token-swap-input-container
|
||||
[approval-required?]
|
||||
{:margin-top (if approval-required? 3 -9)})
|
||||
|
||||
(def footer-container
|
||||
{:flex 1
|
||||
:justify-content :flex-end})
|
||||
|
||||
(def alert-banner
|
||||
{:height 40})
|
||||
|
|
|
@ -1,13 +1,35 @@
|
|||
(ns status-im.contexts.wallet.swap.setup-swap.view
|
||||
(:require [quo.core :as quo]
|
||||
(:require [clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.controlled-input.utils :as controlled-input]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.swap.setup-swap.style :as style]
|
||||
[utils.hex :as hex]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.money :as money]
|
||||
[utils.number :as number]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.string :as utils.string]))
|
||||
|
||||
(def ^:private min-token-decimals-to-display 6)
|
||||
(def ^:private default-text-for-unfocused-input "0.00")
|
||||
|
||||
(defn- on-close
|
||||
[]
|
||||
(rf/dispatch [:wallet/clean-swap-proposal])
|
||||
(events-helper/navigate-back))
|
||||
|
||||
(defn- fetch-swap-proposal
|
||||
[{:keys [amount valid-input?]}]
|
||||
(if valid-input?
|
||||
(rf/dispatch [:wallet/start-get-swap-proposal {:amount-in amount}])
|
||||
(rf/dispatch [:wallet/clean-swap-proposal])))
|
||||
|
||||
(defn- data-item
|
||||
[{:keys [title subtitle size subtitle-icon loading?]}]
|
||||
|
@ -23,110 +45,243 @@
|
|||
:icon subtitle-icon}])
|
||||
|
||||
(defn- transaction-details
|
||||
[{:keys [max-slippage native-currency-symbol loading-fees?]}]
|
||||
(let [max-fees (rf/sub [:wallet/wallet-send-fee-fiat-formatted native-currency-symbol])]
|
||||
[]
|
||||
(let [max-fees (rf/sub [:wallet/wallet-swap-proposal-fee-fiat-formatted
|
||||
constants/token-for-fees-symbol])
|
||||
max-slippage (rf/sub [:wallet/swap-max-slippage])
|
||||
loading-fees? (rf/sub [:wallet/swap-loading-fees?])
|
||||
loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
loading? (or loading-fees? loading-swap-proposal?)]
|
||||
[rn/view {:style style/details-container}
|
||||
[data-item
|
||||
{:title (i18n/label :t/max-fees)
|
||||
:subtitle max-fees
|
||||
:loading? loading-fees?
|
||||
:loading? loading?
|
||||
:size :small}]
|
||||
[data-item
|
||||
{:title (i18n/label :t/max-slippage)
|
||||
:subtitle max-slippage
|
||||
:subtitle-icon :i/edit
|
||||
:loading? loading-fees?}]]))
|
||||
:size :small
|
||||
:loading? loading?}]]))
|
||||
|
||||
(defn- pay-token-input
|
||||
[{:keys [input-state on-max-press on-input-focus on-token-press on-approve-press input-focused?]}]
|
||||
(let [account-color (rf/sub [:wallet/current-viewing-account-color])
|
||||
network (rf/sub [:wallet/swap-network])
|
||||
asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
|
||||
currency (rf/sub [:profile/currency])
|
||||
loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
swap-proposal (rf/sub [:wallet/swap-proposal])
|
||||
approval-required (rf/sub [:wallet/swap-proposal-approval-required])
|
||||
approval-amount-required (rf/sub [:wallet/swap-proposal-approval-amount-required])
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
pay-input-num-value (controlled-input/numeric-value input-state)
|
||||
pay-input-amount (controlled-input/input-value input-state)
|
||||
pay-token-symbol (:symbol asset-to-pay)
|
||||
pay-token-decimals (:decimals asset-to-pay)
|
||||
pay-token-balance-selected-chain (get-in asset-to-pay
|
||||
[:balances-per-chain
|
||||
(:chain-id network) :balance]
|
||||
0)
|
||||
pay-token-fiat-value (str
|
||||
(utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance pay-input-num-value
|
||||
:token asset-to-pay}))
|
||||
available-crypto-limit (number/remove-trailing-zeroes
|
||||
(.toFixed (money/bignumber
|
||||
pay-token-balance-selected-chain)
|
||||
(min pay-token-decimals
|
||||
min-token-decimals-to-display)))
|
||||
approval-amount-required-num (when approval-amount-required
|
||||
(str (number/convert-to-whole-number
|
||||
(native-module/hex-to-number
|
||||
(hex/normalize-hex
|
||||
approval-amount-required))
|
||||
pay-token-decimals)))
|
||||
pay-input-error? (and (not (string/blank? pay-input-amount))
|
||||
(money/greater-than
|
||||
(money/bignumber pay-input-num-value)
|
||||
(money/bignumber
|
||||
pay-token-balance-selected-chain)))
|
||||
valid-pay-input? (and
|
||||
(not (string/blank?
|
||||
pay-input-amount))
|
||||
(> pay-input-amount 0)
|
||||
(not pay-input-error?))
|
||||
request-fetch-swap-proposal (rn/use-callback
|
||||
(fn []
|
||||
(fetch-swap-proposal
|
||||
{:amount pay-input-amount
|
||||
:valid-input? valid-pay-input?}))
|
||||
[pay-input-amount])]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(request-fetch-swap-proposal))
|
||||
[pay-input-amount])
|
||||
[quo/swap-input
|
||||
{:type :pay
|
||||
:error? pay-input-error?
|
||||
:token pay-token-symbol
|
||||
:customization-color :blue
|
||||
:show-approval-label? (and swap-proposal approval-required)
|
||||
:auto-focus? true
|
||||
:status (cond
|
||||
(and loading-swap-proposal? (not input-focused?)) :loading
|
||||
input-focused? :typing
|
||||
:else :disabled)
|
||||
:currency-symbol currency-symbol
|
||||
:on-token-press on-token-press
|
||||
:on-max-press on-max-press
|
||||
:on-input-focus on-input-focus
|
||||
:value pay-input-amount
|
||||
:fiat-value pay-token-fiat-value
|
||||
:network-tag-props {:title (i18n/label :t/max-token
|
||||
{:number available-crypto-limit
|
||||
:token-symbol pay-token-symbol})
|
||||
:networks [{:source (:source network)}]}
|
||||
:approval-label-props {:status :approve
|
||||
:token-value approval-amount-required-num
|
||||
:button-props {:on-press on-approve-press}
|
||||
:customization-color account-color
|
||||
:token-symbol pay-token-symbol}}]))
|
||||
|
||||
(defn- swap-order-button
|
||||
[{:keys [on-press]}]
|
||||
(let [approval-required? (rf/sub [:wallet/swap-proposal-approval-required])]
|
||||
[quo/swap-order-button
|
||||
{:container-style (style/swap-order-button approval-required?)
|
||||
:on-press on-press}]))
|
||||
|
||||
(defn- receive-token-input
|
||||
[{:keys [on-input-focus on-token-press input-focused?]}]
|
||||
(let [account-color (rf/sub [:wallet/current-viewing-account-color])
|
||||
asset-to-receive (rf/sub [:wallet/swap-asset-to-receive])
|
||||
loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
currency (rf/sub [:profile/currency])
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
amount-out (rf/sub [:wallet/swap-proposal-amount-out])
|
||||
approval-required? (rf/sub [:wallet/swap-proposal-approval-required])
|
||||
receive-token-symbol (:symbol asset-to-receive)
|
||||
receive-token-decimals (:decimals asset-to-receive)
|
||||
amount-out-whole-number (when amount-out
|
||||
(number/convert-to-whole-number
|
||||
(native-module/hex-to-number
|
||||
(utils.hex/normalize-hex
|
||||
amount-out))
|
||||
receive-token-decimals))
|
||||
amount-out-num (if amount-out-whole-number
|
||||
(str amount-out-whole-number)
|
||||
default-text-for-unfocused-input)
|
||||
receive-token-fiat-value (str (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance (or amount-out-whole-number 0)
|
||||
:token asset-to-receive}))]
|
||||
[quo/swap-input
|
||||
{:type :receive
|
||||
:error? false
|
||||
:token receive-token-symbol
|
||||
:customization-color account-color
|
||||
:show-approval-label? false
|
||||
:enable-swap? true
|
||||
:input-disabled? true
|
||||
:status (cond
|
||||
(and loading-swap-proposal? (not input-focused?)) :loading
|
||||
input-focused? :typing
|
||||
:else :disabled)
|
||||
:currency-symbol currency-symbol
|
||||
:on-token-press on-token-press
|
||||
:on-input-focus on-input-focus
|
||||
:value amount-out-num
|
||||
:fiat-value receive-token-fiat-value
|
||||
:container-style (style/receive-token-swap-input-container approval-required?)}]))
|
||||
|
||||
(defn- action-button
|
||||
[{:keys [on-press]}]
|
||||
(let [account-color (rf/sub [:wallet/current-viewing-account-color])
|
||||
swap-proposal (rf/sub [:wallet/swap-proposal])
|
||||
loading-fees? (rf/sub [:wallet/swap-loading-fees?])
|
||||
loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
approval-required? (rf/sub [:wallet/swap-proposal-approval-required])]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/review-swap)
|
||||
:button-one-props {:disabled? (or (not swap-proposal)
|
||||
approval-required?
|
||||
loading-swap-proposal?
|
||||
loading-fees?)
|
||||
:customization-color account-color
|
||||
:on-press on-press}}]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [[pay-value set-pay-value] (rn/use-state "")
|
||||
{:keys [color]} (rf/sub [:wallet/current-viewing-account])
|
||||
{:keys [max-slippage swap-proposal loading-fees?
|
||||
receive-amount network]} (rf/sub [:wallet/swap])
|
||||
currency (rf/sub [:profile/currency])
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
|
||||
asset-to-receive (rf/sub [:wallet/swap-asset-to-receive])
|
||||
|
||||
pay-token-fiat-value (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance (or pay-value 0)
|
||||
:token asset-to-pay})
|
||||
receive-token-fiat-value (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance (or receive-amount 0)
|
||||
:token asset-to-receive})
|
||||
native-currency-symbol (get-in swap-proposal
|
||||
[:from :native-currency-symbol])
|
||||
pay-token-symbol (:symbol asset-to-pay)
|
||||
receive-token-symbol (:symbol asset-to-receive)
|
||||
on-press (fn [v] (set-pay-value (str pay-value v)))
|
||||
delete (fn []
|
||||
(set-pay-value #(subs % 0 (dec (count %)))))]
|
||||
(let [[pay-input-state set-pay-input-state] (rn/use-state controlled-input/init-state)
|
||||
[pay-input-focused? set-pay-input-focused?] (rn/use-state true)
|
||||
error-response (rf/sub [:wallet/swap-error-response])
|
||||
network (rf/sub [:wallet/swap-network])
|
||||
loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
swap-proposal (rf/sub [:wallet/swap-proposal])
|
||||
asset-to-pay (rf/sub [:wallet/swap-asset-to-pay])
|
||||
pay-input-amount (controlled-input/input-value pay-input-state)
|
||||
pay-token-decimals (:decimals asset-to-pay)
|
||||
network-chain-id (:chain-id network)
|
||||
pay-token-balance-selected-chain (get-in asset-to-pay
|
||||
[:balances-per-chain network-chain-id
|
||||
:balance]
|
||||
0)
|
||||
on-press (rn/use-callback
|
||||
(fn [c]
|
||||
(let
|
||||
[new-text (str pay-input-amount c)
|
||||
valid-amount?
|
||||
(utils.string/valid-amount-for-token-decimals?
|
||||
pay-token-decimals
|
||||
new-text)]
|
||||
(when valid-amount?
|
||||
(set-pay-input-state
|
||||
#(controlled-input/add-character % c))))))
|
||||
on-long-press (rn/use-callback
|
||||
(fn []
|
||||
(set-pay-input-state controlled-input/delete-all)
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])))
|
||||
delete (rn/use-callback
|
||||
(fn []
|
||||
(set-pay-input-state
|
||||
controlled-input/delete-last)
|
||||
(rf/dispatch [:wallet/clean-swap-proposal])))]
|
||||
[rn/view {:style style/container}
|
||||
[account-switcher/view
|
||||
{:on-press events-helper/navigate-back
|
||||
{:on-press on-close
|
||||
:icon-name :i/arrow-left
|
||||
:margin-top (safe-area/get-top)
|
||||
:switcher-type :select-account}]
|
||||
[rn/view {:style style/inputs-container}
|
||||
[quo/swap-input
|
||||
{:type :pay
|
||||
:error? false
|
||||
:token pay-token-symbol
|
||||
:customization-color :blue
|
||||
:show-approval-label? false
|
||||
:status :default
|
||||
:currency-symbol currency-symbol
|
||||
:on-swap-press #(js/alert "Swap Pressed")
|
||||
:on-token-press #(js/alert "Token Pressed")
|
||||
:on-max-press #(js/alert "Max Pressed")
|
||||
:value pay-value
|
||||
:fiat-value pay-token-fiat-value
|
||||
:network-tag-props {:title (i18n/label :t/max-token
|
||||
{:number 200
|
||||
:token-symbol pay-token-symbol})
|
||||
:networks [{:source (:source network)}]}
|
||||
:approval-label-props {:status :approve
|
||||
:token-value pay-value
|
||||
:button-props {:on-press
|
||||
#(js/alert "Approve Pressed")}
|
||||
:customization-color color
|
||||
:token-symbol pay-token-symbol}}]
|
||||
[quo/swap-order-button
|
||||
{:container-style style/swap-order-button
|
||||
:on-press #(js/alert "Pressed")}]
|
||||
[quo/swap-input
|
||||
{:type :receive
|
||||
:error? false
|
||||
:token receive-token-symbol
|
||||
:customization-color color
|
||||
:show-approval-label? false
|
||||
:enable-swap? true
|
||||
:status :default
|
||||
:currency-symbol currency-symbol
|
||||
:on-swap-press #(js/alert "Swap Pressed")
|
||||
:on-token-press #(js/alert "Token Pressed")
|
||||
:on-max-press #(js/alert "Max Pressed")
|
||||
:value receive-amount
|
||||
:fiat-value receive-token-fiat-value
|
||||
:container-style style/receive-token-swap-input-container}]]
|
||||
[pay-token-input
|
||||
{:input-state pay-input-state
|
||||
:on-max-press #(set-pay-input-state pay-token-balance-selected-chain)
|
||||
:input-focused? pay-input-focused?
|
||||
:on-token-press #(js/alert "Token Pressed")
|
||||
:on-approve-press #(js/alert "Approve Pressed")
|
||||
:on-input-focus #(set-pay-input-focused? true)}]
|
||||
[swap-order-button {:on-press #(js/alert "Swap Order Pressed")}]
|
||||
[receive-token-input
|
||||
{:input-focused? (not pay-input-focused?)
|
||||
:on-token-press #(js/alert "Token Pressed")
|
||||
:on-input-focus #(set-pay-input-focused? false)}]]
|
||||
[rn/view {:style style/footer-container}
|
||||
(when swap-proposal
|
||||
[transaction-details
|
||||
{:native-currency-symbol native-currency-symbol
|
||||
:max-slippage max-slippage
|
||||
:loading-fees? loading-fees?}])
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/review-swap)
|
||||
:button-one-props {:disabled? (or (not swap-proposal)
|
||||
loading-fees?)
|
||||
:customization-color color
|
||||
:on-press #(js/alert "Review swap pressed")}}]]
|
||||
(when error-response
|
||||
[quo/alert-banner
|
||||
{:container-style style/alert-banner
|
||||
:text (i18n/label :t/something-went-wrong-please-try-again-later)}])
|
||||
(when (or loading-swap-proposal? swap-proposal)
|
||||
[transaction-details])
|
||||
[action-button
|
||||
{:on-press #(js/alert "Review swap pressed")}]]
|
||||
[quo/numbered-keyboard
|
||||
{:container-style style/keyboard-container
|
||||
:left-action :dot
|
||||
:delete-key? true
|
||||
:on-press on-press
|
||||
:on-delete delete}]]))
|
||||
:on-delete delete
|
||||
:on-long-press on-long-press}]]))
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
(ns status-im.subs.wallet.swap
|
||||
(:require [re-frame.core :as rf]
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :as rf]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[utils.money :as money]))
|
||||
|
||||
(rf/reg-sub
|
||||
|
@ -19,6 +21,16 @@
|
|||
:<- [:wallet/swap]
|
||||
:-> :asset-to-receive)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-network
|
||||
:<- [:wallet/swap]
|
||||
:-> :network)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-error-response
|
||||
:<- [:wallet/swap]
|
||||
:-> :error-response)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-asset-to-pay-token-symbol
|
||||
:<- [:wallet/swap-asset-to-pay]
|
||||
|
@ -62,3 +74,59 @@
|
|||
:wallet/swap-max-slippage
|
||||
:<- [:wallet/swap]
|
||||
:-> :max-slippage)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-loading-fees?
|
||||
:<- [:wallet/swap]
|
||||
:-> :loading-fees?)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-proposal
|
||||
:<- [:wallet/swap]
|
||||
:-> :swap-proposal)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-loading-swap-proposal?
|
||||
:<- [:wallet/swap]
|
||||
:-> :loading-swap-proposal?)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-proposal-amount-out
|
||||
:<- [:wallet/swap-proposal]
|
||||
:-> :amount-out)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-proposal-approval-required
|
||||
:<- [:wallet/swap-proposal]
|
||||
:-> :approval-required)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/swap-proposal-approval-amount-required
|
||||
:<- [:wallet/swap-proposal]
|
||||
:-> :approval-amount-required)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-swap-proposal-fee-fiat-formatted
|
||||
:<- [:wallet/current-viewing-account]
|
||||
:<- [:wallet/swap-proposal]
|
||||
:<- [:profile/currency]
|
||||
:<- [:profile/currency-symbol]
|
||||
(fn [[account swap-proposal currency currency-symbol] [_ token-symbol-for-fees]]
|
||||
(when token-symbol-for-fees
|
||||
(let [tokens (:tokens account)
|
||||
token-for-fees (first (filter #(= (string/lower-case (:symbol %))
|
||||
(string/lower-case token-symbol-for-fees))
|
||||
tokens))
|
||||
fee-in-native-token (send-utils/calculate-full-route-gas-fee [swap-proposal])
|
||||
fee-in-crypto-formatted (utils/get-standard-crypto-format
|
||||
token-for-fees
|
||||
fee-in-native-token)
|
||||
fee-in-fiat (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance fee-in-native-token
|
||||
:token token-for-fees})
|
||||
fee-formatted (utils/get-standard-fiat-format
|
||||
fee-in-crypto-formatted
|
||||
currency-symbol
|
||||
fee-in-fiat)]
|
||||
fee-formatted))))
|
||||
|
|
|
@ -16,6 +16,27 @@
|
|||
:popular? true
|
||||
:token? false}})
|
||||
|
||||
(def ^:private accounts-with-tokens
|
||||
{:0x1 {:tokens [{:symbol "ETH"
|
||||
:balances-per-chain {1 {:raw-balance "100"}}
|
||||
:market-values-per-currency {:usd {:price 10000}}}
|
||||
{:symbol "SNT"
|
||||
:balances-per-chain {1 {:raw-balance "100"}}
|
||||
:market-values-per-currency {:usd {:price 10000}}}]
|
||||
:network-preferences-names #{}
|
||||
:customization-color nil
|
||||
:operable? true
|
||||
:operable :fully
|
||||
:address "0x1"}
|
||||
:0x2 {:tokens [{:symbol "SNT"
|
||||
:balances-per-chain {1 {:raw-balance "200"}}
|
||||
:market-values-per-currency {:usd {:price 10000}}}]
|
||||
:network-preferences-names #{}
|
||||
:customization-color nil
|
||||
:operable? true
|
||||
:operable :partially
|
||||
:address "0x2"}})
|
||||
|
||||
(def networks
|
||||
{:mainnet-network
|
||||
{:full-name "Mainnet"
|
||||
|
@ -110,7 +131,19 @@
|
|||
:token-list-id ""
|
||||
:built-on "ETH"
|
||||
:verified true}
|
||||
:network nil})
|
||||
:network (networks :mainnet-network)
|
||||
:swap-proposal {:amount-out "0x10000"
|
||||
:amount-in "0x10000"
|
||||
:approval-required true
|
||||
:approval-amount-required "0x10000"
|
||||
:gas-amount "25000"
|
||||
:gas-fees {:max-fee-per-gas-medium "4"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "0"}}
|
||||
:error-response "Error"
|
||||
:loading-fees? false
|
||||
:loading-swap-proposal? false
|
||||
:max-slippage 0.5})
|
||||
|
||||
(h/deftest-sub :wallet/swap
|
||||
[sub-name]
|
||||
|
@ -160,3 +193,91 @@
|
|||
(assoc :currencies currencies)
|
||||
(assoc-in [:wallet :ui :swap] swap-data)))
|
||||
(is (match? {:crypto "1 SNT" :fiat "$0.03"} (rf/sub [sub-name 1])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-network
|
||||
[sub-name]
|
||||
(testing "Return the current swap network"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (match? (swap-data :network) (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-error-response
|
||||
[sub-name]
|
||||
(testing "Return the swap error response"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (match? (swap-data :error-response) (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-max-slippage
|
||||
[sub-name]
|
||||
(testing "Return the max slippage for the swap"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (match? 0.5 (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-loading-fees?
|
||||
[sub-name]
|
||||
(testing "Return if swap is loading fees"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (false? (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-loading-swap-proposal?
|
||||
[sub-name]
|
||||
(testing "Return if swap is loading the swap proposal"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (false? (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-proposal
|
||||
[sub-name]
|
||||
(testing "Return the swap proposal"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (match? (swap-data :swap-proposal) (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-proposal-amount-out
|
||||
[sub-name]
|
||||
(testing "Return the amount out in the swap proposal"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (match? "0x10000" (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-proposal-approval-required
|
||||
[sub-name]
|
||||
(testing "Return if approval is required in the swap proposal"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (true? (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/swap-proposal-approval-amount-required
|
||||
[sub-name]
|
||||
(testing "Return the approval amount required in the swap proposal"
|
||||
(swap! rf-db/app-db assoc-in
|
||||
[:wallet :ui :swap]
|
||||
swap-data)
|
||||
(is (match? "0x10000" (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/wallet-swap-proposal-fee-fiat-formatted
|
||||
[sub-name]
|
||||
(testing "wallet send fee calculated and formatted in fiat"
|
||||
(swap! rf-db/app-db
|
||||
#(-> %
|
||||
(assoc-in [:wallet :accounts] accounts-with-tokens)
|
||||
(assoc-in [:wallet :current-viewing-account-address] "0x1")
|
||||
(assoc-in [:wallet :ui :swap] swap-data)
|
||||
(assoc-in [:currencies] currencies)
|
||||
(assoc-in [:profile/profile :currency] :usd)
|
||||
(assoc-in [:profile/profile :currency-symbol] "$")))
|
||||
|
||||
(let [token-symbol-for-fees "ETH"
|
||||
result (rf/sub [sub-name token-symbol-for-fees])]
|
||||
(is (match? result "$1.00")))))
|
||||
|
|
|
@ -202,11 +202,6 @@
|
|||
[gas gas-price]
|
||||
(.times ^js (bignumber gas) ^js (bignumber gas-price)))
|
||||
|
||||
(defn crypto->fiat
|
||||
[crypto fiat-price]
|
||||
(when-let [^js bn (bignumber crypto)]
|
||||
(.times bn ^js (bignumber fiat-price))))
|
||||
|
||||
(defn percent-change
|
||||
[from to]
|
||||
(let [^js bnf (bignumber from)
|
||||
|
@ -221,6 +216,12 @@
|
|||
(when-let [^js bn (bignumber n)]
|
||||
(.round bn decimals)))
|
||||
|
||||
(defn crypto->fiat
|
||||
[crypto fiat-price]
|
||||
(when-let [^js bn (bignumber crypto)]
|
||||
(-> (.times bn ^js (bignumber fiat-price))
|
||||
(with-precision 2))))
|
||||
|
||||
(defn sufficient-funds?
|
||||
[^js amount ^js balance]
|
||||
(when (and amount balance)
|
||||
|
|
|
@ -15,6 +15,17 @@
|
|||
(/ (Math/round (* n scale))
|
||||
scale)))
|
||||
|
||||
(defn convert-to-whole-number
|
||||
"Converts a fractional `amount` to its corresponding whole number representation
|
||||
by dividing it by 10 raised to the power of `decimals`. This is often used in financial
|
||||
calculations where amounts are stored in their smallest units (e.g., cents) and need
|
||||
to be converted to their whole number equivalents (e.g., dollars).
|
||||
|
||||
Example usage:
|
||||
(convert-to-whole-number 12345 2) ; => 123.45"
|
||||
[amount decimals]
|
||||
(/ amount (Math/pow 10 decimals)))
|
||||
|
||||
(defn parse-int
|
||||
"Parses `n` as an integer. Defaults to zero or `default` instead of NaN."
|
||||
([n]
|
||||
|
|
|
@ -3,6 +3,26 @@
|
|||
[cljs.test :refer [deftest is testing]]
|
||||
[utils.number]))
|
||||
|
||||
(deftest convert-to-whole-number-test
|
||||
(testing "correctly converts fractional amounts to whole numbers"
|
||||
(is (= 123.45 (utils.number/convert-to-whole-number 12345 2)))
|
||||
(is (= 1.2345 (utils.number/convert-to-whole-number 12345 4)))
|
||||
(is (= 12345.0 (utils.number/convert-to-whole-number 1234500 2)))
|
||||
(is (= 0.123 (utils.number/convert-to-whole-number 123 3)))
|
||||
(is (= 1000.0 (utils.number/convert-to-whole-number 1000000 3))))
|
||||
|
||||
(testing "handles zero decimals"
|
||||
(is (= 12345 (utils.number/convert-to-whole-number 12345 0))))
|
||||
|
||||
(testing "handles negative amounts"
|
||||
(is (= -123.45 (utils.number/convert-to-whole-number -12345 2)))
|
||||
(is (= -1.2345 (utils.number/convert-to-whole-number -12345 4)))
|
||||
(is (= -0.123 (utils.number/convert-to-whole-number -123 3))))
|
||||
|
||||
(testing "handles zero amount"
|
||||
(is (= 0 (utils.number/convert-to-whole-number 0 2)))
|
||||
(is (= 0 (utils.number/convert-to-whole-number 0 0)))))
|
||||
|
||||
(deftest parse-int-test
|
||||
(testing "defaults to zero"
|
||||
(is (= 0 (utils.number/parse-int nil))))
|
||||
|
|
|
@ -88,3 +88,9 @@
|
|||
[url]
|
||||
(when (string? url)
|
||||
(string/replace url #"^https?://" "")))
|
||||
|
||||
(defn valid-amount-for-token-decimals?
|
||||
[token-decimals amount-text]
|
||||
(let [regex-pattern (str "^\\d*\\.?\\d{0," token-decimals "}$")
|
||||
regex (re-pattern regex-pattern)]
|
||||
(re-matches regex amount-text)))
|
||||
|
|
|
@ -2302,6 +2302,7 @@
|
|||
"slow": "Slow",
|
||||
"something-about-you": "Something about you",
|
||||
"something-went-wrong": "Something went wrong",
|
||||
"something-went-wrong-please-try-again-later": "Something went wrong, please try again later",
|
||||
"soon": "Soon",
|
||||
"sort-communities": "Sort communities",
|
||||
"special-characters": "Special characters",
|
||||
|
|
Loading…
Reference in New Issue