feat: add ability to tap to disable from networks (#19392)
This commit is contained in:
parent
5412092ca1
commit
98d4969ca5
|
@ -0,0 +1,23 @@
|
|||
(ns quo.components.wallet.network-link.helpers)
|
||||
|
||||
(def ^:private central-figure-width 63)
|
||||
|
||||
(defn calculate-side-lines-path-1x
|
||||
"Calculates the `d` attribute for the side lines based on the SVG width."
|
||||
[width]
|
||||
(let [side-offset (/ (- width central-figure-width) 2)]
|
||||
{:left (str "M0 57 L" side-offset " 57")
|
||||
:right (str "M" (+ side-offset central-figure-width) " 1 L" width " 1")}))
|
||||
|
||||
(defn calculate-transform
|
||||
"Calculates the transform attribute for the central figure based on the SVG width."
|
||||
[width]
|
||||
(let [translate-x (/ (- width central-figure-width) 2)]
|
||||
(str "translate(" translate-x " 0)")))
|
||||
|
||||
(defn calculate-side-lines-path-2x
|
||||
"Calculates the `d` attribute for the side lines based on the SVG width."
|
||||
[width]
|
||||
(let [side-offset (/ (- width central-figure-width) 2)]
|
||||
{:left (str "M0 113 L" side-offset " 113")
|
||||
:right (str "M" (+ side-offset central-figure-width) " 1 L" width " 1")}))
|
|
@ -0,0 +1,34 @@
|
|||
(ns quo.components.wallet.network-link.style)
|
||||
|
||||
(def left-circle-container
|
||||
{:position :absolute
|
||||
:left -3})
|
||||
|
||||
(def right-circle-container
|
||||
{:position :absolute
|
||||
:right -3})
|
||||
|
||||
(def bottom-left-circle-container
|
||||
{:position :absolute
|
||||
:bottom -3
|
||||
:left -3})
|
||||
|
||||
(def top-right-circle-container
|
||||
{:position :absolute
|
||||
:top -3
|
||||
:right -3})
|
||||
|
||||
(def link-linear-container
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:height 10})
|
||||
|
||||
(def link-1x-container
|
||||
{:flex 1
|
||||
:height 58
|
||||
:justify-content :center})
|
||||
|
||||
(def link-2x-container
|
||||
{:flex 1
|
||||
:height 114
|
||||
:justify-content :center})
|
|
@ -1,82 +1,151 @@
|
|||
(ns quo.components.wallet.network-link.view
|
||||
(:require
|
||||
[oops.core :refer [oget]]
|
||||
[quo.components.wallet.network-link.helpers :as helpers]
|
||||
[quo.components.wallet.network-link.schema :as component-schema]
|
||||
[quo.components.wallet.network-link.style :as style]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.svg :as svg]
|
||||
[reagent.core :as reagent]
|
||||
[schema.core :as schema]))
|
||||
|
||||
(defn- circle
|
||||
[fill stroke]
|
||||
[svg/svg
|
||||
{:height "8"
|
||||
:width "8"}
|
||||
[svg/circle
|
||||
{:cx "4"
|
||||
:cy "4"
|
||||
:r "3.5"
|
||||
:fill fill
|
||||
:stroke stroke
|
||||
:strokeWidth "1"}]])
|
||||
|
||||
(defn- line
|
||||
[stroke width]
|
||||
[svg/svg
|
||||
{:height "10"
|
||||
:width "100%"
|
||||
:view-box (str "0 0 " width " 10")}
|
||||
[svg/path
|
||||
{:d (str "M0,5 L" width ",5")
|
||||
:stroke stroke
|
||||
:stroke-width "1"}]])
|
||||
|
||||
(defn link-linear
|
||||
[{:keys [source theme]}]
|
||||
[svg/svg {:xmlns "http://www.w3.org/2000/svg" :width "73" :height "10" :fill :none}
|
||||
[svg/path {:stroke (colors/resolve-color source theme) :d "M68 5H5"}]
|
||||
[svg/circle
|
||||
{:cx "68"
|
||||
:cy "5"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color source theme)}]
|
||||
[svg/circle
|
||||
{:cx "5"
|
||||
:cy "5"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color source theme)}]])
|
||||
[]
|
||||
(let [container-width (reagent/atom 100)]
|
||||
(fn [{:keys [source theme]}]
|
||||
(let [stroke-color (colors/resolve-color source theme)
|
||||
fill-color (colors/theme-colors colors/white colors/neutral-90 theme)]
|
||||
[rn/view
|
||||
{:style style/link-linear-container
|
||||
:on-layout (fn [e]
|
||||
(reset! container-width
|
||||
(oget e :nativeEvent :layout :width)))}
|
||||
[line stroke-color @container-width]
|
||||
[rn/view {:style style/left-circle-container}
|
||||
[circle fill-color stroke-color]]
|
||||
[rn/view {:style style/right-circle-container}
|
||||
[circle fill-color stroke-color]]]))))
|
||||
|
||||
(defn link-1x
|
||||
[{:keys [source destination theme]}]
|
||||
[svg/svg {:xmlns "http://www.w3.org/2000/svg" :width "73" :height "66" :fill :none}
|
||||
[svg/path
|
||||
{:stroke "url(#gradient)" :d "M68 5h-9.364c-11.046 0-20 8.954-20 20v16c0 11.046-8.955 20-20 20H5"}]
|
||||
[svg/circle
|
||||
{:cx "68"
|
||||
:cy "5"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color destination theme)}]
|
||||
[svg/circle
|
||||
{:cx "5"
|
||||
:cy "61"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color source theme)}]
|
||||
[svg/defs
|
||||
[svg/linear-gradient
|
||||
{:id "gradient" :x1 "72.271" :x2 "82.385" :y1 "5" :y2 "34.155" :gradientUnits "userSpaceOnUse"}
|
||||
[svg/stop {:stopColor (colors/resolve-color destination theme)}]
|
||||
[svg/stop {:offset "1" :stopColor (colors/resolve-color source theme)}]]]])
|
||||
[]
|
||||
(let [container-width (reagent/atom 100)
|
||||
stroke-color "url(#gradient)"]
|
||||
(fn [{:keys [source destination theme]}]
|
||||
(let [source-color (colors/resolve-color source theme)
|
||||
destination-color (colors/resolve-color destination theme)
|
||||
fill-color (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
view-box (str "0 0 " @container-width " 58")
|
||||
side-lines-path (helpers/calculate-side-lines-path-1x @container-width)
|
||||
central-transform (helpers/calculate-transform @container-width)]
|
||||
[rn/view
|
||||
{:style style/link-1x-container
|
||||
:on-layout (fn [e]
|
||||
(reset! container-width
|
||||
(oget e :nativeEvent :layout :width)))}
|
||||
[svg/svg
|
||||
{:xmlns "http://www.w3.org/2000/svg"
|
||||
:height "100%"
|
||||
:width "100%"
|
||||
:view-box view-box
|
||||
:fill :none}
|
||||
[svg/path
|
||||
{:d (:left side-lines-path)
|
||||
:stroke source-color}]
|
||||
[svg/path
|
||||
{:d
|
||||
"M63 1L53.6356 1C42.5899 1 33.6356 9.9543 33.6356 21L33.6356 37C33.6356 48.0457 24.6813 57 13.6356 57L2.85889e-05 57"
|
||||
:transform central-transform
|
||||
:stroke stroke-color}]
|
||||
[svg/path
|
||||
{:d (:right side-lines-path)
|
||||
:stroke destination-color}]
|
||||
[svg/defs
|
||||
[svg/linear-gradient
|
||||
{:id "gradient"
|
||||
:x1 "72.271"
|
||||
:x2 "82.385"
|
||||
:y1 "5"
|
||||
:y2 "34.155"
|
||||
:gradient-units "userSpaceOnUse"}
|
||||
[svg/stop {:stop-color (colors/resolve-color destination theme)}]
|
||||
[svg/stop {:offset "1" :stop-color (colors/resolve-color source theme)}]]]]
|
||||
[rn/view {:style style/bottom-left-circle-container}
|
||||
[circle fill-color source-color]]
|
||||
[rn/view {:style style/top-right-circle-container}
|
||||
[circle fill-color destination-color]]]))))
|
||||
|
||||
(defn link-2x
|
||||
[{:keys [source destination theme]}]
|
||||
[svg/svg
|
||||
{:width "73" :height "122" :viewBox "0 0 73 122" :fill "none" :xmlns "http://www.w3.org/2000/svg"}
|
||||
[svg/path
|
||||
{:d
|
||||
"M67.9999 5L58.6356 5C47.5899 5 38.6356 13.9543 38.6356 25L38.6356 97C38.6356 108.046 29.6813 117 18.6356 117L5.00006 117"
|
||||
:stroke "url(#gradient)"}]
|
||||
[svg/circle
|
||||
{:cx "68"
|
||||
:cy "5"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color destination theme)}]
|
||||
[svg/circle
|
||||
{:cx "5"
|
||||
:cy "117"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color source theme)}]
|
||||
[svg/defs
|
||||
[svg/linear-gradient
|
||||
{:id "gradient"
|
||||
:x1 "72.2711"
|
||||
:y1 "5.00001"
|
||||
:x2 "102.867"
|
||||
:y2 "49.0993"
|
||||
:gradientUnits "userSpaceOnUse"}
|
||||
[svg/stop {:stop-color (colors/resolve-color destination theme)}]
|
||||
[svg/stop {:offset "1" :stop-color (colors/resolve-color source theme)}]]]])
|
||||
[]
|
||||
(let [container-width (reagent/atom 100)
|
||||
stroke-color "url(#gradient)"]
|
||||
(fn [{:keys [source destination theme]}]
|
||||
(let [source-color (colors/resolve-color source theme)
|
||||
destination-color (colors/resolve-color destination theme)
|
||||
fill-color (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
view-box (str "0 0 " @container-width " 114")
|
||||
side-lines-path (helpers/calculate-side-lines-path-2x @container-width)
|
||||
central-transform (helpers/calculate-transform @container-width)]
|
||||
[rn/view
|
||||
{:style style/link-2x-container
|
||||
:on-layout #(reset! container-width
|
||||
(oget % :nativeEvent :layout :width))}
|
||||
[svg/svg
|
||||
{:xmlns "http://www.w3.org/2000/svg"
|
||||
:height "100%"
|
||||
:width "100%"
|
||||
:view-box view-box
|
||||
:fill :none}
|
||||
[svg/path
|
||||
{:d (:left side-lines-path)
|
||||
:stroke source-color}]
|
||||
[svg/path
|
||||
{:d
|
||||
"M62.9999 1L53.6356 1C42.5899 1 33.6356 9.9543 33.6356 21L33.6356 93C33.6356 104.046 24.6813 113 13.6356 113L5.71778e-05 113"
|
||||
:transform central-transform
|
||||
:stroke stroke-color}]
|
||||
[svg/path
|
||||
{:d (:right side-lines-path)
|
||||
:stroke destination-color}]
|
||||
[svg/defs
|
||||
[svg/linear-gradient
|
||||
{:id "gradient"
|
||||
:x1 "72.2711"
|
||||
:y1 "5.00001"
|
||||
:x2 "102.867"
|
||||
:y2 "49.0993"
|
||||
:gradient-units "userSpaceOnUse"}
|
||||
[svg/stop {:stop-color (colors/resolve-color destination theme)}]
|
||||
[svg/stop {:offset "1" :stop-color (colors/resolve-color source theme)}]]]]
|
||||
[rn/view {:style style/bottom-left-circle-container}
|
||||
[circle fill-color source-color]]
|
||||
[rn/view {:style style/top-right-circle-container}
|
||||
[circle fill-color destination-color]]]))))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [shape container-style] :as props}]
|
||||
|
|
|
@ -448,6 +448,8 @@
|
|||
(def ^:const optimism-short-name "opt")
|
||||
(def ^:const arbitrum-short-name "arb1")
|
||||
|
||||
(def ^:const default-multichain-address-prefix "eth:opt:arb1:")
|
||||
|
||||
(def ^:const mainnet-abbreviated-name "Eth.")
|
||||
(def ^:const optimism-abbreviated-name "Opt.")
|
||||
(def ^:const arbitrum-abbreviated-name "Arb1.")
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.contexts.preview.quo.wallet.network-link
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.preview.quo.preview :as preview]))
|
||||
|
||||
|
@ -23,17 +24,21 @@
|
|||
:options networks}
|
||||
{:key :destination
|
||||
:type :select
|
||||
:options networks}])
|
||||
:options networks}
|
||||
{:key :width
|
||||
:type :number}])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom {:shape :linear
|
||||
:source :ethereum
|
||||
:destination :optimism})]
|
||||
:destination :optimism
|
||||
:width 63})]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
{:state state
|
||||
:descriptor descriptor
|
||||
:component-container-style {:padding-top 40
|
||||
:align-items :center}}
|
||||
[quo/network-link @state]])))
|
||||
[rn/view {:style {:width (max (:width @state) 63)}}
|
||||
[quo/network-link @state]]])))
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
:button-one-label (i18n/label :t/confirm-bridge)
|
||||
:button-one-props {:icon-left :i/bridge}
|
||||
:on-navigate-back (fn []
|
||||
(rf/dispatch [:wallet/clean-disabled-from-networks])
|
||||
(rf/dispatch [:navigate-back]))}]])
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
(ns status-im.contexts.wallet.common.utils.networks
|
||||
(:require [clojure.string :as string]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]))
|
||||
|
||||
(defn resolve-receiver-networks
|
||||
[{:keys [prefix testnet-enabled? goerli-enabled?]}]
|
||||
(let [prefix (if (string/blank? prefix)
|
||||
constants/default-multichain-address-prefix
|
||||
prefix)
|
||||
prefix-seq (string/split prefix #":")]
|
||||
(->> prefix-seq
|
||||
(remove string/blank?)
|
||||
(mapv
|
||||
#(utils/network->chain-id
|
||||
{:network %
|
||||
:testnet-enabled? testnet-enabled?
|
||||
:goerli-enabled? goerli-enabled?})))))
|
|
@ -1,5 +1,6 @@
|
|||
(ns status-im.contexts.wallet.common.utils.send
|
||||
(:require [utils.money :as money]))
|
||||
(:require [clojure.string :as string]
|
||||
[utils.money :as money]))
|
||||
|
||||
(defn calculate-gas-fee
|
||||
[data]
|
||||
|
@ -20,3 +21,17 @@
|
|||
(defn calculate-full-route-gas-fee
|
||||
[route]
|
||||
(reduce money/add (map calculate-gas-fee route)))
|
||||
|
||||
(defn find-affordable-networks
|
||||
[{:keys [balances-per-chain input-value selected-networks disabled-chain-ids]}]
|
||||
(let [input-value (if (string/blank? input-value) 0 input-value)]
|
||||
(->> balances-per-chain
|
||||
(filter (fn [[_
|
||||
{:keys [balance chain-id]
|
||||
:or {balance 0}}]]
|
||||
(and
|
||||
(money/greater-than-or-equals (money/bignumber balance)
|
||||
(money/bignumber input-value))
|
||||
(some #(= % chain-id) selected-networks)
|
||||
(not-any? #(= % chain-id) disabled-chain-ids))))
|
||||
(map first))))
|
||||
|
|
|
@ -20,3 +20,44 @@
|
|||
expected-eip1559-disabled-result (money/bignumber 0.000760406)]
|
||||
(is (money/equal-to (utils/calculate-gas-fee data-eip1559-disabled)
|
||||
expected-eip1559-disabled-result))))))
|
||||
|
||||
(deftest test-find-affordable-networks
|
||||
(testing "All networks affordable and selected, none disabled"
|
||||
(let [balances-per-chain {"1" {:balance "50.0" :chain-id "1"}
|
||||
"2" {:balance "40.0" :chain-id "2"}}
|
||||
input-value 20
|
||||
selected-networks ["1" "2"]
|
||||
disabled-chain-ids []
|
||||
expected ["1" "2"]]
|
||||
(is (= (set (utils/find-affordable-networks {:balances-per-chain balances-per-chain
|
||||
:input-value input-value
|
||||
:selected-networks selected-networks
|
||||
:disabled-chain-ids disabled-chain-ids}))
|
||||
(set expected)))))
|
||||
|
||||
(testing "No networks affordable"
|
||||
(let [balances-per-chain {"1" {:balance "5.0" :chain-id "1"}
|
||||
"2" {:balance "1.0" :chain-id "2"}}
|
||||
input-value 10
|
||||
selected-networks ["1" "2"]
|
||||
disabled-chain-ids []
|
||||
expected []]
|
||||
(is (= (set (utils/find-affordable-networks {:balances-per-chain balances-per-chain
|
||||
:input-value input-value
|
||||
:selected-networks selected-networks
|
||||
:disabled-chain-ids disabled-chain-ids}))
|
||||
(set expected)))))
|
||||
|
||||
(testing "Selected networks subset, with some disabled"
|
||||
(let [balances-per-chain {"1" {:balance "100.0" :chain-id "1"}
|
||||
"2" {:balance "50.0" :chain-id "2"}
|
||||
"3" {:balance "20.0" :chain-id "3"}}
|
||||
input-value 15
|
||||
selected-networks ["1" "2" "3"]
|
||||
disabled-chain-ids ["2"]
|
||||
expected ["1" "3"]]
|
||||
(is (= (set (utils/find-affordable-networks {:balances-per-chain balances-per-chain
|
||||
:input-value input-value
|
||||
:selected-networks selected-networks
|
||||
:disabled-chain-ids disabled-chain-ids}))
|
||||
(set expected))))))
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
[native-module.core :as native-module]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.common.utils.networks :as network-utils]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
|
@ -24,45 +25,71 @@
|
|||
(rf/reg-event-fx :wallet/suggested-routes-success
|
||||
(fn [{:keys [db]} [suggested-routes timestamp]]
|
||||
(when (= (get-in db [:wallet :ui :send :suggested-routes-call-timestamp]) timestamp)
|
||||
(let [suggested-routes-data (cske/transform-keys transforms/->kebab-case-keyword suggested-routes)
|
||||
chosen-route (:best suggested-routes-data)]
|
||||
(let [suggested-routes-data (cske/transform-keys transforms/->kebab-case-keyword
|
||||
suggested-routes)
|
||||
chosen-route (:best suggested-routes-data)
|
||||
token (get-in db [:wallet :ui :send :token])
|
||||
collectible (get-in db [:wallet :ui :send :collectible])
|
||||
token-display-name (get-in db [:wallet :ui :send :token-display-name])
|
||||
token-decimals (if collectible 0 (:decimals token))
|
||||
native-token? (and token (= token-display-name "ETH"))
|
||||
from-network-amounts-by-chain (send-utils/network-amounts-by-chain {:route chosen-route
|
||||
:token-decimals
|
||||
token-decimals
|
||||
:native-token?
|
||||
native-token?
|
||||
:to? false})
|
||||
from-network-values-for-ui (send-utils/network-values-for-ui from-network-amounts-by-chain)
|
||||
to-network-amounts-by-chain (send-utils/network-amounts-by-chain {:route chosen-route
|
||||
:token-decimals
|
||||
token-decimals
|
||||
:native-token?
|
||||
native-token?
|
||||
:to? true})
|
||||
to-network-values-for-ui (send-utils/network-values-for-ui to-network-amounts-by-chain)]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :suggested-routes] suggested-routes-data)
|
||||
(assoc-in [:wallet :ui :send :route] chosen-route)
|
||||
(assoc-in [:wallet :ui :send :from-values-by-chain] from-network-values-for-ui)
|
||||
(assoc-in [:wallet :ui :send :to-values-by-chain] to-network-values-for-ui)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false))}))))
|
||||
|
||||
(rf/reg-event-fx :wallet/suggested-routes-error
|
||||
(fn [{:keys [db]} [_error]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :suggested-routes)
|
||||
(update-in [:wallet :ui :send] dissoc :route)
|
||||
(update-in [:wallet :ui :send] dissoc :suggested-routes :route)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false))}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-suggested-routes
|
||||
(fn [{:keys [db]}]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :suggested-routes)
|
||||
(update-in [:wallet :ui :send] dissoc :route)
|
||||
(update-in [:wallet :ui :send] dissoc :loading-suggested-routes?))}))
|
||||
{:db (update-in db
|
||||
[:wallet :ui :send]
|
||||
dissoc
|
||||
:suggested-routes
|
||||
:route
|
||||
:from-values-by-chain
|
||||
:to-values-by-chain
|
||||
:loading-suggested-routes?
|
||||
:suggested-routes-call-timestamp)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-send-address
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui :send] dissoc :recipient :to-address)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-disabled-from-networks
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui :send] dissoc :disabled-from-chain-ids)}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/select-send-address
|
||||
(fn [{:keys [db]} [{:keys [address recipient stack-id start-flow?]}]]
|
||||
(let [[prefix to-address] (utils/split-prefix-and-address address)
|
||||
testnet-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
goerli-enabled? (get-in db [:profile/profile :is-goerli-enabled?])
|
||||
prefix-seq (string/split prefix #":")
|
||||
selected-networks (->> prefix-seq
|
||||
(remove string/blank?)
|
||||
(mapv
|
||||
#(utils/network->chain-id
|
||||
{:network %
|
||||
:testnet-enabled? testnet-enabled?
|
||||
:goerli-enabled? goerli-enabled?})))]
|
||||
selected-networks (network-utils/resolve-receiver-networks
|
||||
{:prefix prefix
|
||||
:testnet-enabled? testnet-enabled?
|
||||
:goerli-enabled? goerli-enabled?})]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :recipient] (or recipient address))
|
||||
(assoc-in [:wallet :ui :send :to-address] to-address)
|
||||
|
@ -84,7 +111,8 @@
|
|||
(fn [{:keys [db]} [{:keys [token stack-id start-flow?]}]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :collectible)
|
||||
(assoc-in [:wallet :ui :send :token] token))
|
||||
(assoc-in [:wallet :ui :send :token] token)
|
||||
(assoc-in [:wallet :ui :send :token-display-name] (:symbol token)))
|
||||
:fx [[:dispatch [:wallet/clean-suggested-routes]]
|
||||
[:dispatch
|
||||
[:wallet/wizard-navigate-forward
|
||||
|
@ -95,13 +123,15 @@
|
|||
(rf/reg-event-fx
|
||||
:wallet/edit-token-to-send
|
||||
(fn [{:keys [db]} [token]]
|
||||
{:db (assoc-in db [:wallet :ui :send :token] token)
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :token] token)
|
||||
(assoc-in [:wallet :ui :send :token-display-name] token))
|
||||
:fx [[:dispatch [:hide-bottom-sheet]]
|
||||
[:dispatch [:wallet/clean-suggested-routes]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-selected-token
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui :send] dissoc :token :tx-type)}))
|
||||
{: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]}]
|
||||
|
@ -110,18 +140,30 @@
|
|||
[:wallet :ui :send]
|
||||
dissoc
|
||||
:collectible
|
||||
:token-display-name
|
||||
:amount
|
||||
(when (= transaction-type :collecible) :tx-type))})))
|
||||
|
||||
(rf/reg-event-fx :wallet/send-collectibles-amount
|
||||
(fn [{:keys [db]} [{:keys [collectible stack-id amount]}]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :token)
|
||||
(assoc-in [:wallet :ui :send :collectible] collectible)
|
||||
(assoc-in [:wallet :ui :send :tx-type] :collectible)
|
||||
(assoc-in [:wallet :ui :send :amount] amount))
|
||||
:fx [[:dispatch [:wallet/get-suggested-routes {:amount amount}]]
|
||||
[:navigate-to-within-stack [:screen/wallet.transaction-confirmation stack-id]]]}))
|
||||
(let [collection-data (:collection-data collectible)
|
||||
collectible-data (:collectible-data collectible)
|
||||
collectible-id (get-in collectible [:id :token-id])
|
||||
token-display-name (cond
|
||||
(and collectible
|
||||
(not (string/blank? (:name collectible-data))))
|
||||
(:name collectible-data)
|
||||
|
||||
collectible
|
||||
(str (:name collection-data) " #" collectible-id))]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :token)
|
||||
(assoc-in [:wallet :ui :send :collectible] collectible)
|
||||
(assoc-in [:wallet :ui :send :token-display-name] token-display-name)
|
||||
(assoc-in [:wallet :ui :send :tx-type] :collectible)
|
||||
(assoc-in [:wallet :ui :send :amount] amount))
|
||||
:fx [[:dispatch [:wallet/get-suggested-routes {:amount amount}]]
|
||||
[:navigate-to-within-stack [:screen/wallet.transaction-confirmation stack-id]]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet/select-collectibles-amount
|
||||
(fn [{:keys [db]} [{:keys [collectible stack-id]}]]
|
||||
|
@ -140,6 +182,12 @@
|
|||
:start-flow? start-flow?
|
||||
:flow-id :wallet-flow}]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/disable-from-networks
|
||||
(fn [{:keys [db]} [chain-ids]]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :disabled-from-chain-ids] chain-ids)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] true))}))
|
||||
|
||||
(rf/reg-event-fx :wallet/get-suggested-routes
|
||||
(fn [{:keys [db now]} [{:keys [amount]}]]
|
||||
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
|
||||
|
@ -147,6 +195,7 @@
|
|||
transaction-type (get-in db [:wallet :ui :send :tx-type])
|
||||
collectible (get-in db [:wallet :ui :send :collectible])
|
||||
to-address (get-in db [:wallet :ui :send :to-address])
|
||||
disabled-from-chain-ids (or (get-in db [:wallet :ui :send :disabled-from-chain-ids]) [])
|
||||
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
networks ((if test-networks-enabled? :test :prod)
|
||||
(get-in db [:wallet :networks]))
|
||||
|
@ -163,7 +212,7 @@
|
|||
gas-rates constants/gas-rate-medium
|
||||
amount-in (send-utils/amount-in-hex amount (if token token-decimal 0))
|
||||
from-address wallet-address
|
||||
disabled-from-chain-ids []
|
||||
disabled-from-chain-ids disabled-from-chain-ids
|
||||
disabled-to-chain-ids (if (= transaction-type :bridge)
|
||||
(filter #(not= % bridge-to-chain-id) network-chain-ids)
|
||||
[])
|
||||
|
@ -218,6 +267,7 @@
|
|||
{:fx [[:dispatch [:wallet/clean-scanned-address]]
|
||||
[:dispatch [:wallet/clean-local-suggestions]]
|
||||
[:dispatch [:wallet/clean-send-address]]
|
||||
[:dispatch [:wallet/clean-disabled-from-networks]]
|
||||
[:dispatch [:wallet/select-address-tab nil]]
|
||||
[:dispatch [:dismiss-modal :screen/wallet.transaction-progress]]]}))
|
||||
|
||||
|
|
|
@ -5,60 +5,75 @@
|
|||
[status-im.contexts.wallet.send.input-amount.view :as input-amount]
|
||||
[test-helpers.component :as h]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.money :as money]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(set! rf/dispatch #())
|
||||
(set! debounce/debounce-and-dispatch #())
|
||||
|
||||
(def sub-mocks
|
||||
{:profile/profile {:currency :usd}
|
||||
:wallet/selected-network-details [{:source 525
|
||||
:short-name "eth"
|
||||
:network-name :mainnet
|
||||
:chain-id 1
|
||||
:related-chain-id 5}]
|
||||
:wallet/current-viewing-account {:path "m/44'/60'/0'/0/1"
|
||||
:emoji "💎"
|
||||
:key-uid "0x2f5ea39"
|
||||
:address "0x1"
|
||||
:wallet false
|
||||
:name "Account One"
|
||||
:type :generated
|
||||
:watch-only? false
|
||||
:chat false
|
||||
:test-preferred-chain-ids #{5 420 421613}
|
||||
:color :purple
|
||||
:hidden false
|
||||
:prod-preferred-chain-ids #{1 10 42161}
|
||||
:network-preferences-names #{:mainnet :arbitrum
|
||||
:optimism}
|
||||
:position 1
|
||||
:clock 1698945829328
|
||||
:created-at 1698928839000
|
||||
:operable "fully"
|
||||
:mixedcase-address "0x7bcDfc75c431"
|
||||
:public-key "0x04371e2d9d66b82f056bc128064"
|
||||
:removed false}
|
||||
:wallet/wallet-send-token {:symbol :eth
|
||||
:total-balance 100
|
||||
:market-values-per-currency {:usd {:price 10}}}
|
||||
:wallet/wallet-send-loading-suggested-routes? false
|
||||
: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 []
|
||||
:view-id :screen/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}}}})
|
||||
{:profile/profile {:currency :usd}
|
||||
:wallet/selected-network-details [{:source 525
|
||||
:short-name "eth"
|
||||
:network-name :mainnet
|
||||
:chain-id 1
|
||||
:related-chain-id 5}]
|
||||
:wallet/current-viewing-account {:path "m/44'/60'/0'/0/1"
|
||||
:emoji "💎"
|
||||
:key-uid "0x2f5ea39"
|
||||
:address "0x1"
|
||||
:wallet false
|
||||
:name "Account One"
|
||||
:type :generated
|
||||
:watch-only? false
|
||||
:chat false
|
||||
:test-preferred-chain-ids #{5 420 421613}
|
||||
:color :purple
|
||||
:hidden false
|
||||
:prod-preferred-chain-ids #{1 10 42161}
|
||||
:network-preferences-names #{:mainnet :arbitrum
|
||||
:optimism}
|
||||
:position 1
|
||||
:clock 1698945829328
|
||||
:created-at 1698928839000
|
||||
:operable "fully"
|
||||
:mixedcase-address "0x7bcDfc75c431"
|
||||
:public-key "0x04371e2d9d66b82f056bc128064"
|
||||
:removed false}
|
||||
:wallet/wallet-send-token {:symbol :eth
|
||||
:networks [{:source 879
|
||||
:short-name "eth"
|
||||
:network-name :mainnet
|
||||
:abbreviated-name "Eth."
|
||||
:chain-id 1
|
||||
:related-chain-id 1
|
||||
:layer 1}]}
|
||||
:wallet/current-viewing-account-tokens-filtered {:balances-per-chain {1 {:raw-balance
|
||||
(money/bignumber
|
||||
"2500")
|
||||
:has-error false}}
|
||||
:total-balance 100
|
||||
:market-values-per-currency {:usd {:price 10}}}
|
||||
:wallet/wallet-send-loading-suggested-routes? false
|
||||
: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 [1]
|
||||
:view-id :screen/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}}}
|
||||
:wallet/wallet-send-disabled-from-chain-ids []
|
||||
:wallet/wallet-send-from-values-by-chain {1 (money/bignumber "250")}
|
||||
:wallet/wallet-send-to-values-by-chain {1 (money/bignumber "250")}})
|
||||
|
||||
(h/describe "Send > input amount screen"
|
||||
(h/setup-restorable-re-frame)
|
||||
|
|
|
@ -190,8 +190,9 @@
|
|||
(reset-input-error num-value current-limit-amount input-error)
|
||||
(reagent/flush))))
|
||||
on-navigate-back on-navigate-back
|
||||
fetch-routes (fn [input-num-value current-limit-amount]
|
||||
(let [nav-current-screen-id (rf/sub [:view-id])]
|
||||
fetch-routes (fn [input-num-value current-limit-amount bounce-duration-ms]
|
||||
(let [nav-current-screen-id (rf/sub [:view-id])
|
||||
input-num-value (or input-num-value 0)]
|
||||
; this check is to prevent effect being triggered when screen is
|
||||
; loaded but not being shown to the user (deep in the navigation
|
||||
; stack) and avoid undesired behaviors
|
||||
|
@ -201,7 +202,7 @@
|
|||
(> input-num-value current-limit-amount))
|
||||
(debounce/debounce-and-dispatch
|
||||
[:wallet/get-suggested-routes {:amount @input-value}]
|
||||
2000)
|
||||
bounce-duration-ms)
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])))))
|
||||
handle-on-confirm (fn []
|
||||
(rf/dispatch [:wallet/send-select-amount
|
||||
|
@ -215,65 +216,92 @@
|
|||
(reset! input-selection selection)
|
||||
(reagent/flush))]
|
||||
(fn []
|
||||
(let [{fiat-currency :currency} (rf/sub [:profile/profile])
|
||||
{token-balance :total-balance
|
||||
token-symbol :symbol
|
||||
token-networks :networks
|
||||
:as token} (rf/sub [:wallet/wallet-send-token])
|
||||
conversion-rate (-> token :market-values-per-currency :usd :price)
|
||||
loading-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
|
||||
best-routes (when suggested-routes (or (:best 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))
|
||||
crypto-limit (or default-limit-crypto
|
||||
(utils/get-standard-crypto-format token token-balance))
|
||||
fiat-limit (.toFixed (* token-balance conversion-rate) 2)
|
||||
current-limit #(if @crypto-currency? crypto-limit fiat-limit)
|
||||
current-currency (if @crypto-currency? token-symbol fiat-currency)
|
||||
limit-label (make-limit-label {:amount (current-limit)
|
||||
:currency current-currency})
|
||||
input-num-value (parse-double @input-value)
|
||||
confirm-disabled? (or (nil? route)
|
||||
(empty? route)
|
||||
(empty? @input-value)
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (current-limit)))
|
||||
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-full-route-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/calculate-token-fiat-value
|
||||
{:currency fiat-currency
|
||||
:balance fee-in-native-token
|
||||
: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))
|
||||
show-select-asset-sheet #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[select-asset-bottom-sheet clear-input!])}])]
|
||||
(let [{fiat-currency :currency} (rf/sub [:profile/profile])
|
||||
{token-symbol :symbol
|
||||
token-networks :networks} (rf/sub [:wallet/wallet-send-token])
|
||||
{token-balance :total-balance
|
||||
token-balances-per-chain :balances-per-chain
|
||||
:as
|
||||
token} (rf/sub
|
||||
[:wallet/current-viewing-account-tokens-filtered
|
||||
(str token-symbol)])
|
||||
conversion-rate (-> token :market-values-per-currency :usd :price)
|
||||
loading-routes? (rf/sub
|
||||
[:wallet/wallet-send-loading-suggested-routes?])
|
||||
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
|
||||
best-routes (when suggested-routes
|
||||
(or (:best suggested-routes) []))
|
||||
route (rf/sub [:wallet/wallet-send-route])
|
||||
to-address (rf/sub [:wallet/wallet-send-to-address])
|
||||
disabled-from-chain-ids (rf/sub
|
||||
[:wallet/wallet-send-disabled-from-chain-ids])
|
||||
from-values-by-chain (rf/sub [:wallet/wallet-send-from-values-by-chain])
|
||||
to-values-by-chain (rf/sub [:wallet/wallet-send-to-values-by-chain])
|
||||
on-confirm (or default-on-confirm handle-on-confirm)
|
||||
crypto-decimals (or default-crypto-decimals
|
||||
(utils/get-crypto-decimals-count token))
|
||||
crypto-limit (or default-limit-crypto
|
||||
(utils/get-standard-crypto-format
|
||||
token
|
||||
token-balance))
|
||||
fiat-limit (.toFixed (* token-balance conversion-rate) 2)
|
||||
current-limit #(if @crypto-currency? crypto-limit fiat-limit)
|
||||
current-currency (if @crypto-currency? token-symbol fiat-currency)
|
||||
limit-label (make-limit-label {:amount (current-limit)
|
||||
:currency current-currency})
|
||||
input-num-value (parse-double @input-value)
|
||||
confirm-disabled? (or (nil? route)
|
||||
(empty? route)
|
||||
(empty? @input-value)
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (current-limit)))
|
||||
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-full-route-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/calculate-token-fiat-value
|
||||
{:currency fiat-currency
|
||||
:balance fee-in-native-token
|
||||
: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))
|
||||
show-select-asset-sheet #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[select-asset-bottom-sheet
|
||||
clear-input!])}])
|
||||
selected-networks (rf/sub [:wallet/wallet-send-selected-networks])
|
||||
affordable-networks (send-utils/find-affordable-networks
|
||||
{:balances-per-chain token-balances-per-chain
|
||||
:input-value @input-value
|
||||
:selected-networks selected-networks
|
||||
:disabled-chain-ids disabled-from-chain-ids})]
|
||||
(rn/use-mount
|
||||
(fn []
|
||||
(let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!))
|
||||
app-keyboard-listener (.addEventListener rn/app-state "change" dismiss-keyboard-fn)]
|
||||
#(.remove app-keyboard-listener))))
|
||||
(rn/use-effect
|
||||
#(fetch-routes input-num-value (current-limit))
|
||||
#(when (> (count affordable-networks) 0)
|
||||
(fetch-routes input-num-value (current-limit) 2000))
|
||||
[@input-value])
|
||||
(rn/use-effect
|
||||
#(when (> (count affordable-networks) 0)
|
||||
(fetch-routes input-num-value (current-limit) 0))
|
||||
[disabled-from-chain-ids])
|
||||
[rn/view
|
||||
{:style style/screen
|
||||
:accessibility-label (str "container" (when @input-error "-error"))}
|
||||
|
@ -303,11 +331,28 @@
|
|||
:limit-crypto crypto-limit})
|
||||
:on-token-press show-select-asset-sheet}]
|
||||
[routes/view
|
||||
{:amount amount-text
|
||||
:routes best-routes
|
||||
:token token
|
||||
:input-value @input-value
|
||||
:fetch-routes #(fetch-routes % (current-limit))}]
|
||||
{:from-values-by-chain from-values-by-chain
|
||||
:to-values-by-chain to-values-by-chain
|
||||
:affordable-networks affordable-networks
|
||||
:routes best-routes
|
||||
:token token
|
||||
:input-value @input-value
|
||||
:fetch-routes #(fetch-routes % (current-limit) 2000)
|
||||
:disabled-from-networks disabled-from-chain-ids
|
||||
:on-press-from-network (fn [chain-id _]
|
||||
(let [disabled-chain-ids (if (contains? (set
|
||||
disabled-from-chain-ids)
|
||||
chain-id)
|
||||
(vec (remove #(= % chain-id)
|
||||
disabled-from-chain-ids))
|
||||
(conj disabled-from-chain-ids
|
||||
chain-id))
|
||||
re-enabling-chain? (< (count disabled-chain-ids)
|
||||
(count disabled-from-chain-ids))]
|
||||
(when (or re-enabling-chain?
|
||||
(> (count affordable-networks) 1))
|
||||
(rf/dispatch [:wallet/disable-from-networks
|
||||
disabled-chain-ids]))))}]
|
||||
(when (or loading-routes? (seq route))
|
||||
[estimated-fees
|
||||
{:loading-suggested-routes? loading-routes?
|
||||
|
|
|
@ -12,20 +12,23 @@
|
|||
{:flex-direction :row
|
||||
:justify-content :space-between})
|
||||
|
||||
(def routes-inner-container
|
||||
{:margin-top 8
|
||||
(defn routes-inner-container
|
||||
[first-item?]
|
||||
{:margin-top (if first-item? 7.5 11)
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between})
|
||||
|
||||
(defn section-label
|
||||
[margin-left]
|
||||
{:flex 0.5
|
||||
:margin-left margin-left})
|
||||
(def section-label-right
|
||||
{:width 135})
|
||||
|
||||
(def section-label-left
|
||||
{:width 136})
|
||||
|
||||
(def network-link
|
||||
{:right 6
|
||||
:z-index 1})
|
||||
{:margin-horizontal -1.5
|
||||
:z-index 1
|
||||
:flex 1})
|
||||
|
||||
(def empty-container
|
||||
{:flex-grow 1
|
||||
|
@ -33,9 +36,8 @@
|
|||
:justify-content :center})
|
||||
|
||||
(def add-network
|
||||
{:margin-top 8
|
||||
:align-self :flex-end
|
||||
:right 12})
|
||||
{:margin-top 11
|
||||
:align-self :flex-end})
|
||||
|
||||
(defn warning-container
|
||||
[color theme]
|
||||
|
|
|
@ -7,19 +7,17 @@
|
|||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.routes.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[utils.vector :as vector-utils]))
|
||||
|
||||
(defn- find-affordable-networks
|
||||
[{:keys [balances-per-chain]} input-value selected-networks]
|
||||
(->> balances-per-chain
|
||||
(filter (fn [[_ {:keys [balance chain-id]}]]
|
||||
(and
|
||||
(>= (js/parseFloat balance) input-value)
|
||||
(some #(= % chain-id) selected-networks))))
|
||||
(map first)))
|
||||
(def ^:private network-priority-score
|
||||
{:ethereum 1
|
||||
:optimism 2
|
||||
:arbitrum 3})
|
||||
|
||||
(defn- make-network-item
|
||||
[{:keys [network-name chain-id] :as _network}
|
||||
|
@ -34,6 +32,36 @@
|
|||
:checked? (some #(= % chain-id) @network-preferences)
|
||||
:on-change on-change}})
|
||||
|
||||
(defn- find-network-link-insertion-index
|
||||
[network-links chain-id loading-suggested-routes?]
|
||||
(let [network (utils/id->network chain-id)
|
||||
inserted-network-link-priority-score (network-priority-score network)]
|
||||
(or (->> network-links
|
||||
(keep-indexed (fn [idx network-link]
|
||||
(let [network-link (utils/id->network (if loading-suggested-routes?
|
||||
network-link
|
||||
(get-in network-link
|
||||
[:from :chain-id])))]
|
||||
(when (> (network-priority-score network-link)
|
||||
inserted-network-link-priority-score)
|
||||
idx))))
|
||||
first)
|
||||
(count network-links))))
|
||||
|
||||
(defn- add-disabled-networks
|
||||
[network-links disabled-from-networks loading-suggested-routes?]
|
||||
(let [sorted-networks (sort-by (comp network-priority-score utils/id->network) disabled-from-networks)]
|
||||
(reduce (fn [acc-network-links chain-id]
|
||||
(let [index (find-network-link-insertion-index acc-network-links
|
||||
chain-id
|
||||
loading-suggested-routes?)
|
||||
disabled-network-link {:status :disabled
|
||||
:chain-id chain-id
|
||||
:network (utils/id->network chain-id)}]
|
||||
(vector-utils/insert-element-at acc-network-links disabled-network-link index)))
|
||||
network-links
|
||||
sorted-networks)))
|
||||
|
||||
(defn networks-drawer
|
||||
[{:keys [fetch-routes theme]}]
|
||||
(let [network-details (rf/sub [:wallet/network-details])
|
||||
|
@ -90,7 +118,9 @@
|
|||
:customization-color color}}]])))
|
||||
|
||||
(defn route-item
|
||||
[{:keys [amount from-network to-network status theme fetch-routes]}]
|
||||
[{:keys [first-item? from-amount to-amount token-symbol from-chain-id to-chain-id from-network
|
||||
to-network on-press-from-network on-press-to-network status theme fetch-routes disabled?
|
||||
loading?]}]
|
||||
(if (= status :add)
|
||||
[quo/network-bridge
|
||||
{:status :add
|
||||
|
@ -99,59 +129,115 @@
|
|||
{:content (fn [] [networks-drawer
|
||||
{:theme theme
|
||||
:fetch-routes fetch-routes}])}])}]
|
||||
[rn/view {:style style/routes-inner-container}
|
||||
[rn/view {:style (style/routes-inner-container first-item?)}
|
||||
[quo/network-bridge
|
||||
{:amount amount
|
||||
:network from-network
|
||||
:status status}]
|
||||
{:amount (str from-amount " " token-symbol)
|
||||
:network from-network
|
||||
:status status
|
||||
:on-press #(when (and on-press-from-network (not loading?))
|
||||
(on-press-from-network from-chain-id from-amount))}]
|
||||
(if (= status :default)
|
||||
[quo/network-link
|
||||
{:shape :linear
|
||||
:source from-network
|
||||
:destination to-network
|
||||
:container-style style/network-link}]
|
||||
[rn/view {:style {:width 73}}])
|
||||
[rn/view {:style {:flex 1}}])
|
||||
[quo/network-bridge
|
||||
{:amount amount
|
||||
:network to-network
|
||||
:status status
|
||||
:container-style {:right 12}}]]))
|
||||
{:amount (str to-amount " " token-symbol)
|
||||
:network to-network
|
||||
:status (cond
|
||||
(and disabled? loading?) :loading
|
||||
(and disabled? (not loading?)) :default
|
||||
:else status)
|
||||
:on-press #(when (and on-press-to-network (not loading?))
|
||||
(on-press-to-network to-chain-id to-amount))}]]))
|
||||
|
||||
(defn- render-network-link
|
||||
[item index _
|
||||
{:keys [from-values-by-chain to-values-by-chain theme fetch-routes on-press-from-network
|
||||
on-press-to-network token-symbol loading-suggested-routes?]}]
|
||||
(let [first-item? (zero? index)
|
||||
disabled-network? (= (:status item) :disabled)
|
||||
from-chain-id (get-in item [:from :chain-id])
|
||||
to-chain-id (get-in item [:to :chain-id])
|
||||
from-amount (when from-chain-id
|
||||
(from-values-by-chain from-chain-id))
|
||||
to-amount (when to-chain-id
|
||||
(to-values-by-chain to-chain-id))]
|
||||
[route-item
|
||||
{:first-item? first-item?
|
||||
:from-amount (if disabled-network? 0 from-amount)
|
||||
:to-amount (if disabled-network? 0 to-amount)
|
||||
:token-symbol token-symbol
|
||||
:disabled? disabled-network?
|
||||
:loading? loading-suggested-routes?
|
||||
:theme theme
|
||||
:fetch-routes fetch-routes
|
||||
:status (cond
|
||||
(= (:status item) :add) :add
|
||||
(= (:status item) :disabled) :disabled
|
||||
loading-suggested-routes? :loading
|
||||
:else :default)
|
||||
:from-chain-id (or from-chain-id (:chain-id item))
|
||||
:to-chain-id (or to-chain-id (:chain-id item))
|
||||
:from-network (cond (and loading-suggested-routes?
|
||||
(not disabled-network?))
|
||||
(utils/id->network item)
|
||||
disabled-network?
|
||||
(utils/id->network (:chain-id
|
||||
item))
|
||||
:else
|
||||
(utils/id->network from-chain-id))
|
||||
:to-network (cond (and loading-suggested-routes?
|
||||
(not disabled-network?))
|
||||
(utils/id->network item)
|
||||
disabled-network?
|
||||
(utils/id->network (:chain-id
|
||||
item))
|
||||
:else
|
||||
(utils/id->network to-chain-id))
|
||||
:on-press-from-network on-press-from-network
|
||||
:on-press-to-network on-press-to-network}]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [amount routes token input-value theme fetch-routes]}]
|
||||
(let [selected-networks (rf/sub [:wallet/wallet-send-selected-networks])
|
||||
loading-networks (find-affordable-networks token input-value selected-networks)
|
||||
[{:keys [from-values-by-chain to-values-by-chain routes token theme fetch-routes
|
||||
affordable-networks disabled-from-networks on-press-from-network on-press-to-network]}]
|
||||
(let [token-symbol (:symbol token)
|
||||
loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
data (if loading-suggested-routes? loading-networks routes)]
|
||||
(if (or (and (not-empty loading-networks) loading-suggested-routes?) (not-empty routes))
|
||||
[rn/flat-list
|
||||
{:data (if (and (< (count data) 3) (pos? (count data)))
|
||||
(concat data [{:status :add}])
|
||||
data)
|
||||
:content-container-style style/routes-container
|
||||
:header [rn/view {:style style/routes-header-container}
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/from-label)
|
||||
:container-style (style/section-label 0)}]
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/to-label)
|
||||
:container-style (style/section-label 64)}]]
|
||||
:render-fn (fn [item]
|
||||
[route-item
|
||||
{:amount amount
|
||||
:theme theme
|
||||
:fetch-routes fetch-routes
|
||||
:status (cond
|
||||
(= (:status item) :add) :add
|
||||
loading-suggested-routes? :loading
|
||||
:else :default)
|
||||
:from-network (if loading-suggested-routes?
|
||||
(utils/id->network item)
|
||||
(utils/id->network (get-in item [:from :chain-id])))
|
||||
:to-network (if loading-suggested-routes?
|
||||
(utils/id->network item)
|
||||
(utils/id->network (get-in item
|
||||
[:to :chain-id])))}])}]
|
||||
network-links (if loading-suggested-routes? affordable-networks routes)]
|
||||
(if (or (and (not-empty affordable-networks) loading-suggested-routes?) (not-empty routes))
|
||||
(let [initial-network-links-count (count network-links)
|
||||
disabled-count (count disabled-from-networks)
|
||||
network-links (if (not-empty disabled-from-networks)
|
||||
(add-disabled-networks network-links
|
||||
disabled-from-networks
|
||||
loading-suggested-routes?)
|
||||
network-links)
|
||||
network-links-with-add-button (if (and (< (- (count network-links) disabled-count)
|
||||
constants/default-network-count)
|
||||
(pos? initial-network-links-count))
|
||||
(concat network-links [{:status :add}])
|
||||
network-links)]
|
||||
[rn/flat-list
|
||||
{:data network-links-with-add-button
|
||||
:content-container-style style/routes-container
|
||||
:header [rn/view {:style style/routes-header-container}
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/from-label)
|
||||
:container-style style/section-label-left}]
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/to-label)
|
||||
:container-style style/section-label-right}]]
|
||||
:render-data {:from-values-by-chain from-values-by-chain
|
||||
:to-values-by-chain to-values-by-chain
|
||||
:theme theme
|
||||
:fetch-routes fetch-routes
|
||||
:on-press-from-network on-press-from-network
|
||||
:on-press-to-network on-press-to-network
|
||||
:token-symbol token-symbol
|
||||
:loading-suggested-routes? loading-suggested-routes?}
|
||||
:render-fn render-network-link}])
|
||||
[rn/view {:style style/empty-container}
|
||||
(when (and (not (nil? routes)) (not loading-suggested-routes?))
|
||||
[quo/text (i18n/label :t/no-routes-found)])])))
|
||||
|
|
|
@ -132,6 +132,7 @@
|
|||
(rf/dispatch [:wallet/clean-selected-token])
|
||||
(rf/dispatch [:wallet/clean-selected-collectible])
|
||||
(rf/dispatch [:wallet/clean-send-address])
|
||||
(rf/dispatch [:wallet/clean-disabled-from-networks])
|
||||
(rf/dispatch [:wallet/select-address-tab nil])
|
||||
(rf/dispatch [:navigate-back]))
|
||||
on-change-tab #(rf/dispatch [:wallet/select-address-tab %])
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
[input-amount/view
|
||||
{:current-screen-id :screen/wallet.send-input-amount
|
||||
:button-one-label (i18n/label :t/confirm)
|
||||
:on-navigate-back #(rf/dispatch [:navigate-back])}])
|
||||
:on-navigate-back (fn []
|
||||
(rf/dispatch [:wallet/clean-disabled-from-networks])
|
||||
(rf/dispatch [:navigate-back]))}])
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
(ns status-im.contexts.wallet.send.transaction-confirmation.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.utils.hex :as utils.hex]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[native-module.core :as native-module]
|
||||
[quo.core :as quo]
|
||||
[quo.theme :as quo.theme]
|
||||
[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.common.standard-authentication.core :as standard-auth]
|
||||
[status-im.contexts.wallet.common.utils :as wallet-utils]
|
||||
[status-im.contexts.wallet.send.transaction-confirmation.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(defn- transaction-title
|
||||
[{:keys [token-symbol amount account to-address route to-network image-url transaction-type
|
||||
[{:keys [token-display-name amount account to-address route to-network image-url transaction-type
|
||||
collectible?]}]
|
||||
(let [to-network-name (:network-name to-network)
|
||||
to-network-color (if (= to-network-name :mainnet) :ethereum to-network-name)]
|
||||
|
@ -32,8 +30,8 @@
|
|||
(i18n/label :t/bridge)
|
||||
(i18n/label :t/send))]
|
||||
[quo/summary-tag
|
||||
{:token (if collectible? "" token-symbol)
|
||||
:label (str amount " " token-symbol)
|
||||
{:token (if collectible? "" token-display-name)
|
||||
:label (str amount " " token-display-name)
|
||||
:type (if collectible? :collectible :token)
|
||||
:image-source (if collectible? image-url :eth)}]]
|
||||
(if (= transaction-type :bridge)
|
||||
|
@ -125,84 +123,34 @@
|
|||
:emoji (:emoji account)
|
||||
:customization-color (:color account)}]])]))
|
||||
|
||||
(defn network-name-from-chain-id
|
||||
[chain-id]
|
||||
(let [network-name (-> (rf/sub [:wallet/network-details-by-chain-id chain-id])
|
||||
:network-name)]
|
||||
(if (= network-name :mainnet) :ethereum network-name)))
|
||||
|
||||
(defn- network-amounts-from-route
|
||||
[{:keys [route token-symbol token-decimals to?]}]
|
||||
(reduce (fn [acc path]
|
||||
(let [network (if to? (:to path) (:from path))
|
||||
chain-id (:chain-id network)
|
||||
amount-hex (if to? (:amount-in path) (:amount-out path))
|
||||
amount-units (native-module/hex-to-number
|
||||
(utils.hex/normalize-hex amount-hex))
|
||||
amount (money/with-precision
|
||||
(if (= token-symbol "ETH")
|
||||
(money/wei->ether amount-units)
|
||||
(money/token->unit amount-units
|
||||
token-decimals))
|
||||
6)
|
||||
network-name (network-name-from-chain-id chain-id)]
|
||||
(merge-with money/add acc {network-name amount})))
|
||||
{}
|
||||
route))
|
||||
|
||||
(defn- network-values-from-amounts
|
||||
[network-amounts token-symbol]
|
||||
(reduce-kv (fn [acc k v]
|
||||
(assoc acc
|
||||
k
|
||||
{:amount v
|
||||
:token-symbol token-symbol}))
|
||||
{}
|
||||
network-amounts))
|
||||
|
||||
(defn- sanitize-network-values
|
||||
[network-values]
|
||||
(into {}
|
||||
(map (fn [[k v]]
|
||||
[k
|
||||
(if (money/equal-to (v :amount) 0)
|
||||
(assoc v :amount "<0.01")
|
||||
v)])
|
||||
network-values)))
|
||||
|
||||
(defn- values-by-network
|
||||
[{:keys [collectible amount token-symbol route token-decimals to?]}]
|
||||
(if collectible
|
||||
(let [collectible-chain-id (get-in collectible [:id :contract-id :chain-id])
|
||||
network-name (network-name-from-chain-id collectible-chain-id)]
|
||||
{network-name {:amount amount :token-symbol token-symbol}})
|
||||
(let [network-amounts (network-amounts-from-route {:route route
|
||||
:token-symbol token-symbol
|
||||
:token-decimals token-decimals
|
||||
:to? to?})
|
||||
network-values (network-values-from-amounts network-amounts token-symbol)]
|
||||
(sanitize-network-values network-values))))
|
||||
|
||||
(defn- user-summary
|
||||
[{:keys [account-props theme label accessibility-label
|
||||
summary-type network-values]
|
||||
:as _props}]
|
||||
[rn/view
|
||||
{:style {:padding-horizontal 20
|
||||
:padding-bottom 16}}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/section-label theme)
|
||||
:accessibility-label accessibility-label}
|
||||
label]
|
||||
[quo/summary-info
|
||||
{:type summary-type
|
||||
:networks? true
|
||||
:values network-values
|
||||
:account-props account-props}]])
|
||||
[{:keys [network-values token-display-name account-props theme label accessibility-label
|
||||
summary-type]}]
|
||||
(let [network-values
|
||||
(reduce-kv
|
||||
(fn [acc chain-id amount]
|
||||
(let [network-name (wallet-utils/id->network chain-id)]
|
||||
(assoc acc
|
||||
(if (= network-name :mainnet) :ethereum network-name)
|
||||
{:amount amount :token-symbol token-display-name})))
|
||||
{}
|
||||
network-values)]
|
||||
[rn/view
|
||||
{:style {:padding-horizontal 20
|
||||
:padding-bottom 16}}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/section-label theme)
|
||||
:accessibility-label accessibility-label}
|
||||
label]
|
||||
[quo/summary-info
|
||||
{:type summary-type
|
||||
:networks? true
|
||||
:values network-values
|
||||
:account-props account-props}]]))
|
||||
|
||||
(defn data-item
|
||||
(defn- data-item
|
||||
[{:keys [title subtitle]}]
|
||||
[quo/data-item
|
||||
{:container-style style/detail-item
|
||||
|
@ -217,7 +165,8 @@
|
|||
:subtitle subtitle}])
|
||||
|
||||
(defn- transaction-details
|
||||
[{:keys [estimated-time-min max-fees token-symbol amount to-address to-network route transaction-type
|
||||
[{:keys [estimated-time-min max-fees token-display-name amount to-address to-network route
|
||||
transaction-type
|
||||
theme]}]
|
||||
(let [currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
route-loaded? (and route (seq route))
|
||||
|
@ -253,56 +202,42 @@
|
|||
(i18n/label :t/bridged-to
|
||||
{:network (:abbreviated-name to-network)})
|
||||
(i18n/label :t/user-gets {:name (utils/get-shortened-address to-address)}))
|
||||
:subtitle (str amount " " token-symbol)}]]
|
||||
:subtitle (str amount " " token-display-name)}]]
|
||||
:else
|
||||
[quo/text {:style {:align-self :center}}
|
||||
(i18n/label :t/no-routes-found-confirmation)])]]))
|
||||
|
||||
(defn collectible-token-symbol
|
||||
[collectible]
|
||||
(let [collection-data (:collection-data collectible)
|
||||
collectible-data (:collectible-data collectible)
|
||||
collectible-id (get-in collectible [:id :token-id])]
|
||||
(first (remove
|
||||
string/blank?
|
||||
[(:name collectible-data)
|
||||
(str (:name collection-data) " #" collectible-id)]))))
|
||||
|
||||
(defn- view-internal
|
||||
[_]
|
||||
(let [on-close (fn []
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])
|
||||
(rf/dispatch [:navigate-back]))]
|
||||
(fn [{:keys [theme]}]
|
||||
(let [send-transaction-data (rf/sub [:wallet/wallet-send])
|
||||
{:keys [token collectible amount route
|
||||
to-address bridge-to-chain-id]} send-transaction-data
|
||||
collectible? (some? collectible)
|
||||
token-symbol (if collectible
|
||||
(collectible-token-symbol collectible)
|
||||
(:symbol token))
|
||||
token-decimals (if collectible 0 (:decimals token))
|
||||
image-url (when collectible
|
||||
(get-in collectible [:preview-url :uri]))
|
||||
transaction-type (:tx-type send-transaction-data)
|
||||
estimated-time-min (reduce + (map :estimated-time route))
|
||||
max-fees "-"
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
account-color (:color account)
|
||||
bridge-to-network (when bridge-to-chain-id
|
||||
(rf/sub [:wallet/network-details-by-chain-id
|
||||
bridge-to-chain-id]))
|
||||
from-account-props {:customization-color account-color
|
||||
:size 32
|
||||
:emoji (:emoji account)
|
||||
:type :default
|
||||
:name (:name account)
|
||||
:address (utils/get-shortened-address
|
||||
(:address
|
||||
account))}
|
||||
user-props {:full-name to-address
|
||||
:address (utils/get-shortened-address
|
||||
to-address)}]
|
||||
(let [send-transaction-data (rf/sub [:wallet/wallet-send])
|
||||
{:keys [token-display-name collectible amount route
|
||||
to-address bridge-to-chain-id
|
||||
from-values-by-chain
|
||||
to-values-by-chain]} send-transaction-data
|
||||
collectible? (some? collectible)
|
||||
image-url (when collectible
|
||||
(get-in collectible [:preview-url :uri]))
|
||||
transaction-type (:tx-type send-transaction-data)
|
||||
estimated-time-min (reduce + (map :estimated-time route))
|
||||
max-fees "-"
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
account-color (:color account)
|
||||
bridge-to-network (when bridge-to-chain-id
|
||||
(rf/sub [:wallet/network-details-by-chain-id
|
||||
bridge-to-chain-id]))
|
||||
from-account-props {:customization-color account-color
|
||||
:size 32
|
||||
:emoji (:emoji account)
|
||||
:type :default
|
||||
:name (:name account)
|
||||
:address (utils/get-shortened-address (:address
|
||||
account))}
|
||||
user-props {:full-name to-address
|
||||
:address (utils/get-shortened-address to-address)}]
|
||||
[rn/view {:style {:flex 1}}
|
||||
[floating-button-page/view
|
||||
{:footer-container-padding 0
|
||||
|
@ -329,29 +264,26 @@
|
|||
:customization-color (:color account)}
|
||||
[rn/view
|
||||
[transaction-title
|
||||
{:token-symbol token-symbol
|
||||
:amount amount
|
||||
:account account
|
||||
:to-address to-address
|
||||
:route route
|
||||
:to-network bridge-to-network
|
||||
:image-url image-url
|
||||
:transaction-type transaction-type
|
||||
:collectible? collectible?}]
|
||||
{:token-display-name token-display-name
|
||||
:amount amount
|
||||
:account account
|
||||
:to-address to-address
|
||||
:route route
|
||||
:to-network bridge-to-network
|
||||
:image-url image-url
|
||||
:transaction-type transaction-type
|
||||
:collectible? collectible?}]
|
||||
[user-summary
|
||||
{:summary-type :status-account
|
||||
{:token-display-name token-display-name
|
||||
:summary-type :status-account
|
||||
:accessibility-label :summary-from-label
|
||||
:label (i18n/label :t/from-capitalized)
|
||||
:network-values from-values-by-chain
|
||||
:account-props from-account-props
|
||||
:theme theme
|
||||
:network-values (values-by-network {:collectible collectible
|
||||
:amount amount
|
||||
:token-symbol token-symbol
|
||||
:route route
|
||||
:token-decimals token-decimals
|
||||
:to? false})}]
|
||||
:theme theme}]
|
||||
[user-summary
|
||||
{:summary-type (if (= transaction-type :bridge)
|
||||
{:token-display-name token-display-name
|
||||
:summary-type (if (= transaction-type :bridge)
|
||||
:status-account
|
||||
:account)
|
||||
:accessibility-label :summary-to-label
|
||||
|
@ -359,17 +291,12 @@
|
|||
:account-props (if (= transaction-type :bridge)
|
||||
from-account-props
|
||||
user-props)
|
||||
:theme theme
|
||||
:network-values (values-by-network {:collectible collectible
|
||||
:amount amount
|
||||
:token-symbol token-symbol
|
||||
:route route
|
||||
:token-decimals token-decimals
|
||||
:to? true})}]
|
||||
:network-values to-values-by-chain
|
||||
:theme theme}]
|
||||
[transaction-details
|
||||
{:estimated-time-min estimated-time-min
|
||||
:max-fees max-fees
|
||||
:token-symbol token-symbol
|
||||
:token-display-name token-display-name
|
||||
:amount amount
|
||||
:to-address to-address
|
||||
:to-network bridge-to-network
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
(ns status-im.contexts.wallet.send.utils
|
||||
(:require [utils.money :as money]))
|
||||
(:require
|
||||
[legacy.status-im.utils.hex :as utils.hex]
|
||||
[native-module.core :as native-module]
|
||||
[utils.money :as money]))
|
||||
|
||||
(defn amount-in-hex
|
||||
[amount token-decimal]
|
||||
|
@ -20,3 +23,27 @@
|
|||
value1)))
|
||||
{}
|
||||
transaction-hashes))
|
||||
|
||||
(defn network-amounts-by-chain
|
||||
[{:keys [route token-decimals native-token? to?]}]
|
||||
(reduce (fn [acc path]
|
||||
(let [amount-hex (if to? (:amount-in path) (:amount-out path))
|
||||
amount-units (native-module/hex-to-number
|
||||
(utils.hex/normalize-hex amount-hex))
|
||||
amount (money/with-precision
|
||||
(if native-token?
|
||||
(money/wei->ether amount-units)
|
||||
(money/token->unit amount-units
|
||||
token-decimals))
|
||||
6)
|
||||
chain-id (if to? (get-in path [:to :chain-id]) (get-in path [:from :chain-id]))]
|
||||
(update acc chain-id money/add amount)))
|
||||
{}
|
||||
route))
|
||||
|
||||
(defn network-values-for-ui
|
||||
[amounts]
|
||||
(reduce-kv (fn [acc k v]
|
||||
(assoc acc k (if (money/equal-to v 0) "<0.01" v)))
|
||||
{}
|
||||
amounts))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.contexts.wallet.send.utils-test
|
||||
(:require [cljs.test :refer [deftest is testing]]
|
||||
[status-im.contexts.wallet.send.utils :as utils]))
|
||||
[status-im.contexts.wallet.send.utils :as utils]
|
||||
[utils.money :as money]))
|
||||
|
||||
(deftest test-amount-in-hex
|
||||
(testing "Test amount-in-hex function"
|
||||
|
@ -27,3 +28,68 @@
|
|||
"0x11" {:status :pending
|
||||
:id 61
|
||||
:chain-id :420}})))))
|
||||
|
||||
(deftest test-network-amounts-by-chain
|
||||
(testing "Correctly calculates network amounts for transaction with native token"
|
||||
(let [route [{:amount-in "0xde0b6b3a7640000"
|
||||
:to {:chain-id "1"}}
|
||||
{:amount-in "0xde0b6b3a7640000"
|
||||
:to {:chain-id "2"}}]
|
||||
token-decimals 18
|
||||
native-token? true
|
||||
to? true
|
||||
result (utils/network-amounts-by-chain {:route route
|
||||
:token-decimals token-decimals
|
||||
:native-token? native-token?
|
||||
:to? to?})
|
||||
expected {"1" (money/bignumber "1")
|
||||
"2" (money/bignumber "1")}]
|
||||
(doseq [[chain-id exp-value] expected]
|
||||
(is (money/equal-to (get result chain-id) exp-value)))))
|
||||
|
||||
(testing
|
||||
"Correctly calculates network amounts for transaction with native token and multiple routes to same chain-id"
|
||||
(let [route [{:amount-in "0xde0b6b3a7640000"
|
||||
:to {:chain-id "1"}}
|
||||
{:amount-in "0xde0b6b3a7640000"
|
||||
:to {:chain-id "1"}}]
|
||||
token-decimals 18
|
||||
native-token? true
|
||||
to? true
|
||||
result (utils/network-amounts-by-chain {:route route
|
||||
:token-decimals token-decimals
|
||||
:native-token? native-token?
|
||||
:to? to?})
|
||||
expected {"1" (money/bignumber "2")}]
|
||||
(doseq [[chain-id exp-value] expected]
|
||||
(is (money/equal-to (get result chain-id) exp-value)))))
|
||||
|
||||
(testing "Correctly calculates network amounts for transaction with non-native token"
|
||||
(let [route [{:amount-out "0x1e8480"
|
||||
:from {:chain-id "1"}}
|
||||
{:amount-out "0x1e8480"
|
||||
:from {:chain-id "2"}}]
|
||||
token-decimals 6
|
||||
native-token? false
|
||||
to? false
|
||||
result (utils/network-amounts-by-chain {:route route
|
||||
:token-decimals token-decimals
|
||||
:native-token? native-token?
|
||||
:to? to?})
|
||||
expected {"1" (money/bignumber "2")
|
||||
"2" (money/bignumber "2")}]
|
||||
(doseq [[chain-id exp-value] expected]
|
||||
(is (money/equal-to (get result chain-id) exp-value))))))
|
||||
|
||||
(deftest test-network-values-for-ui
|
||||
(testing "Sanitizes values correctly for display"
|
||||
(let [amounts {"1" (money/bignumber "0")
|
||||
"2" (money/bignumber "2.5")
|
||||
"3" (money/bignumber "0.005")}
|
||||
result (utils/network-values-for-ui amounts)
|
||||
expected {"1" "<0.01"
|
||||
"2" (money/bignumber "2.5")
|
||||
"3" (money/bignumber "0.005")}]
|
||||
(doseq [[chain-id exp-value] expected]
|
||||
(is #(or (= (get result chain-id) exp-value)
|
||||
(money/equal-to (get result chain-id) exp-value)))))))
|
||||
|
|
|
@ -95,6 +95,21 @@
|
|||
:<- [:wallet/wallet-send]
|
||||
:-> :token)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-disabled-from-chain-ids
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :disabled-from-chain-ids)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-from-values-by-chain
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :from-values-by-chain)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-to-values-by-chain
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :to-values-by-chain)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-loading-suggested-routes?
|
||||
:<- [:wallet/wallet-send]
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
(ns utils.vector)
|
||||
|
||||
(defn insert-element-at
|
||||
[data element index]
|
||||
(let [before (take index data)
|
||||
after (drop index data)]
|
||||
(vec (concat before [element] after))))
|
|
@ -0,0 +1,17 @@
|
|||
(ns utils.vector-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest is testing]]
|
||||
[utils.vector :as vector]))
|
||||
|
||||
(deftest test-insert-element-at
|
||||
(testing "Inserting into an empty vector"
|
||||
(is (= [42] (vector/insert-element-at [] 42 0))))
|
||||
|
||||
(testing "Inserting at the beginning of a vector"
|
||||
(is (= [42 1 2 3] (vector/insert-element-at [1 2 3] 42 0))))
|
||||
|
||||
(testing "Inserting in the middle of a vector"
|
||||
(is (= [1 42 2 3] (vector/insert-element-at [1 2 3] 42 1))))
|
||||
|
||||
(testing "Inserting at the end of a vector"
|
||||
(is (= [1 2 3 42] (vector/insert-element-at [1 2 3] 42 3)))))
|
Loading…
Reference in New Issue