mirror of
https://github.com/status-im/status-react.git
synced 2025-02-23 08:08:33 +00:00
refactor: suggested routes rendering (#19768)
Signed-off-by: Brian Sztamfater <brian@status.im>
This commit is contained in:
parent
d8d1e030e4
commit
355e144ef7
@ -30,7 +30,7 @@
|
||||
[{:keys [network status amount container-style on-press] :as args}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
(if (= status :add)
|
||||
[network-bridge-add args]
|
||||
[network-bridge-add (assoc args :theme theme)]
|
||||
[rn/pressable
|
||||
{:style (merge (style/container network status theme) container-style)
|
||||
:accessible true
|
||||
|
@ -25,10 +25,10 @@
|
||||
|
||||
(def link-1x-container
|
||||
{:flex 1
|
||||
:height 58
|
||||
:height 57
|
||||
:justify-content :center})
|
||||
|
||||
(def link-2x-container
|
||||
{:flex 1
|
||||
:height 114
|
||||
:height 112
|
||||
:justify-content :center})
|
||||
|
@ -24,33 +24,50 @@
|
||||
:strokeWidth "1"}]])
|
||||
|
||||
(defn- line
|
||||
[stroke width]
|
||||
[{:keys [stroke-color source-color destination-color width theme]}]
|
||||
[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"}]])
|
||||
:stroke stroke-color
|
||||
:stroke-width "1"}]
|
||||
[svg/defs
|
||||
[svg/linear-gradient
|
||||
{:id "gradient"
|
||||
:x1 "0%"
|
||||
:x2 "100%"
|
||||
:y1 "0%"
|
||||
:y2 "0%"
|
||||
:gradient-units "objectBoundingBox"}
|
||||
[svg/stop {:offset "0%" :stop-color (colors/resolve-color source-color theme)}]
|
||||
[svg/stop {:offset "100%" :stop-color (colors/resolve-color destination-color theme)}]]]])
|
||||
|
||||
(defn link-linear
|
||||
[{:keys [source]}]
|
||||
[{:keys [source destination]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
[container-width
|
||||
set-container-width] (rn/use-state 100)
|
||||
stroke-color (colors/resolve-color source theme)
|
||||
stroke-color "url(#gradient)"
|
||||
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)
|
||||
on-layout (rn/use-callback #(set-container-width
|
||||
(oget % :nativeEvent :layout :width)))]
|
||||
[rn/view
|
||||
{:style style/link-linear-container
|
||||
:on-layout on-layout}
|
||||
[line stroke-color container-width]
|
||||
[line
|
||||
{:stroke-color stroke-color
|
||||
:source-color source-color
|
||||
:destination-color destination-color
|
||||
:width container-width
|
||||
:theme theme}]
|
||||
[rn/view {:style style/left-circle-container}
|
||||
[circle fill-color stroke-color]]
|
||||
[circle fill-color source-color]]
|
||||
[rn/view {:style style/right-circle-container}
|
||||
[circle fill-color stroke-color]]]))
|
||||
[circle fill-color destination-color]]]))
|
||||
|
||||
(defn link-1x
|
||||
[{:keys [source destination]}]
|
||||
|
@ -263,3 +263,11 @@
|
||||
{}
|
||||
tokens)
|
||||
(update-vals #(prettify-balance currency-symbol %))))
|
||||
|
||||
(defn format-token-id
|
||||
[token collectible]
|
||||
(if token
|
||||
(:symbol token)
|
||||
(str (get-in collectible [:id :contract-id :address])
|
||||
":"
|
||||
(get-in collectible [:id :token-id]))))
|
||||
|
@ -1,34 +0,0 @@
|
||||
(ns status-im.contexts.wallet.common.utils.send
|
||||
(:require [clojure.string :as string]
|
||||
[utils.money :as money]))
|
||||
|
||||
(defn calculate-gas-fee
|
||||
[data]
|
||||
(let [gas-amount (money/bignumber (get data :gas-amount))
|
||||
gas-fees (get data :gas-fees)
|
||||
eip1559-enabled? (get gas-fees :eip-1559-enabled)
|
||||
optimal-price-gwei (money/bignumber (if eip1559-enabled?
|
||||
(get gas-fees :max-fee-per-gas-medium)
|
||||
(get gas-fees :gas-price)))
|
||||
total-gas-fee-wei (money/mul (money/->wei :gwei optimal-price-gwei) gas-amount)
|
||||
l1-fee-wei (money/->wei :gwei (get gas-fees :l-1-gas-fee))]
|
||||
(money/add total-gas-fee-wei l1-fee-wei)))
|
||||
|
||||
(defn calculate-full-route-gas-fee
|
||||
"Sums all the routes fees in wei and then convert the total value to ether"
|
||||
[route]
|
||||
(money/wei->ether (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))))
|
@ -1,116 +0,0 @@
|
||||
(ns status-im.contexts.wallet.common.utils.send-test
|
||||
(:require [cljs.test :refer [deftest is testing]]
|
||||
[status-im.contexts.wallet.common.utils.send :as utils]
|
||||
[utils.money :as money]))
|
||||
|
||||
(deftest test-calculate-gas-fee
|
||||
(testing "EIP-1559 transaction without L1 fee"
|
||||
(let [data {:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "0"}}
|
||||
expected-result (money/bignumber "53063589834657")] ; This is in Wei
|
||||
(is (money/equal-to (utils/calculate-gas-fee data)
|
||||
expected-result))))
|
||||
|
||||
(testing "EIP-1559 transaction with L1 fee of 60,000 Gwei"
|
||||
(let [data {:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "60000"}}
|
||||
expected-result (money/bignumber "113063589834657")] ; Added 60,000 Gwei in Wei to the
|
||||
; previous result
|
||||
(is (money/equal-to (utils/calculate-gas-fee data)
|
||||
expected-result))))
|
||||
|
||||
(testing "Non-EIP-1559 transaction with specified gas price"
|
||||
(let [data {:gas-amount "23487"
|
||||
:gas-fees {:gas-price "2.872721089"
|
||||
:eip-1559-enabled false
|
||||
:l-1-gas-fee "0"}}
|
||||
expected-result (money/bignumber "67471600217343")] ; This is in Wei, for the specified
|
||||
; gas amount and price
|
||||
(is (money/equal-to (utils/calculate-gas-fee data)
|
||||
expected-result)))))
|
||||
|
||||
(deftest test-calculate-full-route-gas-fee
|
||||
(testing "Route with a single EIP-1559 transaction, no L1 fees"
|
||||
(let [route [{:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "0"}}]
|
||||
expected-result (money/bignumber "0.000053063589834657")] ; The Wei amount for the
|
||||
; transaction, converted to
|
||||
; Ether
|
||||
(is (money/equal-to (utils/calculate-full-route-gas-fee route)
|
||||
expected-result))))
|
||||
|
||||
(testing "Route with two EIP-1559 transactions, no L1 fees"
|
||||
(let [route [{:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "0"}}
|
||||
{:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "0"}}]
|
||||
expected-result (money/bignumber "0.000106127179669314")] ; Sum of both transactions' Wei
|
||||
; amounts, converted to Ether
|
||||
(is (money/equal-to (utils/calculate-full-route-gas-fee route)
|
||||
expected-result))))
|
||||
|
||||
(testing "Route with two EIP-1559 transactions, one with L1 fee of 60,000 Gwei"
|
||||
(let [route [{:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "0"}}
|
||||
{:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "60000"}}]
|
||||
expected-result (money/bignumber "0.000166127179669314")] ; Added 60,000 Gwei in Wei to
|
||||
; the previous total and
|
||||
; converted to Ether
|
||||
(is (money/equal-to (utils/calculate-full-route-gas-fee route)
|
||||
expected-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))))))
|
@ -31,8 +31,13 @@
|
||||
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])
|
||||
receiver-networks (get-in db [:wallet :ui :send :receiver-networks])
|
||||
receiver-network-values (get-in db [:wallet :ui :send :receiver-network-values])
|
||||
sender-network-values (get-in db [:wallet :ui :send :sender-network-values])
|
||||
disabled-from-chain-ids (or (get-in db [:wallet :ui :send :disabled-from-chain-ids]) [])
|
||||
token-decimals (if collectible 0 (:decimals token))
|
||||
native-token? (and token (= token-display-name "ETH"))
|
||||
routes-available? (pos? (count chosen-route))
|
||||
from-network-amounts-by-chain (send-utils/network-amounts-by-chain {:route chosen-route
|
||||
:token-decimals
|
||||
token-decimals
|
||||
@ -46,19 +51,54 @@
|
||||
:native-token?
|
||||
native-token?
|
||||
:to? true})
|
||||
to-network-values-for-ui (send-utils/network-values-for-ui to-network-amounts-by-chain)]
|
||||
to-network-values-for-ui (send-utils/network-values-for-ui to-network-amounts-by-chain)
|
||||
sender-network-values (if routes-available?
|
||||
(send-utils/network-amounts from-network-values-for-ui
|
||||
disabled-from-chain-ids
|
||||
receiver-networks
|
||||
false)
|
||||
(send-utils/reset-network-amounts-to-zero
|
||||
sender-network-values))
|
||||
receiver-network-values (if routes-available?
|
||||
(send-utils/network-amounts to-network-values-for-ui
|
||||
disabled-from-chain-ids
|
||||
receiver-networks
|
||||
true)
|
||||
(send-utils/reset-network-amounts-to-zero
|
||||
receiver-network-values))
|
||||
network-links (when routes-available?
|
||||
(send-utils/network-links chosen-route
|
||||
sender-network-values
|
||||
receiver-network-values))]
|
||||
{: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 :sender-network-values] sender-network-values)
|
||||
(assoc-in [:wallet :ui :send :receiver-network-values] receiver-network-values)
|
||||
(assoc-in [:wallet :ui :send :network-links] network-links)
|
||||
(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 :route)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false))}))
|
||||
(fn [{:keys [db]} [error]]
|
||||
(let [cleaned-sender-network-values (-> (get-in db [:wallet :ui :send :sender-network-values])
|
||||
(send-utils/reset-network-amounts-to-zero))
|
||||
cleaned-receiver-network-values (-> (get-in db [:wallet :ui :send :receiver-network-values])
|
||||
(send-utils/reset-network-amounts-to-zero))]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send]
|
||||
dissoc
|
||||
:route)
|
||||
(assoc-in [:wallet :ui :send :sender-network-values] cleaned-sender-network-values)
|
||||
(assoc-in [:wallet :ui :send :receiver-network-values] cleaned-receiver-network-values)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false)
|
||||
(assoc-in [:wallet :ui :send :suggested-routes] {:best []}))
|
||||
:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :send-transaction-error
|
||||
:type :negative
|
||||
:text (:message error)}]]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-suggested-routes
|
||||
(fn [{:keys [db]}]
|
||||
@ -69,6 +109,9 @@
|
||||
:route
|
||||
:from-values-by-chain
|
||||
:to-values-by-chain
|
||||
:sender-network-values
|
||||
:receiver-network-values
|
||||
:network-links
|
||||
:loading-suggested-routes?
|
||||
:suggested-routes-call-timestamp)}))
|
||||
|
||||
@ -203,56 +246,74 @@
|
||||
|
||||
(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])
|
||||
token (get-in db [:wallet :ui :send :token])
|
||||
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])
|
||||
receiver-networks (get-in db [:wallet :ui :send :receiver-networks])
|
||||
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
|
||||
token (get-in db [:wallet :ui :send :token])
|
||||
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])
|
||||
receiver-networks (get-in db [:wallet :ui :send :receiver-networks])
|
||||
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]))
|
||||
network-chain-ids (map :chain-id networks)
|
||||
bridge-to-chain-id (get-in db [:wallet :ui :send :bridge-to-chain-id])
|
||||
token-decimal (when token (:decimals token))
|
||||
token-id (if token
|
||||
(:symbol token)
|
||||
(str (get-in collectible [:id :contract-id :address])
|
||||
":"
|
||||
(get-in collectible [:id :token-id])))
|
||||
to-token-id ""
|
||||
network-preferences (if token [] [(get-in collectible [:id :contract-id :chain-id])])
|
||||
gas-rates constants/gas-rate-medium
|
||||
amount-in (send-utils/amount-in-hex amount (if token token-decimal 0))
|
||||
from-address wallet-address
|
||||
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)
|
||||
bridge-to-chain-id (get-in db [:wallet :ui :send :bridge-to-chain-id])
|
||||
token-decimal (when token (:decimals token))
|
||||
token-id (utils/format-token-id token collectible)
|
||||
to-token-id ""
|
||||
network-preferences (if token [] [(get-in collectible [:id :contract-id :chain-id])])
|
||||
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-to-chain-ids (if (= transaction-type :bridge)
|
||||
(filter #(not= % bridge-to-chain-id) network-chain-ids)
|
||||
(filter (fn [chain-id]
|
||||
(not (some #(= chain-id %)
|
||||
receiver-networks)))
|
||||
network-chain-ids))
|
||||
from-locked-amount {}
|
||||
transaction-type-param (case transaction-type
|
||||
:collectible constants/send-type-erc-721-transfer
|
||||
:bridge constants/send-type-bridge
|
||||
constants/send-type-transfer)
|
||||
request-params [transaction-type-param
|
||||
from-address
|
||||
to-address
|
||||
amount-in
|
||||
token-id
|
||||
to-token-id
|
||||
disabled-to-chain-ids (if (= transaction-type :bridge)
|
||||
(filter #(not= % bridge-to-chain-id) network-chain-ids)
|
||||
(filter (fn [chain-id]
|
||||
(not (some #(= chain-id %)
|
||||
receiver-networks)))
|
||||
network-chain-ids))
|
||||
from-locked-amount {}
|
||||
transaction-type-param (case transaction-type
|
||||
:collectible constants/send-type-erc-721-transfer
|
||||
:bridge constants/send-type-bridge
|
||||
constants/send-type-transfer)
|
||||
balances-per-chain (when token (:balances-per-chain token))
|
||||
token-available-networks-for-suggested-routes
|
||||
(when token
|
||||
(send-utils/token-available-networks-for-suggested-routes {:balances-per-chain
|
||||
balances-per-chain
|
||||
:disabled-chain-ids
|
||||
disabled-from-chain-ids}))
|
||||
sender-network-values (when token-available-networks-for-suggested-routes
|
||||
(send-utils/loading-network-amounts
|
||||
token-available-networks-for-suggested-routes
|
||||
disabled-from-chain-ids
|
||||
disabled-to-chain-ids
|
||||
network-preferences
|
||||
gas-rates
|
||||
from-locked-amount]]
|
||||
receiver-networks
|
||||
false))
|
||||
receiver-network-values (when token-available-networks-for-suggested-routes
|
||||
(send-utils/loading-network-amounts
|
||||
token-available-networks-for-suggested-routes
|
||||
disabled-from-chain-ids
|
||||
receiver-networks
|
||||
true))
|
||||
request-params [transaction-type-param
|
||||
from-address
|
||||
to-address
|
||||
amount-in
|
||||
token-id
|
||||
to-token-id
|
||||
disabled-from-chain-ids
|
||||
disabled-to-chain-ids
|
||||
network-preferences
|
||||
gas-rates
|
||||
from-locked-amount]]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :amount] amount)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] true)
|
||||
(assoc-in [:wallet :ui :send :suggested-routes-call-timestamp] now))
|
||||
(assoc-in [:wallet :ui :send :sender-network-values] sender-network-values)
|
||||
(assoc-in [:wallet :ui :send :receiver-network-values] receiver-network-values)
|
||||
(assoc-in [:wallet :ui :send :suggested-routes-call-timestamp] now)
|
||||
(update-in [:wallet :ui :send] dissoc :network-links))
|
||||
:json-rpc/call [{:method "wallet_getSuggestedRoutes"
|
||||
:params request-params
|
||||
:on-success (fn [suggested-routes]
|
||||
|
@ -63,7 +63,7 @@
|
||||
: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-suggested-routes nil
|
||||
:wallet/wallet-send-receiver-networks [1]
|
||||
:view-id :screen/wallet.send-input-amount
|
||||
:wallet/wallet-send-to-address "0x04371e2d9d66b82f056bc128064"
|
||||
@ -73,7 +73,10 @@
|
||||
: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")}})
|
||||
:wallet/wallet-send-to-values-by-chain {1 (money/bignumber "250")}
|
||||
:wallet/wallet-send-sender-network-values nil
|
||||
:wallet/wallet-send-receiver-network-values nil
|
||||
:wallet/wallet-send-network-links nil})
|
||||
|
||||
(h/describe "Send > input amount screen"
|
||||
(h/setup-restorable-re-frame)
|
||||
|
@ -33,3 +33,8 @@
|
||||
{:flex 1
|
||||
:height 40
|
||||
:background-color :transparent})
|
||||
|
||||
(def no-routes-found-container
|
||||
{:height 40
|
||||
:width "100%"
|
||||
:align-items :center})
|
||||
|
@ -9,11 +9,12 @@
|
||||
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
|
||||
[status-im.contexts.wallet.common.asset-list.view :as asset-list]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.common.utils.send :as send-utils]
|
||||
[status-im.contexts.wallet.send.input-amount.style :as style]
|
||||
[status-im.contexts.wallet.send.routes.view :as routes]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[utils.address :as address]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- make-limit-label
|
||||
@ -52,6 +53,15 @@
|
||||
:title (i18n/label :t/user-gets {:name receiver})
|
||||
:subtitle amount}]])
|
||||
|
||||
(defn- every-network-value-is-zero?
|
||||
[sender-network-values]
|
||||
(every? (fn [{:keys [total-amount]}]
|
||||
(and
|
||||
total-amount
|
||||
(money/equal-to total-amount
|
||||
(money/bignumber "0"))))
|
||||
sender-network-values))
|
||||
|
||||
(defn select-asset-bottom-sheet
|
||||
[clear-input!]
|
||||
(let [{preselected-token-symbol :symbol} (rf/sub [:wallet/wallet-send-token])]
|
||||
@ -157,7 +167,18 @@
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[select-asset-bottom-sheet
|
||||
clear-input!])}])]
|
||||
clear-input!])}])
|
||||
loading-suggested-routes? (rf/sub
|
||||
[:wallet/wallet-send-loading-suggested-routes?])
|
||||
sender-network-values (rf/sub
|
||||
[:wallet/wallet-send-sender-network-values])
|
||||
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
|
||||
routes (when suggested-routes
|
||||
(or (:best suggested-routes) []))
|
||||
no-routes-found? (and
|
||||
(every-network-value-is-zero? sender-network-values)
|
||||
(not (nil? routes))
|
||||
(not loading-suggested-routes?))]
|
||||
(rn/use-mount
|
||||
(fn []
|
||||
(let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!))
|
||||
@ -200,12 +221,28 @@
|
||||
:fees fee-formatted
|
||||
:amount amount-text
|
||||
:receiver (address/get-shortened-key to-address)}])
|
||||
(when no-routes-found?
|
||||
[rn/view {:style style/no-routes-found-container}
|
||||
[quo/info-message
|
||||
{:type :error
|
||||
:icon :i/alert
|
||||
:size :default
|
||||
:style {:margin-top 15}}
|
||||
(i18n/label :t/no-routes-found)]])
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label button-one-label
|
||||
:button-one-label (if no-routes-found?
|
||||
(i18n/label :t/try-again)
|
||||
button-one-label)
|
||||
:button-one-props (merge button-one-props
|
||||
{:disabled? confirm-disabled?
|
||||
:on-press on-confirm})}]
|
||||
{:disabled? (and (not no-routes-found?) confirm-disabled?)
|
||||
:on-press (if no-routes-found?
|
||||
#(rf/dispatch [:wallet/get-suggested-routes
|
||||
{:amount (controlled-input/input-value
|
||||
input-state)}])
|
||||
on-confirm)}
|
||||
(when no-routes-found?
|
||||
{:type :grey}))}]
|
||||
[quo/numbered-keyboard
|
||||
{:container-style (style/keyboard-container bottom)
|
||||
:left-action :dot
|
||||
|
@ -3,20 +3,16 @@
|
||||
|
||||
(def routes-container
|
||||
{:padding-horizontal 20
|
||||
:flex 1
|
||||
:flex-grow 1
|
||||
:padding-vertical 16
|
||||
:width "100%"
|
||||
:height "100%"})
|
||||
:width "100%"})
|
||||
|
||||
(def routes-header-container
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between})
|
||||
|
||||
(defn routes-inner-container
|
||||
[first-item?]
|
||||
{:margin-top (if first-item? 7.5 11)
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
(def routes-inner-container
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between})
|
||||
|
||||
(def section-label-right
|
||||
@ -25,20 +21,26 @@
|
||||
(def section-label-left
|
||||
{:width 136})
|
||||
|
||||
(def network-link
|
||||
(def network-links-container
|
||||
{:margin-horizontal -1.5
|
||||
:z-index 1
|
||||
:margin-top 7.5
|
||||
:z-index 3
|
||||
:flex 1})
|
||||
|
||||
(defn network-link-container
|
||||
[margin-top inverted?]
|
||||
(cond-> {:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:top margin-top}
|
||||
inverted?
|
||||
(assoc :transform [{:scaleY -1}])))
|
||||
|
||||
(def empty-container
|
||||
{:flex-grow 1
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def add-network
|
||||
{:margin-top 11
|
||||
:align-self :flex-end})
|
||||
|
||||
(defn warning-container
|
||||
[color theme]
|
||||
{:flex-direction :row
|
||||
|
@ -6,19 +6,18 @@
|
||||
[quo.foundations.resources :as resources]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils.networks :as networks-utils]
|
||||
[status-im.contexts.wallet.common.utils.send :as send-utils]
|
||||
[status-im.contexts.wallet.common.utils.networks :as network-utils]
|
||||
[status-im.contexts.wallet.send.routes.style :as style]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.vector :as vector-utils]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def ^:private network-priority-score
|
||||
{:ethereum 1
|
||||
:optimism 2
|
||||
:arbitrum 3})
|
||||
(def row-height 44)
|
||||
(def space-between-rows 11)
|
||||
(def network-link-linear-height 10)
|
||||
(def network-link-1x-height 56)
|
||||
(def network-link-2x-height 111)
|
||||
|
||||
(defn- make-network-item
|
||||
[{:keys [network-name chain-id] :as _network}
|
||||
@ -33,40 +32,16 @@
|
||||
: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 (networks-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 (networks-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 networks-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 (networks-utils/id->network chain-id)}]
|
||||
(vector-utils/insert-element-at acc-network-links disabled-network-link index)))
|
||||
network-links
|
||||
sorted-networks)))
|
||||
(defn fetch-routes
|
||||
[amount valid-input? bounce-duration-ms]
|
||||
(if valid-input?
|
||||
(debounce/debounce-and-dispatch
|
||||
[:wallet/get-suggested-routes {:amount amount}]
|
||||
bounce-duration-ms)
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])))
|
||||
|
||||
(defn networks-drawer
|
||||
[{:keys [fetch-routes theme]}]
|
||||
[{:keys [on-save theme]}]
|
||||
(let [network-details (rf/sub [:wallet/network-details])
|
||||
{:keys [color]} (rf/sub [:wallet/current-viewing-account])
|
||||
selected-networks (rf/sub [:wallet/wallet-send-receiver-networks])
|
||||
@ -119,188 +94,149 @@
|
||||
(rf/dispatch [:wallet/update-receiver-networks
|
||||
@network-preferences])
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(fetch-routes))
|
||||
(on-save))
|
||||
:customization-color color}}]])))
|
||||
|
||||
(defn route-item
|
||||
[{: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
|
||||
:container-style style/add-network
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [networks-drawer
|
||||
{:theme theme
|
||||
:fetch-routes fetch-routes}])}])}]
|
||||
[rn/view {:style (style/routes-inner-container first-item?)}
|
||||
[quo/network-bridge
|
||||
{: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 {:flex 1}}])
|
||||
[quo/network-bridge
|
||||
{: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-values
|
||||
[{:keys [network-values token-symbol on-press theme on-save to? loading-suggested-routes?]}]
|
||||
[rn/view
|
||||
(map-indexed (fn [index {:keys [chain-id total-amount type]}]
|
||||
[rn/view
|
||||
{:key (str (if to? "to" "from") "-" chain-id)
|
||||
:style {:margin-top (if (pos? index) 11 7.5)}}
|
||||
[quo/network-bridge
|
||||
{:amount (str total-amount " " token-symbol)
|
||||
:network (network-utils/id->network chain-id)
|
||||
:status type
|
||||
:on-press #(when (not loading-suggested-routes?)
|
||||
(cond
|
||||
(= type :add)
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[networks-drawer
|
||||
{:theme theme
|
||||
:on-save on-save}])}])
|
||||
on-press (on-press chain-id total-amount)))}]])
|
||||
network-values)])
|
||||
|
||||
(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?))
|
||||
(networks-utils/id->network item)
|
||||
disabled-network?
|
||||
(networks-utils/id->network (:chain-id
|
||||
item))
|
||||
:else
|
||||
(networks-utils/id->network from-chain-id))
|
||||
:to-network (cond (and loading-suggested-routes?
|
||||
(not disabled-network?))
|
||||
(networks-utils/id->network item)
|
||||
disabled-network?
|
||||
(networks-utils/id->network (:chain-id
|
||||
item))
|
||||
:else
|
||||
(networks-utils/id->network to-chain-id))
|
||||
:on-press-from-network on-press-from-network
|
||||
:on-press-to-network on-press-to-network}]))
|
||||
(defn render-network-links
|
||||
[{:keys [network-links sender-network-values]}]
|
||||
[rn/view {:style style/network-links-container}
|
||||
(map
|
||||
(fn [{:keys [from-chain-id to-chain-id position-diff]}]
|
||||
(let [position-diff-absolute (js/Math.abs position-diff)
|
||||
shape (case position-diff-absolute
|
||||
0 :linear
|
||||
1 :1x
|
||||
2 :2x)
|
||||
height (case position-diff-absolute
|
||||
0 network-link-linear-height
|
||||
1 network-link-1x-height
|
||||
2 network-link-2x-height)
|
||||
inverted? (neg? position-diff)
|
||||
source (network-utils/id->network from-chain-id)
|
||||
destination (network-utils/id->network to-chain-id)
|
||||
from-chain-id-index (first (keep-indexed #(when (= from-chain-id (:chain-id %2)) %1)
|
||||
sender-network-values))
|
||||
base-margin-top (* (+ row-height space-between-rows)
|
||||
from-chain-id-index)
|
||||
margin-top (if (zero? position-diff)
|
||||
(+ base-margin-top
|
||||
(- (/ row-height 2) (/ height 2)))
|
||||
(+ base-margin-top
|
||||
(- (/ row-height 2) height)
|
||||
(if inverted? height 0)))]
|
||||
[rn/view
|
||||
{:key (str "from-" from-chain-id "-to-" to-chain-id)
|
||||
:style (style/network-link-container margin-top inverted?)}
|
||||
[rn/view {:style {:flex 1}}
|
||||
[quo/network-link
|
||||
{:shape shape
|
||||
:source source
|
||||
:destination destination}]]]))
|
||||
network-links)])
|
||||
|
||||
(defn fetch-routes
|
||||
[amount valid-input? bounce-duration-ms]
|
||||
(if valid-input?
|
||||
(debounce/debounce-and-dispatch
|
||||
[:wallet/get-suggested-routes {:amount amount}]
|
||||
bounce-duration-ms)
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])))
|
||||
(defn disable-chain
|
||||
[chain-id disabled-from-chain-ids token-available-networks-for-suggested-routes]
|
||||
(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))]
|
||||
(if (or re-enabling-chain?
|
||||
(> (count token-available-networks-for-suggested-routes) 1))
|
||||
(rf/dispatch [:wallet/disable-from-networks
|
||||
disabled-chain-ids])
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:id :disable-chain-error
|
||||
:type :negative
|
||||
:text (i18n/label :t/at-least-one-network-must-be-activated)}]))))
|
||||
|
||||
(defn view
|
||||
[{:keys [token theme input-value valid-input?
|
||||
on-press-to-network current-screen-id]}]
|
||||
|
||||
(let [token-symbol (:symbol token)
|
||||
nav-current-screen-id (rf/sub [:view-id])
|
||||
active-screen? (= nav-current-screen-id current-screen-id)
|
||||
loading-suggested-routes? (rf/sub
|
||||
[:wallet/wallet-send-loading-suggested-routes?])
|
||||
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])
|
||||
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
|
||||
selected-networks (rf/sub [:wallet/wallet-send-receiver-networks])
|
||||
disabled-from-chain-ids (rf/sub
|
||||
[:wallet/wallet-send-disabled-from-chain-ids])
|
||||
routes (when suggested-routes
|
||||
(or (:best suggested-routes) []))
|
||||
(let [token-symbol (:symbol token)
|
||||
nav-current-screen-id (rf/sub [:view-id])
|
||||
active-screen? (= nav-current-screen-id current-screen-id)
|
||||
loading-suggested-routes? (rf/sub
|
||||
[:wallet/wallet-send-loading-suggested-routes?])
|
||||
sender-network-values (rf/sub
|
||||
[:wallet/wallet-send-sender-network-values])
|
||||
receiver-network-values (rf/sub
|
||||
[:wallet/wallet-send-receiver-network-values])
|
||||
network-links (rf/sub [:wallet/wallet-send-network-links])
|
||||
disabled-from-chain-ids (rf/sub
|
||||
[:wallet/wallet-send-disabled-from-chain-ids])
|
||||
{token-balances-per-chain :balances-per-chain} (rf/sub
|
||||
[:wallet/current-viewing-account-tokens-filtered
|
||||
(str token-symbol)])
|
||||
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})
|
||||
network-links (if loading-suggested-routes?
|
||||
affordable-networks
|
||||
routes)
|
||||
show-routes? (or (and (not-empty affordable-networks)
|
||||
loading-suggested-routes?)
|
||||
(not-empty routes))]
|
||||
|
||||
token-available-networks-for-suggested-routes
|
||||
(send-utils/token-available-networks-for-suggested-routes
|
||||
{:balances-per-chain token-balances-per-chain
|
||||
:disabled-chain-ids disabled-from-chain-ids})
|
||||
show-routes? (not-empty sender-network-values)]
|
||||
(rn/use-effect
|
||||
#(when (and active-screen? (> (count affordable-networks) 0))
|
||||
#(when (and active-screen? (> (count token-available-networks-for-suggested-routes) 0))
|
||||
(fetch-routes input-value valid-input? 2000))
|
||||
[input-value valid-input?])
|
||||
(rn/use-effect
|
||||
#(when (and active-screen? (> (count affordable-networks) 0))
|
||||
#(when (and active-screen? (> (count token-available-networks-for-suggested-routes) 0))
|
||||
(fetch-routes input-value valid-input? 0))
|
||||
[disabled-from-chain-ids])
|
||||
(if show-routes?
|
||||
(let [initial-network-links-count (count network-links)
|
||||
disabled-count (count disabled-from-chain-ids)
|
||||
network-links (if (not-empty disabled-from-chain-ids)
|
||||
(add-disabled-networks network-links
|
||||
disabled-from-chain-ids
|
||||
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 % valid-input? 2000)
|
||||
: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]))))
|
||||
: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)])])))
|
||||
[rn/scroll-view {:content-container-style style/routes-container}
|
||||
(when show-routes?
|
||||
[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}]])
|
||||
[rn/view {:style style/routes-inner-container}
|
||||
[render-network-values
|
||||
{:token-symbol token-symbol
|
||||
:network-values sender-network-values
|
||||
:on-press #(disable-chain %1
|
||||
disabled-from-chain-ids
|
||||
token-available-networks-for-suggested-routes)
|
||||
:to? false
|
||||
:theme theme
|
||||
:loading-suggested-routes? loading-suggested-routes?}]
|
||||
[render-network-links
|
||||
{:network-links network-links
|
||||
:sender-network-values sender-network-values}]
|
||||
[render-network-values
|
||||
{:token-symbol token-symbol
|
||||
:network-values receiver-network-values
|
||||
:on-press on-press-to-network
|
||||
:to? true
|
||||
:loading-suggested-routes? loading-suggested-routes?
|
||||
:theme theme
|
||||
:on-save #(fetch-routes input-value valid-input? 0)}]]]))
|
||||
|
||||
|
@ -209,9 +209,7 @@
|
||||
|
||||
(defn view
|
||||
[_]
|
||||
(let [on-close (fn []
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])
|
||||
(rf/dispatch [:navigate-back]))]
|
||||
(let [on-close #(rf/dispatch [:navigate-back])]
|
||||
(fn []
|
||||
(let [theme (quo.theme/use-theme)
|
||||
send-transaction-data (rf/sub [:wallet/wallet-send])
|
||||
|
@ -2,6 +2,7 @@
|
||||
(:require
|
||||
[legacy.status-im.utils.hex :as utils.hex]
|
||||
[native-module.core :as native-module]
|
||||
[status-im.contexts.wallet.common.utils.networks :as network-utils]
|
||||
[utils.money :as money]))
|
||||
|
||||
(defn amount-in-hex
|
||||
@ -24,6 +25,23 @@
|
||||
{}
|
||||
transaction-hashes))
|
||||
|
||||
(defn calculate-gas-fee
|
||||
[data]
|
||||
(let [gas-amount (money/bignumber (get data :gas-amount))
|
||||
gas-fees (get data :gas-fees)
|
||||
eip1559-enabled? (get gas-fees :eip-1559-enabled)
|
||||
optimal-price-gwei (money/bignumber (if eip1559-enabled?
|
||||
(get gas-fees :max-fee-per-gas-medium)
|
||||
(get gas-fees :gas-price)))
|
||||
total-gas-fee-wei (money/mul (money/->wei :gwei optimal-price-gwei) gas-amount)
|
||||
l1-fee-wei (money/->wei :gwei (get gas-fees :l-1-gas-fee))]
|
||||
(money/add total-gas-fee-wei l1-fee-wei)))
|
||||
|
||||
(defn calculate-full-route-gas-fee
|
||||
"Sums all the routes fees in wei and then convert the total value to ether"
|
||||
[route]
|
||||
(money/wei->ether (reduce money/add (map calculate-gas-fee route))))
|
||||
|
||||
(defn network-amounts-by-chain
|
||||
[{:keys [route token-decimals native-token? to?]}]
|
||||
(reduce (fn [acc path]
|
||||
@ -47,3 +65,104 @@
|
||||
(assoc acc k (if (money/equal-to v 0) "<0.01" v)))
|
||||
{}
|
||||
amounts))
|
||||
|
||||
(defn token-available-networks-for-suggested-routes
|
||||
[{:keys [balances-per-chain disabled-chain-ids]}]
|
||||
(let [disabled-set (set disabled-chain-ids)]
|
||||
(->> balances-per-chain
|
||||
(filter (fn [[_ {:keys [chain-id]}]]
|
||||
(not (contains? disabled-set chain-id))))
|
||||
(map first))))
|
||||
|
||||
(def ^:private network-priority-score
|
||||
{:ethereum 1
|
||||
:optimism 2
|
||||
:arbitrum 3})
|
||||
|
||||
(def ^:private available-networks-count
|
||||
(count (set (keys network-priority-score))))
|
||||
|
||||
(defn reset-network-amounts-to-zero
|
||||
[network-amounts]
|
||||
(map
|
||||
(fn [network-amount]
|
||||
(cond-> network-amount
|
||||
(= (:type network-amount) :loading)
|
||||
(assoc :total-amount (money/bignumber "0")
|
||||
:type :default)))
|
||||
network-amounts))
|
||||
|
||||
(defn network-amounts
|
||||
[network-values disabled-chain-ids receiver-networks to?]
|
||||
(let [disabled-set (set disabled-chain-ids)
|
||||
receiver-networks-set (set receiver-networks)
|
||||
network-values-keys (set (keys network-values))
|
||||
routes-found? (pos? (count network-values-keys))
|
||||
updated-network-values (when routes-found?
|
||||
(reduce (fn [acc k]
|
||||
(if (or (contains? network-values-keys k)
|
||||
(and to?
|
||||
(not (contains? receiver-networks-set k))))
|
||||
acc
|
||||
(assoc acc k (money/bignumber "0"))))
|
||||
network-values
|
||||
disabled-chain-ids))]
|
||||
(cond-> (->> updated-network-values
|
||||
(map
|
||||
(fn [[k v]]
|
||||
{:chain-id k
|
||||
:total-amount v
|
||||
:type (if (or to? (not (contains? disabled-set k))) :default :disabled)}))
|
||||
(sort-by #(get network-priority-score (network-utils/id->network (:chain-id %))))
|
||||
(filter
|
||||
#(or (and to?
|
||||
(or (contains? receiver-networks-set (:chain-id %))
|
||||
(money/greater-than (:total-amount %) (money/bignumber "0"))))
|
||||
(not to?)))
|
||||
(vec))
|
||||
(and to?
|
||||
routes-found?
|
||||
(< (count updated-network-values) available-networks-count))
|
||||
(conj {:type :add}))))
|
||||
|
||||
(defn loading-network-amounts
|
||||
[valid-networks disabled-chain-ids receiver-networks to?]
|
||||
(let [disabled-set (set disabled-chain-ids)
|
||||
receiver-networks-set (set receiver-networks)
|
||||
receiver-networks-count (count receiver-networks)
|
||||
valid-networks (concat valid-networks disabled-chain-ids)]
|
||||
(cond-> (->> valid-networks
|
||||
(map (fn [k]
|
||||
(cond-> {:chain-id k
|
||||
:type (if (or to?
|
||||
(not (contains? disabled-set k)))
|
||||
:loading
|
||||
:disabled)}
|
||||
(and (not to?) (contains? disabled-set k))
|
||||
(assoc :total-amount (money/bignumber "0")))))
|
||||
(sort-by (fn [item]
|
||||
(get network-priority-score
|
||||
(network-utils/id->network (:chain-id item)))))
|
||||
(filter
|
||||
#(or (and to? (contains? receiver-networks-set (:chain-id %)))
|
||||
(and (not to?)
|
||||
(not (contains? disabled-chain-ids (:chain-id %))))))
|
||||
(vec))
|
||||
(and to? (< receiver-networks-count available-networks-count)) (conj {:type :add}))))
|
||||
|
||||
(defn network-links
|
||||
[route from-values-by-chain to-values-by-chain]
|
||||
(reduce (fn [acc path]
|
||||
(let [from-chain-id (get-in path [:from :chain-id])
|
||||
to-chain-id (get-in path [:to :chain-id])
|
||||
from-chain-id-index (first (keep-indexed #(when (= from-chain-id (:chain-id %2)) %1)
|
||||
from-values-by-chain))
|
||||
to-chain-id-index (first (keep-indexed #(when (= to-chain-id (:chain-id %2)) %1)
|
||||
to-values-by-chain))
|
||||
position-diff (- from-chain-id-index to-chain-id-index)]
|
||||
(conj acc
|
||||
{:from-chain-id from-chain-id
|
||||
:to-chain-id to-chain-id
|
||||
:position-diff position-diff})))
|
||||
[]
|
||||
route))
|
||||
|
@ -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]
|
||||
[utils.map :as map]
|
||||
[utils.money :as money]))
|
||||
|
||||
(deftest test-amount-in-hex
|
||||
@ -93,3 +94,350 @@
|
||||
(doseq [[chain-id exp-value] expected]
|
||||
(is #(or (= (get result chain-id) exp-value)
|
||||
(money/equal-to (get result chain-id) exp-value)))))))
|
||||
|
||||
(deftest test-calculate-gas-fee
|
||||
(testing "EIP-1559 transaction without L1 fee"
|
||||
(let [data {:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "0"}}
|
||||
expected-result (money/bignumber "53063589834657")] ; This is in Wei
|
||||
(is (money/equal-to (utils/calculate-gas-fee data)
|
||||
expected-result))))
|
||||
|
||||
(testing "EIP-1559 transaction with L1 fee of 60,000 Gwei"
|
||||
(let [data {:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "60000"}}
|
||||
expected-result (money/bignumber "113063589834657")] ; Added 60,000 Gwei in Wei to the
|
||||
; previous result
|
||||
(is (money/equal-to (utils/calculate-gas-fee data)
|
||||
expected-result))))
|
||||
|
||||
(testing "Non-EIP-1559 transaction with specified gas price"
|
||||
(let [data {:gas-amount "23487"
|
||||
:gas-fees {:gas-price "2.872721089"
|
||||
:eip-1559-enabled false
|
||||
:l-1-gas-fee "0"}}
|
||||
expected-result (money/bignumber "67471600217343")] ; This is in Wei, for the specified
|
||||
; gas amount and price
|
||||
(is (money/equal-to (utils/calculate-gas-fee data)
|
||||
expected-result)))))
|
||||
|
||||
(deftest test-calculate-full-route-gas-fee
|
||||
(testing "Route with a single EIP-1559 transaction, no L1 fees"
|
||||
(let [route [{:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "0"}}]
|
||||
expected-result (money/bignumber "0.000053063589834657")] ; The Wei amount for the
|
||||
; transaction, converted to
|
||||
; Ether
|
||||
(is (money/equal-to (utils/calculate-full-route-gas-fee route)
|
||||
expected-result))))
|
||||
|
||||
(testing "Route with two EIP-1559 transactions, no L1 fees"
|
||||
(let [route [{:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "0"}}
|
||||
{:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "0"}}]
|
||||
expected-result (money/bignumber "0.000106127179669314")] ; Sum of both transactions' Wei
|
||||
; amounts, converted to Ether
|
||||
(is (money/equal-to (utils/calculate-full-route-gas-fee route)
|
||||
expected-result))))
|
||||
|
||||
(testing "Route with two EIP-1559 transactions, one with L1 fee of 60,000 Gwei"
|
||||
(let [route [{:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "0"}}
|
||||
{:gas-amount "23487"
|
||||
:gas-fees {:max-fee-per-gas-medium "2.259274911"
|
||||
:eip-1559-enabled true
|
||||
:l-1-gas-fee "60000"}}]
|
||||
expected-result (money/bignumber "0.000166127179669314")] ; Added 60,000 Gwei in Wei to
|
||||
; the previous total and
|
||||
; converted to Ether
|
||||
(is (money/equal-to (utils/calculate-full-route-gas-fee route)
|
||||
expected-result)))))
|
||||
|
||||
(deftest test-token-available-networks-for-suggested-routes
|
||||
(testing "Excludes disabled chain-ids correctly"
|
||||
(let [balances-per-chain {"1" {:chain-id "1" :balance 100}
|
||||
"10" {:chain-id "10" :balance 200}
|
||||
"42161" {:chain-id "42161" :balance 300}}
|
||||
disabled-chain-ids ["10"]
|
||||
expected ["1" "42161"]]
|
||||
(is (= expected
|
||||
(utils/token-available-networks-for-suggested-routes {:balances-per-chain balances-per-chain
|
||||
:disabled-chain-ids
|
||||
disabled-chain-ids})))))
|
||||
|
||||
(testing "Returns all chains when no disabled chains are specified"
|
||||
(let [balances-per-chain {"1" {:chain-id "1" :balance 100}
|
||||
"10" {:chain-id "10" :balance 200}
|
||||
"42161" {:chain-id "42161" :balance 300}}
|
||||
disabled-chain-ids []
|
||||
expected ["1" "10" "42161"]]
|
||||
(is (= expected
|
||||
(utils/token-available-networks-for-suggested-routes {:balances-per-chain balances-per-chain
|
||||
:disabled-chain-ids
|
||||
disabled-chain-ids})))))
|
||||
|
||||
(testing "Returns empty list when all chains are disabled"
|
||||
(let [balances-per-chain {"1" {:chain-id "1" :balance 100}
|
||||
"10" {:chain-id "10" :balance 200}
|
||||
"42161" {:chain-id "42161" :balance 300}}
|
||||
disabled-chain-ids ["1" "10" "42161"]
|
||||
expected []]
|
||||
(is (= expected
|
||||
(utils/token-available-networks-for-suggested-routes {:balances-per-chain balances-per-chain
|
||||
:disabled-chain-ids
|
||||
disabled-chain-ids})))))
|
||||
|
||||
(testing "Handles non-existent chain-ids gracefully"
|
||||
(let [balances-per-chain {"59144" {:chain-id "59144" :balance 400}}
|
||||
disabled-chain-ids ["1" "10" "42161"]
|
||||
expected ["59144"]]
|
||||
(is (= expected
|
||||
(utils/token-available-networks-for-suggested-routes {:balances-per-chain balances-per-chain
|
||||
:disabled-chain-ids
|
||||
disabled-chain-ids}))))))
|
||||
|
||||
(deftest test-reset-network-amounts-to-zero
|
||||
(testing "Correctly resets loading network amounts to zero and changes type to default"
|
||||
(let [network-amounts [{:chain-id "1" :total-amount (money/bignumber "100") :type :loading}
|
||||
{:chain-id "10" :total-amount (money/bignumber "200") :type :default}]
|
||||
expected [{:chain-id "1" :total-amount (money/bignumber "0") :type :default}
|
||||
{:chain-id "10" :total-amount (money/bignumber "200") :type :default}]
|
||||
result (utils/reset-network-amounts-to-zero network-amounts)
|
||||
comparisons (map #(map/deep-compare %1 %2)
|
||||
expected
|
||||
result)]
|
||||
(is (every? identity comparisons))))
|
||||
|
||||
(testing "Leaves non-loading types unchanged"
|
||||
(let [network-amounts [{:chain-id "1" :total-amount (money/bignumber "100") :type :default}
|
||||
{:chain-id "10" :total-amount (money/bignumber "0") :type :disabled}]
|
||||
expected [{:chain-id "1" :total-amount (money/bignumber "100") :type :default}
|
||||
{:chain-id "10" :total-amount (money/bignumber "0") :type :disabled}]
|
||||
result (utils/reset-network-amounts-to-zero network-amounts)
|
||||
comparisons (map #(map/deep-compare %1 %2)
|
||||
expected
|
||||
result)]
|
||||
(is (every? identity comparisons))))
|
||||
|
||||
(testing "Processes an empty list without error"
|
||||
(let [network-amounts []
|
||||
expected []
|
||||
result (utils/reset-network-amounts-to-zero network-amounts)
|
||||
comparisons (map #(map/deep-compare %1 %2)
|
||||
expected
|
||||
result)]
|
||||
(is (every? identity comparisons))))
|
||||
|
||||
(testing "Applies transformations to multiple loading entries"
|
||||
(let [network-amounts [{:chain-id "1" :total-amount (money/bignumber "100") :type :loading}
|
||||
{:chain-id "10" :total-amount (money/bignumber "200") :type :loading}]
|
||||
expected [{:chain-id "1" :total-amount (money/bignumber "0") :type :default}
|
||||
{:chain-id "10" :total-amount (money/bignumber "0") :type :default}]
|
||||
result (utils/reset-network-amounts-to-zero network-amounts)
|
||||
comparisons (map #(map/deep-compare %1 %2)
|
||||
expected
|
||||
result)]
|
||||
(is (every? identity comparisons))))
|
||||
|
||||
(testing "Mix of loading and non-loading types"
|
||||
(let [network-amounts [{:chain-id "1" :total-amount (money/bignumber "100") :type :loading}
|
||||
{:chain-id "10" :total-amount (money/bignumber "200") :type :default}
|
||||
{:chain-id "42161" :total-amount (money/bignumber "300") :type :loading}
|
||||
{:chain-id "59144" :total-amount (money/bignumber "0") :type :disabled}]
|
||||
expected [{:chain-id "1" :total-amount (money/bignumber "0") :type :default}
|
||||
{:chain-id "10" :total-amount (money/bignumber "200") :type :default}
|
||||
{:chain-id "42161" :total-amount (money/bignumber "0") :type :default}
|
||||
{:chain-id "59144" :total-amount (money/bignumber "0") :type :disabled}]
|
||||
result (utils/reset-network-amounts-to-zero network-amounts)
|
||||
comparisons (map #(map/deep-compare %1 %2)
|
||||
expected
|
||||
result)]
|
||||
(is (every? identity comparisons)))))
|
||||
|
||||
(deftest test-network-amounts
|
||||
(testing "Handles disabled and receiver networks correctly when to? is true"
|
||||
(let [network-values {"1" (money/bignumber "100")
|
||||
"10" (money/bignumber "200")}
|
||||
disabled-chain-ids ["1"]
|
||||
receiver-networks ["10"]
|
||||
to? true
|
||||
expected [{:chain-id "1"
|
||||
:total-amount (money/bignumber "100")
|
||||
:type :default}
|
||||
{:chain-id "10"
|
||||
:total-amount (money/bignumber "200")
|
||||
:type :default}
|
||||
{:type :add}]
|
||||
result (utils/network-amounts network-values
|
||||
disabled-chain-ids
|
||||
receiver-networks
|
||||
to?)]
|
||||
(is (every? identity (map #(map/deep-compare %1 %2) expected result)))))
|
||||
|
||||
(testing "Adds default amount for non-disabled non-receiver networks when to? is false"
|
||||
(let [network-values {"1" (money/bignumber "100")}
|
||||
disabled-chain-ids ["10"]
|
||||
receiver-networks []
|
||||
to? false
|
||||
expected [{:chain-id "1"
|
||||
:total-amount (money/bignumber "100")
|
||||
:type :default}
|
||||
{:chain-id "10"
|
||||
:total-amount (money/bignumber "0")
|
||||
:type :disabled}]
|
||||
result (utils/network-amounts network-values
|
||||
disabled-chain-ids
|
||||
receiver-networks
|
||||
to?)]
|
||||
(is (every? identity (map #(map/deep-compare %1 %2) expected result)))))
|
||||
|
||||
(testing "Handles empty inputs correctly"
|
||||
(let [network-values {}
|
||||
disabled-chain-ids []
|
||||
receiver-networks []
|
||||
to? true
|
||||
expected []
|
||||
result (utils/network-amounts network-values
|
||||
disabled-chain-ids
|
||||
receiver-networks
|
||||
to?)]
|
||||
(is (= expected result))))
|
||||
|
||||
(testing "Processes case with multiple network interactions"
|
||||
(let [network-values {"1" (money/bignumber "300")
|
||||
"10" (money/bignumber "400")
|
||||
"42161" (money/bignumber "500")}
|
||||
disabled-chain-ids ["1" "42161"]
|
||||
receiver-networks ["10"]
|
||||
to? true
|
||||
expected [{:chain-id "1"
|
||||
:total-amount (money/bignumber "300")
|
||||
:type :default}
|
||||
{:chain-id "10"
|
||||
:total-amount (money/bignumber "400")
|
||||
:type :default}
|
||||
{:chain-id "42161"
|
||||
:total-amount (money/bignumber "500")
|
||||
:type :default}]
|
||||
result (utils/network-amounts network-values
|
||||
disabled-chain-ids
|
||||
receiver-networks
|
||||
to?)]
|
||||
(is (every? identity (map #(map/deep-compare %1 %2) expected result))))))
|
||||
|
||||
(deftest test-loading-network-amounts
|
||||
(testing "Assigns :loading type to valid networks except for disabled ones"
|
||||
(let [valid-networks ["1" "10" "42161"]
|
||||
disabled-chain-ids ["42161"]
|
||||
receiver-networks ["1" "10"]
|
||||
to? true
|
||||
expected [{:chain-id "1" :type :loading}
|
||||
{:chain-id "10" :type :loading}
|
||||
{:type :add}]
|
||||
result (utils/loading-network-amounts valid-networks
|
||||
disabled-chain-ids
|
||||
receiver-networks
|
||||
to?)
|
||||
comparisons (map #(map/deep-compare %1 %2)
|
||||
expected
|
||||
result)]
|
||||
(is (every? identity comparisons))))
|
||||
|
||||
(testing "Assigns :disabled type with zero total-amount to disabled networks when to? is false"
|
||||
(let [valid-networks ["1" "10" "42161"]
|
||||
disabled-chain-ids ["10" "42161"]
|
||||
receiver-networks ["1"]
|
||||
to? false
|
||||
expected [{:chain-id "1" :type :loading}
|
||||
{:chain-id "10" :type :disabled :total-amount (money/bignumber "0")}
|
||||
{:chain-id "42161" :type :disabled :total-amount (money/bignumber "0")}]
|
||||
result (utils/loading-network-amounts valid-networks
|
||||
disabled-chain-ids
|
||||
receiver-networks
|
||||
to?)
|
||||
comparisons (map #(map/deep-compare %1 %2)
|
||||
expected
|
||||
result)]
|
||||
(is (every? identity comparisons))))
|
||||
|
||||
(testing "Filters out networks not in receiver networks when to? is true"
|
||||
(let [valid-networks ["1" "10" "42161" "59144"]
|
||||
disabled-chain-ids ["10"]
|
||||
receiver-networks ["1" "42161"]
|
||||
to? true
|
||||
expected [{:chain-id "1" :type :loading}
|
||||
{:chain-id "42161" :type :loading}]
|
||||
result (utils/loading-network-amounts valid-networks
|
||||
disabled-chain-ids
|
||||
receiver-networks
|
||||
to?)
|
||||
comparisons (map #(map/deep-compare %1 %2)
|
||||
expected
|
||||
result)]
|
||||
(is (every? identity comparisons))))
|
||||
|
||||
(testing "Appends :add type if receiver network count is less than available networks and to? is true"
|
||||
(let [valid-networks ["1" "10" "42161"]
|
||||
disabled-chain-ids ["10"]
|
||||
receiver-networks ["1"]
|
||||
to? true
|
||||
expected [{:chain-id "1" :type :loading}
|
||||
{:type :add}]
|
||||
result (utils/loading-network-amounts valid-networks
|
||||
disabled-chain-ids
|
||||
receiver-networks
|
||||
to?)
|
||||
comparisons (map #(map/deep-compare %1 %2)
|
||||
expected
|
||||
result)]
|
||||
(is (every? identity comparisons)))))
|
||||
|
||||
(deftest test-network-links
|
||||
(testing "Calculates position differences correctly"
|
||||
(let [route [{:from {:chain-id "1"} :to {:chain-id "42161"}}
|
||||
{:from {:chain-id "10"} :to {:chain-id "1"}}
|
||||
{:from {:chain-id "42161"} :to {:chain-id "10"}}]
|
||||
from-values-by-chain [{:chain-id "1"} {:chain-id "10"} {:chain-id "42161"}]
|
||||
to-values-by-chain [{:chain-id "42161"} {:chain-id "1"} {:chain-id "10"}]
|
||||
expected [{:from-chain-id "1" :to-chain-id "42161" :position-diff 0}
|
||||
{:from-chain-id "10" :to-chain-id "1" :position-diff 0}
|
||||
{:from-chain-id "42161" :to-chain-id "10" :position-diff 0}]
|
||||
result (utils/network-links route from-values-by-chain to-values-by-chain)]
|
||||
(is (= expected result))))
|
||||
|
||||
(testing "Handles cases with no position difference"
|
||||
(let [route [{:from {:chain-id "1"} :to {:chain-id "1"}}]
|
||||
from-values-by-chain [{:chain-id "1"} {:chain-id "10"} {:chain-id "42161"}]
|
||||
to-values-by-chain [{:chain-id "1"} {:chain-id "10"} {:chain-id "42161"}]
|
||||
expected [{:from-chain-id "1" :to-chain-id "1" :position-diff 0}]
|
||||
result (utils/network-links route from-values-by-chain to-values-by-chain)]
|
||||
(is (= expected result))))
|
||||
|
||||
(testing "Handles empty route"
|
||||
(let [route []
|
||||
from-values-by-chain []
|
||||
to-values-by-chain []
|
||||
expected []
|
||||
result (utils/network-links route from-values-by-chain to-values-by-chain)]
|
||||
(is (= expected result))))
|
||||
|
||||
(testing "Verifies negative position differences"
|
||||
(let [route [{:from {:chain-id "1"} :to {:chain-id "42161"}}]
|
||||
from-values-by-chain [{:chain-id "1"} {:chain-id "10"} {:chain-id "42161"}]
|
||||
to-values-by-chain [{:chain-id "1"} {:chain-id "10"} {:chain-id "42161"}]
|
||||
expected [{:from-chain-id "1" :to-chain-id "42161" :position-diff -2}]
|
||||
result (utils/network-links route from-values-by-chain to-values-by-chain)]
|
||||
(is (= expected result)))))
|
||||
|
@ -121,6 +121,21 @@
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :suggested-routes)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-sender-network-values
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :sender-network-values)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-receiver-network-values
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :receiver-network-values)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-network-links
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :network-links)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/keypairs
|
||||
:<- [:wallet]
|
||||
|
17
src/utils/map.cljs
Normal file
17
src/utils/map.cljs
Normal file
@ -0,0 +1,17 @@
|
||||
(ns utils.map
|
||||
(:require [utils.money :as money]))
|
||||
|
||||
(defn compare-values
|
||||
"Compares two values, using special handling for BigNumbers and regular equality for others."
|
||||
[v1 v2]
|
||||
(cond
|
||||
(and (money/bignumber? v1) (money/bignumber? v2)) (money/equal-to v1 v2)
|
||||
:else (= v1 v2)))
|
||||
|
||||
(defn deep-compare
|
||||
"Recursively compare two maps, specially handling BigNumber values within the maps."
|
||||
[map1 map2]
|
||||
(and
|
||||
(= (set (keys map1)) (set (keys map2)))
|
||||
(every? (fn [k] (compare-values (get map1 k) (get map2 k)))
|
||||
(keys map1))))
|
@ -37,6 +37,11 @@
|
||||
(new BigNumber (normalize (str n)))
|
||||
(catch :default _ nil))))
|
||||
|
||||
(defn bignumber?
|
||||
"Check if the value is a bignumber."
|
||||
[x]
|
||||
(instance? BigNumber x))
|
||||
|
||||
(defn greater-than-or-equals
|
||||
[^js bn1 ^js bn2]
|
||||
(.greaterThanOrEqualTo bn1 bn2))
|
||||
|
@ -2595,5 +2595,6 @@
|
||||
"this-account-has-no-activity": "This account has no activity",
|
||||
"this-address-has-activity": "This address has activity",
|
||||
"scanning-for-activity": "Scanning for activity...",
|
||||
"send-community-link": "Send community link"
|
||||
"send-community-link": "Send community link",
|
||||
"at-least-one-network-must-be-activated": "At least 1 network must be activated"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user