Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2eb401a16 | ||
|
|
c568a51c60 | ||
|
|
f474edf67d | ||
|
|
dfd90617bf | ||
|
|
9782ba2ac3 | ||
|
|
f0e0c95fe0 | ||
|
|
ef7d977299 | ||
|
|
70a5ed255f | ||
|
|
be1347346c | ||
|
|
803e83ae02 | ||
|
|
64748c939b | ||
|
|
64fb344197 | ||
|
|
f27b402205 | ||
|
|
b22744f81e | ||
|
|
174e44c77d |
@@ -267,9 +267,11 @@ run-metro: export TARGET := clojure
|
||||
run-metro: ##@run Start Metro to build React Native changes
|
||||
@scripts/run-metro.sh
|
||||
|
||||
export RE_FRISK_PORT ?= 4567
|
||||
|
||||
run-re-frisk: export TARGET := clojure
|
||||
run-re-frisk: ##@run Start re-frisk server
|
||||
yarn shadow-cljs run re-frisk-remote.core/start
|
||||
yarn shadow-cljs run re-frisk-remote.core/start ${RE_FRISK_PORT}
|
||||
|
||||
# TODO: Migrate this to a Nix recipe, much the same way as nix/mobile/android/targets/release-android.nix
|
||||
run-android: export TARGET := android
|
||||
@@ -443,7 +445,7 @@ android-ports: export RCT_METRO_PORT ?= 8081
|
||||
android-ports: ##@other Add proxies to Android Device/Simulator
|
||||
adb reverse tcp:$(RCT_METRO_PORT) tcp:$(RCT_METRO_PORT) && \
|
||||
adb reverse tcp:3449 tcp:3449 && \
|
||||
adb reverse tcp:4567 tcp:4567 && \
|
||||
adb reverse tcp:$(RE_FRISK_PORT) tcp:$(RE_FRISK_PORT) && \
|
||||
adb reverse tcp:$(FLOWSTORM_PORT) tcp:$(FLOWSTORM_PORT) && \
|
||||
adb forward tcp:5561 tcp:5561
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
- [Patching](patching.md)
|
||||
- [Creating a pixel perfect UI](pixel-perfection.md)
|
||||
- [Contributing to status-go](status-go-changes.md)
|
||||
- [Status Backend Server](use-status-backend-server.md)
|
||||
- [Malli schemas (recorded demo)](https://www.youtube.com/watch?v=SlRio70aYVI) ([slides](files/forging-code-with-schemas-sep-2023-slides.pdf))
|
||||
|
||||
## Testing
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 98 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 86 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 156 KiB |
@@ -37,6 +37,8 @@ SECRETS_ENV_VARS=(
|
||||
'ALCHEMY_ARBITRUM_SEPOLIA_TOKEN'
|
||||
'ALCHEMY_OPTIMISM_MAINNET_TOKEN'
|
||||
'ALCHEMY_OPTIMISM_SEPOLIA_TOKEN'
|
||||
'ALCHEMY_BASE_MAINNET_TOKEN'
|
||||
'ALCHEMY_BASE_SEPOLIA_TOKEN'
|
||||
'RARIBLE_MAINNET_API_KEY'
|
||||
'RARIBLE_TESTNET_API_KEY'
|
||||
'INFURA_TOKEN'
|
||||
|
||||
+9
-3
@@ -58,7 +58,7 @@
|
||||
:preloads [;; The official recommendation is to
|
||||
;; load the debugger preload first.
|
||||
flow-storm.api
|
||||
re-frisk-remote.preload
|
||||
dev.re-frisk-preload
|
||||
status-im.setup.schema-preload
|
||||
;; In order to use component test helpers in the REPL we need to
|
||||
;; preload namespaces that are not normally required by
|
||||
@@ -87,7 +87,9 @@
|
||||
status-im.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"}
|
||||
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"
|
||||
status-im.config/ALCHEMY_BASE_MAINNET_TOKEN #shadow/env "ALCHEMY_BASE_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_BASE_SEPOLIA_TOKEN #shadow/env "ALCHEMY_BASE_SEPOLIA_TOKEN"}
|
||||
:compiler-options {:output-feature-set :es5
|
||||
;; We disable `:fn-deprecated` warnings because we
|
||||
;; are managing deprecation via clj-kondo and we
|
||||
@@ -123,7 +125,9 @@
|
||||
status-im.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"}
|
||||
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"
|
||||
status-im.config/ALCHEMY_BASE_MAINNET_TOKEN #shadow/env "ALCHEMY_BASE_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_BASE_SEPOLIA_TOKEN #shadow/env "ALCHEMY_BASE_SEPOLIA_TOKEN"}
|
||||
:compiler-options {:output-feature-set :es6
|
||||
;;disable for android build as there
|
||||
;;is an intermittent warning with deftype
|
||||
@@ -165,6 +169,8 @@
|
||||
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"
|
||||
status-im.config/ALCHEMY_BASE_MAINNET_TOKEN #shadow/env "ALCHEMY_BASE_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_BASE_SEPOLIA_TOKEN #shadow/env "ALCHEMY_BASE_SEPOLIA_TOKEN"
|
||||
status-im.config/WALLET_CONNECT_PROJECT_ID #shadow/env "WALLET_CONNECT_PROJECT_ID"}
|
||||
:compiler-options
|
||||
{;; needed because we override require and it
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
(ns dev.re-frisk-preload
|
||||
(:require [re-frisk-remote.core :as re-frisk-remote]
|
||||
[status-im.config]))
|
||||
|
||||
(re-frisk-remote/enable {:host (str status-im.config/re-frisk-host ":" status-im.config/re-frisk-port)})
|
||||
@@ -0,0 +1,43 @@
|
||||
(ns ^{:doc "Mailserver events and API"} legacy.status-im.mailserver.core
|
||||
(:require
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn handle-mailserver-changed
|
||||
[{:keys [db]} ms]
|
||||
(when (seq ms)
|
||||
{:db (assoc db :mailserver/current-id (keyword ms))}))
|
||||
|
||||
(rf/defn handle-mailserver-available
|
||||
[{:keys [db]} ms]
|
||||
{:db (assoc db :mailserver/current-id (keyword ms))})
|
||||
|
||||
(rf/defn toggle-use-mailservers
|
||||
[_ value]
|
||||
{:json-rpc/call
|
||||
[{:method "wakuext_toggleUseMailservers"
|
||||
:params [value]
|
||||
:on-success #(log/info "successfully toggled use-mailservers" value)
|
||||
:on-error #(log/error "failed to toggle use-mailserver" value %)}]})
|
||||
|
||||
(rf/defn update-use-mailservers
|
||||
{:events [:mailserver.ui/use-history-switch-pressed]}
|
||||
[cofx use-mailservers?]
|
||||
(rf/merge cofx
|
||||
(multiaccounts.update/optimistic :use-mailservers? use-mailservers?)
|
||||
(toggle-use-mailservers use-mailservers?)))
|
||||
|
||||
(defn add-mailservers
|
||||
[db mailservers]
|
||||
(reduce (fn [db {:keys [fleet id name] :as mailserver}]
|
||||
(let [updated-mailserver
|
||||
(-> mailserver
|
||||
(update :id keyword)
|
||||
(assoc :name (if (seq name) name id))
|
||||
(dissoc :fleet))]
|
||||
(assoc-in db
|
||||
[:mailserver/mailservers (keyword fleet) (keyword id)]
|
||||
updated-mailserver)))
|
||||
db
|
||||
mailservers))
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns legacy.status-im.subs.mailservers
|
||||
(:require
|
||||
[legacy.status-im.fleet.core :as fleet]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
@@ -17,10 +16,3 @@
|
||||
:<- [:mailserver/mailservers]
|
||||
(fn [[current-fleet mailservers]]
|
||||
(current-fleet mailservers)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:mailserver/preferred-id
|
||||
:<- [:profile/profile]
|
||||
(fn [multiaccount]
|
||||
(get-in multiaccount
|
||||
[:pinned-mailservers (fleet/current-fleet-sub multiaccount)])))
|
||||
|
||||
@@ -38,11 +38,6 @@
|
||||
;;mailserver
|
||||
(reg-root-key-sub :mailserver/current-id :mailserver/current-id)
|
||||
(reg-root-key-sub :mailserver/mailservers :mailserver/mailservers)
|
||||
(reg-root-key-sub :mailserver.edit/mailserver :mailserver.edit/mailserver)
|
||||
(reg-root-key-sub :mailserver/state :mailserver/state)
|
||||
(reg-root-key-sub :mailserver/pending-requests :mailserver/pending-requests)
|
||||
(reg-root-key-sub :mailserver/request-error? :mailserver/request-error)
|
||||
(reg-root-key-sub :mailserver/fetching-gaps-in-progress :mailserver/fetching-gaps-in-progress)
|
||||
|
||||
;;contacts
|
||||
(reg-root-key-sub :contacts/contacts-raw :contacts/contacts)
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.offline-messaging-settings.styles
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.utils.styles :as styles]))
|
||||
|
||||
(def wrapper
|
||||
{:flex 1})
|
||||
|
||||
(styles/defn mailserver-item
|
||||
[]
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between
|
||||
:padding-horizontal 16
|
||||
:ios {:height 64}
|
||||
:android {:height 56}})
|
||||
|
||||
(def mailserver-item-name-text
|
||||
{:typography :title})
|
||||
|
||||
(def switch-container
|
||||
{:height 52})
|
||||
|
||||
(def automatic-selection-container
|
||||
{:border-top-width 1
|
||||
:border-top-color colors/gray-lighter
|
||||
:margin-top 16})
|
||||
|
||||
(def explanation-text
|
||||
{:color colors/gray})
|
||||
|
||||
(def use-history-explanation-text-container
|
||||
{:margin-right 16
|
||||
:margin-left 16
|
||||
:margin-top 8
|
||||
:margin-bottom 16})
|
||||
|
||||
(def history-nodes-label
|
||||
{:color colors/gray
|
||||
:padding-horizontal 16
|
||||
:margin-top 48})
|
||||
@@ -1,88 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.offline-messaging-settings.views
|
||||
(:require-macros [legacy.status-im.utils.views :as views])
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.list.views :as list]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.offline-messaging-settings.styles :as styles]
|
||||
[legacy.status-im.ui.screens.profile.components.views :as profile.components]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn pinned-state
|
||||
[pinned?]
|
||||
[react/view {:style styles/automatic-selection-container}
|
||||
[react/view {:style styles/switch-container}
|
||||
[profile.components/settings-switch-item
|
||||
{:label-kw :t/mailserver-automatic
|
||||
:value (not pinned?)
|
||||
:action-fn #(if pinned?
|
||||
(re-frame/dispatch [:mailserver.ui/unpin-pressed])
|
||||
(re-frame/dispatch [:mailserver.ui/pin-pressed]))}]]
|
||||
[react/view {:style {:padding-horizontal 16}}
|
||||
[react/text {:style styles/explanation-text}
|
||||
(i18n/label :t/mailserver-automatic-switch-explanation)]]])
|
||||
|
||||
(defn render-row
|
||||
[{:keys [name id custom]} _ _ {:keys [current-mailserver-id preferred-mailserver-id]}]
|
||||
(let [pinned? preferred-mailserver-id
|
||||
connected? (= id current-mailserver-id)
|
||||
visible? (or pinned? ; show everything when auto selection is turned off
|
||||
(and (not pinned?) ; auto selection turned on
|
||||
(= current-mailserver-id id)))] ; show only the selected server
|
||||
|
||||
(when visible?
|
||||
[react/touchable-highlight
|
||||
{:on-press (when pinned?
|
||||
#(if custom
|
||||
(re-frame/dispatch [:mailserver.ui/custom-mailserver-selected id])
|
||||
(re-frame/dispatch [:mailserver.ui/default-mailserver-selected id])))
|
||||
:accessibility-label :mailserver-item}
|
||||
[react/view (styles/mailserver-item)
|
||||
[react/text {:style styles/mailserver-item-name-text}
|
||||
name]
|
||||
|
||||
(if pinned?
|
||||
[quo/radio {:value connected?}]
|
||||
[icons/icon :check {:color colors/blue}])]])))
|
||||
|
||||
(views/defview offline-messaging-settings
|
||||
[]
|
||||
(views/letsubs [current-mailserver-id [:mailserver/current-id]
|
||||
preferred-mailserver-id [:mailserver/preferred-id]
|
||||
mailservers [:mailserver/fleet-mailservers]
|
||||
{:keys [use-mailservers?]} [:profile/profile]]
|
||||
[react/view {:style styles/wrapper}
|
||||
[topbar/topbar
|
||||
{:title (i18n/label :t/history-nodes)
|
||||
:right-accessories
|
||||
[{:icon :main-icons/add-circle
|
||||
:on-press #(re-frame/dispatch [:mailserver.ui/add-pressed])}]}]
|
||||
|
||||
[react/scroll-view
|
||||
[react/view {:style styles/switch-container}
|
||||
[profile.components/settings-switch-item
|
||||
{:label-kw :t/offline-messaging-use-history-nodes
|
||||
:value use-mailservers?
|
||||
:action-fn #(re-frame/dispatch [:mailserver.ui/use-history-switch-pressed
|
||||
(not use-mailservers?)])}]]
|
||||
[react/view {:style styles/use-history-explanation-text-container}
|
||||
[react/text {:style styles/explanation-text}
|
||||
(i18n/label :t/offline-messaging-use-history-explanation)]]
|
||||
|
||||
(when use-mailservers?
|
||||
[:<>
|
||||
[pinned-state preferred-mailserver-id]
|
||||
|
||||
[react/text {:style styles/history-nodes-label}
|
||||
(i18n/label :t/history-nodes)]
|
||||
[list/flat-list
|
||||
{:data (vals mailservers)
|
||||
:default-separator? false
|
||||
:key-fn :name
|
||||
:render-data {:current-mailserver-id current-mailserver-id
|
||||
:preferred-mailserver-id preferred-mailserver-id}
|
||||
:render-fn render-row}]])]]))
|
||||
@@ -12,7 +12,6 @@
|
||||
[legacy.status-im.ui.screens.help-center.views :as help-center]
|
||||
[legacy.status-im.ui.screens.log-level-settings.views :as log-level-settings]
|
||||
[legacy.status-im.ui.screens.notifications-settings.views :as notifications-settings]
|
||||
[legacy.status-im.ui.screens.offline-messaging-settings.views :as offline-messaging-settings]
|
||||
[legacy.status-im.ui.screens.pairing.views :as pairing]
|
||||
[legacy.status-im.ui.screens.peers-stats :as peers-stats]
|
||||
[legacy.status-im.ui.screens.profile.seed.views :as profile.seed]
|
||||
@@ -113,9 +112,6 @@
|
||||
:options {:topBar (topbar-options (i18n/label :t/devices))
|
||||
:insets {:top? true}}
|
||||
:component pairing/installations}
|
||||
{:name :offline-messaging-settings
|
||||
:options {:insets {:top? true}}
|
||||
:component offline-messaging-settings/offline-messaging-settings}
|
||||
{:name :rpc-usage-info
|
||||
:options {:topBar (topbar-options :t/rpc-usage-info)
|
||||
:insets {:top? true}}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[quo.core :as quo]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.clipboard :as clipboard]
|
||||
[status-im.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -67,10 +68,10 @@
|
||||
{:size :small
|
||||
:accessibility-label :offline-messages-settings-button
|
||||
:title (i18n/label :t/history-nodes)
|
||||
:on-press #(re-frame/dispatch [:navigate-to :offline-messaging-settings])
|
||||
:on-press (fn []
|
||||
(clipboard/set-string current-mailserver-name))
|
||||
:accessory :text
|
||||
:accessory-text (when use-mailservers? current-mailserver-name)
|
||||
:chevron true}]
|
||||
:accessory-text (when use-mailservers? current-mailserver-name)}]
|
||||
;; TODO(Ferossgp): Devider componemt
|
||||
[react/view
|
||||
{:height 1
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
[variant-colors]
|
||||
{:color (:label variant-colors)})
|
||||
|
||||
(def counter-container
|
||||
(def right-label-container
|
||||
{:flex 1
|
||||
:align-items :flex-end})
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(defn- label-&-counter
|
||||
[{:keys [label current-chars char-limit variant-colors theme]}]
|
||||
(defn- label-line
|
||||
[{:keys [label label-right current-chars char-limit variant-colors theme]}]
|
||||
[rn/view
|
||||
{:accessibility-label :input-labels
|
||||
:style style/texts-container}
|
||||
@@ -18,17 +18,24 @@
|
||||
:weight :medium
|
||||
:size :paragraph-2}
|
||||
label]]
|
||||
(when-let [count-text (some->> char-limit
|
||||
(str current-chars "/"))]
|
||||
[rn/view {:style style/counter-container}
|
||||
(when label-right
|
||||
[rn/view {:style style/right-label-container}
|
||||
[text/text
|
||||
{:style (style/counter-color {:current-chars current-chars
|
||||
:char-limit char-limit
|
||||
:variant-colors variant-colors
|
||||
:theme theme})
|
||||
{:style (style/label-color variant-colors)
|
||||
:weight :regular
|
||||
:size :paragraph-2}
|
||||
count-text]])])
|
||||
label-right]])
|
||||
(when char-limit
|
||||
(let [count-text (str current-chars "/" char-limit)]
|
||||
[rn/view {:style style/right-label-container}
|
||||
[text/text
|
||||
{:style (style/counter-color {:current-chars current-chars
|
||||
:char-limit char-limit
|
||||
:variant-colors variant-colors
|
||||
:theme theme})
|
||||
:weight :regular
|
||||
:size :paragraph-2}
|
||||
count-text]]))])
|
||||
|
||||
(defn- left-accessory
|
||||
[{:keys [variant-colors small? icon-name]}]
|
||||
@@ -65,7 +72,7 @@
|
||||
(defn- base-input
|
||||
[{:keys [blur? error? right-icon left-icon disabled? small? button
|
||||
label char-limit multiline? clearable? on-focus on-blur container-style input-container-style
|
||||
on-change-text on-char-limit-reach weight default-value on-clear placeholder]
|
||||
on-change-text on-char-limit-reach weight default-value on-clear placeholder label-right]
|
||||
:as props}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
ref (rn/use-ref-atom nil)
|
||||
@@ -115,10 +122,11 @@
|
||||
;; https://github.com/facebook/react-native/issues/27687
|
||||
modified-placeholder (if platform/android? (str "\u2009" placeholder) placeholder)]
|
||||
[rn/view {:style container-style}
|
||||
(when (or label char-limit)
|
||||
[label-&-counter
|
||||
(when (or label char-limit label-right)
|
||||
[label-line
|
||||
{:variant-colors variant-colors
|
||||
:label label
|
||||
:label-right label-right
|
||||
:current-chars char-count
|
||||
:char-limit char-limit
|
||||
:theme theme}])
|
||||
@@ -199,6 +207,7 @@
|
||||
- :on-clear - Function executed when the clear button is pressed.
|
||||
- :button - Map containing `:on-press` & `:text` keys, if provided renders a button
|
||||
- :label - A string to set as label for this input.
|
||||
- :label-right - Additional label aligned to the right
|
||||
- :char-limit - A number to set a maximum char limit for this input.
|
||||
- :on-char-limit-reach - Function executed each time char limit is reached or exceeded.
|
||||
- :default-shown? - boolean to show password input initially
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
subtitle]]])
|
||||
|
||||
(defn- main-variant
|
||||
[{:keys [title subtitle button-label image max-height accessibility-label on-press]}]
|
||||
[{:keys [title subtitle button-label image max-height accessibility-label on-press button-type]}]
|
||||
[rn/view {:style style/main-variant}
|
||||
[rn/view {:style style/main-variant-text-container}
|
||||
[text/text
|
||||
@@ -58,7 +58,7 @@
|
||||
[button/button
|
||||
{:on-press on-press
|
||||
:accessibility-label accessibility-label
|
||||
:type :grey
|
||||
:type (or button-type :grey)
|
||||
:size 40
|
||||
:container-style style/main-button
|
||||
:theme :dark
|
||||
@@ -66,7 +66,7 @@
|
||||
button-label]])
|
||||
|
||||
(defn small-option-card
|
||||
[{:keys [variant title subtitle button-label image max-height on-press accessibility-label]
|
||||
[{:keys [variant title subtitle button-label image max-height on-press accessibility-label button-type]
|
||||
:or {variant :main accessibility-label :small-option-card}}]
|
||||
(let [main-variant? (= variant :main)
|
||||
card-component (if main-variant? main-variant icon-variant)
|
||||
@@ -82,4 +82,5 @@
|
||||
:on-press on-press
|
||||
:accessibility-label accessibility-label
|
||||
:image image
|
||||
:max-height max-height}]]))
|
||||
:max-height max-height
|
||||
:button-type button-type}]]))
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
:padding-bottom 2})
|
||||
|
||||
(defn title-style
|
||||
[{:keys [status theme]}]
|
||||
{:padding-left 4
|
||||
[{:keys [status theme networks-shown?]}]
|
||||
{:padding-left (if networks-shown? 4 0)
|
||||
:margin-top -1
|
||||
:color (when (= status :error)
|
||||
(colors/resolve-color :danger theme))})
|
||||
|
||||
@@ -14,14 +14,16 @@
|
||||
:theme theme
|
||||
:blur? blur?})
|
||||
container-style)}
|
||||
[preview-list/view
|
||||
{:type :network
|
||||
:number (count networks)
|
||||
:size :size-16}
|
||||
networks]
|
||||
(when networks
|
||||
[preview-list/view
|
||||
{:type :network
|
||||
:number (count networks)
|
||||
:size :size-16}
|
||||
networks])
|
||||
[text/text
|
||||
{:weight :medium
|
||||
:size :paragraph-2
|
||||
:style (style/title-style {:status status
|
||||
:theme theme})}
|
||||
:style (style/title-style {:status status
|
||||
:theme theme
|
||||
:networks-shown? networks})}
|
||||
title]]))
|
||||
|
||||
@@ -30,13 +30,16 @@
|
||||
|
||||
(defn networks
|
||||
[values theme]
|
||||
(let [{:keys [ethereum optimism arbitrum]} values
|
||||
show-optimism? (and optimism
|
||||
(or (pos? (:amount optimism))
|
||||
(= (:amount optimism) "<0.01")))
|
||||
show-arbitrum? (and arbitrum
|
||||
(or (pos? (:amount arbitrum))
|
||||
(= (:amount arbitrum) "<0.01")))]
|
||||
(let [{:keys [ethereum optimism arbitrum base]} values
|
||||
show-optimism? (and optimism
|
||||
(or (pos? (:amount optimism))
|
||||
(= (:amount optimism) "<0.01")))
|
||||
show-arbitrum? (and arbitrum
|
||||
(or (pos? (:amount arbitrum))
|
||||
(= (:amount arbitrum) "<0.01")))
|
||||
show-base? (and base
|
||||
(or (pos? (:amount base))
|
||||
(= (:amount base) "<0.01")))]
|
||||
[rn/view
|
||||
{:style style/networks-container
|
||||
:accessibility-label :networks}
|
||||
@@ -56,6 +59,11 @@
|
||||
[network-amount
|
||||
{:network :arbitrum
|
||||
:amount (str (:amount arbitrum) " " (or (:token-symbol arbitrum) "ARB"))
|
||||
:theme theme}])
|
||||
(when show-base?
|
||||
[network-amount
|
||||
{:network :base
|
||||
:amount (str (:amount base) " " (or (:token-symbol base) "ETH"))
|
||||
:theme theme}])]))
|
||||
|
||||
(defn- view-internal
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
[:currency-symbol [:maybe [:or :string :keyword]]]
|
||||
[:hint-component {:optional true} [:maybe :schema.common/hiccup]]
|
||||
[:on-token-press {:optional true} [:maybe fn?]]
|
||||
[:on-swap [:maybe fn?]]
|
||||
[:on-swap {:optional true} [:maybe fn?]]
|
||||
[:container-style {:optional true} [:maybe :map]]
|
||||
[:error? [:maybe :boolean]]
|
||||
[:show-token-icon? {:optional true} [:maybe :boolean]]
|
||||
[:value [:maybe :string]]
|
||||
[:converted-value [:maybe :string]]]]]
|
||||
[:converted-value {:optional true} [:maybe :string]]
|
||||
[:swappable? {:optional true} [:maybe :boolean]]]]]
|
||||
:any])
|
||||
|
||||
@@ -19,9 +19,8 @@
|
||||
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
|
||||
:padding-bottom 3})
|
||||
|
||||
(defn input-container
|
||||
[window-width]
|
||||
{:width (- window-width 120)
|
||||
(def input-container
|
||||
{:flex 1
|
||||
:margin-left 8
|
||||
:margin-right 8
|
||||
:flex-direction :row
|
||||
|
||||
@@ -20,17 +20,18 @@
|
||||
(string/upper-case (or (clj->js text) ""))])
|
||||
|
||||
(defn input-section
|
||||
[{:keys [token-symbol on-token-press value error? on-swap currency-symbol]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
window-width (:width (rn/get-window))]
|
||||
[{:keys [token-symbol on-token-press value error? on-swap currency-symbol show-token-icon?
|
||||
swappable?]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/pressable
|
||||
{:style {:width "100%"
|
||||
:flex-direction :row}
|
||||
:on-press on-token-press}
|
||||
[token/view
|
||||
{:token token-symbol
|
||||
:size :size-32}]
|
||||
[rn/view {:style (style/input-container window-width)}
|
||||
(when show-token-icon?
|
||||
[token/view
|
||||
{:token token-symbol
|
||||
:size :size-32}])
|
||||
[rn/view {:style style/input-container}
|
||||
[rn/text-input
|
||||
{:style (style/text-input theme error?)
|
||||
:placeholder-text-color (style/placeholder-text theme)
|
||||
@@ -39,14 +40,15 @@
|
||||
:editable false
|
||||
:value value}]
|
||||
[token-name-text theme currency-symbol]]
|
||||
[button/button
|
||||
{:icon true
|
||||
:icon-only? true
|
||||
:size 32
|
||||
:on-press #(when on-swap (on-swap))
|
||||
:type :outline
|
||||
:accessibility-label :reorder}
|
||||
:i/reorder]]))
|
||||
(when swappable?
|
||||
[button/button
|
||||
{:icon true
|
||||
:icon-only? true
|
||||
:size 32
|
||||
:on-press #(when on-swap (on-swap))
|
||||
:type :outline
|
||||
:accessibility-label :reorder}
|
||||
:i/reorder])]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [token-symbol
|
||||
@@ -57,26 +59,33 @@
|
||||
on-swap
|
||||
converted-value
|
||||
hint-component
|
||||
currency-symbol]}]
|
||||
show-token-icon?
|
||||
currency-symbol
|
||||
swappable?]
|
||||
:or {show-token-icon? true
|
||||
swappable? true}}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
width (:width (rn/get-window))]
|
||||
[rn/view {:style (merge (style/main-container width) container-style)}
|
||||
[rn/view {:style style/amount-container}
|
||||
[input-section
|
||||
{:theme theme
|
||||
:token-symbol token-symbol
|
||||
:on-token-press on-token-press
|
||||
:value value
|
||||
:error? error?
|
||||
:on-swap on-swap
|
||||
:currency-symbol currency-symbol}]]
|
||||
{:theme theme
|
||||
:token-symbol token-symbol
|
||||
:on-token-press on-token-press
|
||||
:value value
|
||||
:error? error?
|
||||
:on-swap on-swap
|
||||
:currency-symbol currency-symbol
|
||||
:show-token-icon? show-token-icon?
|
||||
:swappable? swappable?}]]
|
||||
[divider-line/view {:container-style (style/divider theme)}]
|
||||
[rn/view {:style style/data-container}
|
||||
hint-component
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/converted-amount theme)}
|
||||
converted-value]]]))
|
||||
(when swappable?
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/converted-amount theme)}
|
||||
converted-value])]]))
|
||||
|
||||
(def view (schema/instrument #'view-internal component-schema/?schema))
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
:hermez (js/require "../resources/images/networks/Hermez.png")
|
||||
:optimism (js/require "../resources/images/networks/Optimism.png")
|
||||
:paraswap (js/require "../resources/images/networks/Paraswap.png")
|
||||
:base (js/require "../resources/images/networks/Base.png")
|
||||
:polygon (js/require "../resources/images/networks/Polygon.png")
|
||||
:scroll (js/require "../resources/images/networks/Scroll.png")
|
||||
:taiko (js/require "../resources/images/networks/Taiko.png")
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
(when (money/bignumber? (value-bn state))
|
||||
(money/greater-than (value-bn state) (upper-limit-bn state)))))
|
||||
|
||||
(defn- lower-limit-exceeded?
|
||||
(defn lower-limit-exceeded?
|
||||
[state]
|
||||
(and (lower-limit state)
|
||||
(when (money/bignumber? (value-bn state))
|
||||
@@ -78,16 +78,19 @@
|
||||
|
||||
(defn set-upper-limit
|
||||
[state limit]
|
||||
(when limit
|
||||
(if limit
|
||||
(-> state
|
||||
(assoc :upper-limit limit)
|
||||
recheck-errorness)))
|
||||
recheck-errorness)
|
||||
state))
|
||||
|
||||
(defn set-lower-limit
|
||||
[state limit]
|
||||
(-> state
|
||||
(assoc :lower-limit limit)
|
||||
recheck-errorness))
|
||||
(if limit
|
||||
(-> state
|
||||
(assoc :lower-limit limit)
|
||||
recheck-errorness)
|
||||
state))
|
||||
|
||||
(defn increase
|
||||
[state]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
:music (js/require "../resources/images/ui2/music.png")
|
||||
:podcasts (js/require "../resources/images/ui2/podcasts.png")
|
||||
:generate-keys (js/require "../resources/images/ui2/generate-keys.png")
|
||||
:generate-keys1 (js/require "../resources/images/ui2/generating-keys-1.png")
|
||||
:add-key-to-keycard (js/require "../resources/images/ui2/add-key-to-keycard.png")
|
||||
:ethereum-address (js/require "../resources/images/ui2/ethereum-address.png")
|
||||
:use-keycard (js/require "../resources/images/ui2/keycard.png")
|
||||
:use-recovery-phrase (js/require "../resources/images/ui2/recovery-phrase.png")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im.common.signals.events
|
||||
(:require
|
||||
[legacy.status-im.chat.models.message :as models.message]
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
[legacy.status-im.visibility-status-updates.core :as visibility-status-updates]
|
||||
[oops.core :as oops]
|
||||
[status-im.common.pairing.events :as pairing]
|
||||
@@ -63,6 +64,12 @@
|
||||
"messages.new"
|
||||
(messages.transport/sanitize-messages-and-process-response cofx event-js true)
|
||||
|
||||
"mailserver.changed"
|
||||
(mailserver/handle-mailserver-changed cofx (oops/oget event-js :id))
|
||||
|
||||
"mailserver.available"
|
||||
(mailserver/handle-mailserver-available cofx (oops/oget event-js :id))
|
||||
|
||||
"discovery.summary"
|
||||
(summary cofx (transforms/js->clj event-js))
|
||||
|
||||
|
||||
@@ -11,28 +11,28 @@
|
||||
[{:keys [track-text customization-color auth-button-label on-auth-success on-auth-fail
|
||||
auth-button-icon-left size blur? container-style disabled? dependencies on-complete]
|
||||
:or {container-style {:flex 1}}}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
auth-method (rf/sub [:auth-method])
|
||||
biometric-auth? (= auth-method constants/auth-method-biometric)
|
||||
on-complete-callback (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:standard-auth/authorize
|
||||
{:auth-button-icon-left auth-button-icon-left
|
||||
:theme theme
|
||||
:blur? blur?
|
||||
:biometric-auth? biometric-auth?
|
||||
:on-auth-success on-auth-success
|
||||
:on-auth-fail on-auth-fail
|
||||
:auth-button-label auth-button-label}]))
|
||||
(vec (conj dependencies on-auth-success on-auth-fail)))
|
||||
on-slider-complete (rn/use-callback
|
||||
(fn [reset-slider-fn]
|
||||
(js/setTimeout #(reset-slider-fn false) 500)
|
||||
(if (fn? on-complete)
|
||||
(on-complete)
|
||||
(on-complete-callback)))
|
||||
[on-complete on-complete-callback])
|
||||
biometric-type (rf/sub [:biometrics/supported-type])]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
auth-method (rf/sub [:auth-method])
|
||||
biometric-auth? (= auth-method constants/auth-method-biometric)
|
||||
authorization-callback (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:standard-auth/authorize
|
||||
{:auth-button-icon-left auth-button-icon-left
|
||||
:theme theme
|
||||
:blur? blur?
|
||||
:biometric-auth? biometric-auth?
|
||||
:on-auth-success on-auth-success
|
||||
:on-auth-fail on-auth-fail
|
||||
:auth-button-label auth-button-label}]))
|
||||
(vec (conj dependencies on-auth-success on-auth-fail)))
|
||||
on-slider-complete (rn/use-callback
|
||||
(fn [reset-slider-fn]
|
||||
(js/setTimeout #(reset-slider-fn false) 500)
|
||||
(if (fn? on-complete)
|
||||
(on-complete)
|
||||
(authorization-callback)))
|
||||
[on-complete authorization-callback])
|
||||
biometric-type (rf/sub [:biometrics/supported-type])]
|
||||
[quo/slide-button
|
||||
{:container-style container-style
|
||||
:size size
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
(goog-define ALCHEMY_ARBITRUM_SEPOLIA_TOKEN "")
|
||||
(goog-define ALCHEMY_OPTIMISM_MAINNET_TOKEN "")
|
||||
(goog-define ALCHEMY_OPTIMISM_SEPOLIA_TOKEN "")
|
||||
(goog-define ALCHEMY_BASE_MAINNET_TOKEN "")
|
||||
(goog-define ALCHEMY_BASE_SEPOLIA_TOKEN "")
|
||||
(goog-define WALLET_CONNECT_PROJECT_ID "87815d72a81d739d2a7ce15c2cfdefb3")
|
||||
(goog-define MIXPANEL_APP_ID "3350627")
|
||||
(goog-define MIXPANEL_TOKEN "5c73bda2d36a9f688a5ee45641fb6775")
|
||||
@@ -38,9 +40,11 @@
|
||||
(def mainnet-tx-details-base-link "https://etherscan.io/tx")
|
||||
(def optimism-mainnet-tx-details-base-link "https://optimistic.etherscan.io/tx")
|
||||
(def arbitrum-mainnet-tx-details-base-link "https://arbiscan.io/tx")
|
||||
(def base-mainnet-tx-details-base-link "https://basescan.org/tx")
|
||||
(def mainnet-sepolia-tx-details-base-link "https://sepolia.etherscan.io/tx")
|
||||
(def optimism-sepolia-tx-details-base-link "https://sepolia-optimistic.etherscan.io/tx")
|
||||
(def arbitrum-sepolia-tx-details-base-link "https://sepolia.arbiscan.io/tx")
|
||||
(def base-sepolia-tx-details-base-link "https://sepolia.basescan.org/tx")
|
||||
(def opensea-link "https://opensea.io")
|
||||
(def opensea-tesnet-link "https://testnets.opensea.io")
|
||||
|
||||
@@ -124,3 +128,6 @@
|
||||
(goog-define STATUS_BACKEND_SERVER_ROOT_DATA_DIR "")
|
||||
;; if you're using android simulator, I suggest set the env variable to "http://10.0.2.2:"
|
||||
(goog-define STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX "https://localhost:")
|
||||
|
||||
(def re-frisk-host (get-config :RE_FRISK_HOST "localhost"))
|
||||
(def re-frisk-port (get-config :RE_FRISK_PORT "4567"))
|
||||
|
||||
@@ -396,29 +396,34 @@
|
||||
(def ^:const arbitrum-sepolia-chain-id 421614)
|
||||
(def ^:const optimism-mainnet-chain-id 10)
|
||||
(def ^:const optimism-sepolia-chain-id 11155420)
|
||||
(def ^:const base-mainnet-chain-id 8453)
|
||||
(def ^:const base-sepolia-chain-id 84532)
|
||||
|
||||
(def opensea-url-names
|
||||
{:ethereum "ethereum"
|
||||
:sepolia "sepolia"})
|
||||
|
||||
(def ^:const mainnet-chain-ids
|
||||
#{ethereum-mainnet-chain-id arbitrum-mainnet-chain-id optimism-mainnet-chain-id})
|
||||
#{ethereum-mainnet-chain-id arbitrum-mainnet-chain-id optimism-mainnet-chain-id base-mainnet-chain-id})
|
||||
|
||||
(def ^:const sepolia-chain-ids
|
||||
#{ethereum-sepolia-chain-id arbitrum-sepolia-chain-id optimism-sepolia-chain-id})
|
||||
#{ethereum-sepolia-chain-id arbitrum-sepolia-chain-id optimism-sepolia-chain-id base-sepolia-chain-id})
|
||||
|
||||
(def ^:const mainnet-short-name "eth")
|
||||
(def ^:const ethereum-short-name "eth")
|
||||
(def ^:const optimism-short-name "oeth")
|
||||
(def ^:const arbitrum-short-name "arb1")
|
||||
(def ^:const base-short-name "base")
|
||||
|
||||
(def ^:const mainnet-abbreviated-name "Eth.")
|
||||
(def ^:const optimism-abbreviated-name "Oeth.")
|
||||
(def ^:const arbitrum-abbreviated-name "Arb1.")
|
||||
(def ^:const base-abbreviated-name "Base")
|
||||
|
||||
(def ^:const mainnet-full-name "Mainnet")
|
||||
(def ^:const optimism-full-name "Optimism")
|
||||
(def ^:const arbitrum-full-name "Arbitrum")
|
||||
(def ^:const base-full-name "Base")
|
||||
|
||||
(def ^:const sepolia-full-name "Sepolia")
|
||||
|
||||
@@ -426,11 +431,13 @@
|
||||
(def ^:const ethereum-network-name :ethereum)
|
||||
(def ^:const optimism-network-name :optimism)
|
||||
(def ^:const arbitrum-network-name :arbitrum)
|
||||
(def ^:const base-network-name :base)
|
||||
|
||||
(def ^:const layer-1-network 1)
|
||||
(def ^:const layer-2-network 2)
|
||||
|
||||
(def ^:const default-network-names [mainnet-network-name optimism-network-name arbitrum-network-name])
|
||||
(def ^:const default-network-names
|
||||
[mainnet-network-name optimism-network-name arbitrum-network-name base-network-name])
|
||||
|
||||
(def ^:const default-network-count (count default-network-names))
|
||||
|
||||
@@ -441,7 +448,10 @@
|
||||
(def ^:const wallet-account-name-max-length 20)
|
||||
|
||||
|
||||
(def ^:const gas-rate-low 0)
|
||||
(def ^:const gas-rate-medium 1)
|
||||
(def ^:const gas-rate-high 2)
|
||||
(def ^:const gas-rate-custom 3)
|
||||
(def ^:const send-type-transfer 0)
|
||||
(def ^:const send-type-bridge 5)
|
||||
(def ^:const send-type-erc-721-transfer 6)
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.not-implemented :as not-implemented]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -43,20 +45,23 @@
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back
|
||||
:right-side [(when config/show-not-implemented-features?
|
||||
{:icon-name :i/info
|
||||
:on-press not-implemented/alert})]}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/ready-add-keypair-keycard)
|
||||
:description :text
|
||||
:description-text ""}]
|
||||
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :generate-keys1)}]]
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:style {:flex 1 :align-self :center :margin-vertical 37}
|
||||
:source (resources/get-image :add-key-to-keycard)}]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/ready-to-scan)
|
||||
:button-one-label (i18n/label :t/scan-keycard)
|
||||
:button-one-props {:on-press #(rf/dispatch [:keycard/create.start])}}]])
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
(ns status-im.contexts.keycard.different-card.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/different-keycard)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/scan-previous-keycard)}]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/button {:on-press events-helper/navigate-back}
|
||||
(i18n/label :t/try-again)]]])
|
||||
|
||||
@@ -52,6 +52,10 @@
|
||||
(fn [args]
|
||||
(keycard/export-key (keycard.utils/wrap-handlers args))))
|
||||
|
||||
(rf/reg-fx :effects.keycard/factory-reset
|
||||
(fn [args]
|
||||
(keycard/factory-reset (keycard.utils/wrap-handlers args))))
|
||||
|
||||
(rf/reg-fx :effects.keycard/sign
|
||||
(fn [args]
|
||||
(-> (keycard/sign args)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
:button-label (i18n/label :t/lets-go)
|
||||
:accessibility-label :create-new-profile-keycard
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:button-type :primary
|
||||
:on-press #(rf/dispatch [:keycard/create.get-phrase])}]]
|
||||
[quo/information-box
|
||||
{:type :default
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.contexts.keycard.factory-reset.view :as factory-reset]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -31,7 +32,17 @@
|
||||
:description-text description}]
|
||||
[rn/view {:style {:margin-horizontal 20}}
|
||||
[quo/keycard {:holder-name ""}]
|
||||
[quo/information-box
|
||||
{:type :default
|
||||
:style {:margin-top 20}}
|
||||
(i18n/label :t/unlock-reset-instructions)]]]))
|
||||
(when (not= :keycard/error.keycard-blank error)
|
||||
[:<>
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/what-you-can-do) :container-style {:padding-vertical 8}}]
|
||||
[quo/settings-item
|
||||
{:title (i18n/label :t/factory-reset)
|
||||
:image :icon
|
||||
:image-props :i/placeholder
|
||||
:action :arrow
|
||||
:description :text
|
||||
:description-props {:text (i18n/label :t/remove-keycard-content)}
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content factory-reset/sheet}]))}]])]]))
|
||||
|
||||
@@ -68,6 +68,10 @@
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/export-key data}))
|
||||
|
||||
(rf/reg-event-fx :keycard/factory-reset
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/factory-reset data}))
|
||||
|
||||
(rf/reg-event-fx :keycard/connect-derive-address-and-add-account
|
||||
(fn [_ [{:keys [pin derivation-path key-uid account-preferences]}]]
|
||||
{:fx [[:dispatch
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
(ns status-im.contexts.keycard.factory-reset.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- reset-card
|
||||
[]
|
||||
(rf/dispatch
|
||||
[:keycard/factory-reset
|
||||
{:on-success (fn []
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.factory-reset.success]))
|
||||
:on-failure (fn []
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.factory-reset.fail]))}]))
|
||||
|
||||
(defn- connect-and-reset
|
||||
[key-uid]
|
||||
(rf/dispatch
|
||||
[:keycard/connect
|
||||
{:key-uid key-uid
|
||||
:on-success reset-card
|
||||
:on-error (fn [error]
|
||||
(if (or (= error :keycard/error.keycard-frozen)
|
||||
(= error :keycard/error.keycard-locked)
|
||||
(= error :keycard/error.keycard-unpaired))
|
||||
(reset-card)
|
||||
(do
|
||||
(rf/dispatch [:navigate-back])
|
||||
(if (= error :keycard/error.keycard-wrong-profile)
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.different-card]))
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))))}]))
|
||||
|
||||
(defn success-view
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/keycard-reset-success)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/keycard-empty-ready)}]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/button {:on-press events-helper/navigate-back}
|
||||
(i18n/label :t/done)]]])
|
||||
|
||||
(defn failed-view
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/keycard-reset-failed)}]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/button {:on-press events-helper/navigate-back}
|
||||
(i18n/label :t/try-again)]]])
|
||||
|
||||
(defn sheet
|
||||
[]
|
||||
(let [customization-color (rf/sub [:profile/customization-color])
|
||||
key-uid (rf/sub [:keycard/key-uid])
|
||||
[checked? set-checked] (rn/use-state false)]
|
||||
[:<>
|
||||
[quo/drawer-top {:title (i18n/label :t/factory-reset-keycard)}]
|
||||
[quo/text
|
||||
{:style {:padding-horizontal 20
|
||||
:padding-top 8
|
||||
:padding-bottom 8}}
|
||||
(i18n/label :t/factory-reset-warning)]
|
||||
[quo/disclaimer
|
||||
{:checked? checked?
|
||||
:container-style {:margin-horizontal 20}
|
||||
:on-change #(set-checked (not checked?))}
|
||||
(i18n/label :t/key-pair-erased)]
|
||||
[quo/bottom-actions
|
||||
{:actions :two-actions
|
||||
:button-one-label (i18n/label :t/continue)
|
||||
:button-one-props {:disabled? (not checked?)
|
||||
:customization-color customization-color
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(connect-and-reset key-uid))}
|
||||
:button-two-label (i18n/label :t/cancel)
|
||||
:button-two-props {:type :grey
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet]))}}]]))
|
||||
@@ -19,6 +19,6 @@
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :not-keycard)}]]
|
||||
[rn/view {:padding-horizontal 20}
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/button {:on-press events-helper/navigate-back}
|
||||
(i18n/label :t/try-again)]]])
|
||||
|
||||
@@ -23,29 +23,31 @@
|
||||
:key :title}
|
||||
{:type :select
|
||||
:key :networks
|
||||
:options [{:key 1}
|
||||
:options [{:key 0}
|
||||
{:key 1}
|
||||
{:key 2}
|
||||
{:key 3}]}
|
||||
{:type :boolean
|
||||
:key :blur?}])
|
||||
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom {:title "Tag"
|
||||
:status :default
|
||||
:networks 3})]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
{:state state
|
||||
:descriptor descriptor
|
||||
:blur? (:blur? @state)
|
||||
:show-blur-background? true}
|
||||
[rn/view
|
||||
{:style {:align-self :center
|
||||
:justify-content :center
|
||||
:flex 1}}
|
||||
[quo/network-tags
|
||||
(assoc @state
|
||||
:networks
|
||||
(nth community-networks (dec (:networks @state))))]]])))
|
||||
(let [selected-networks-id (dec (:networks @state))]
|
||||
[preview/preview-container
|
||||
{:state state
|
||||
:descriptor descriptor
|
||||
:blur? (:blur? @state)
|
||||
:show-blur-background? true}
|
||||
[rn/view
|
||||
{:style {:align-self :center
|
||||
:justify-content :center
|
||||
:flex 1}}
|
||||
[quo/network-tags
|
||||
(assoc @state
|
||||
:networks
|
||||
(when (pos? selected-networks-id)
|
||||
(nth community-networks selected-networks-id)))]]]))))
|
||||
|
||||
@@ -22,21 +22,29 @@
|
||||
[{:key :token-symbol
|
||||
:type :select
|
||||
:options [{:key :eth}
|
||||
{:key :snt}]}
|
||||
{:key :snt}
|
||||
{:key :gwei}
|
||||
{:key :units}]}
|
||||
{:key :currency
|
||||
:type :select
|
||||
:options [{:key "$"}
|
||||
{:key "€"}]}
|
||||
{:key :error?
|
||||
:type :boolean}
|
||||
{:key :show-token-icon?
|
||||
:type :boolean}
|
||||
{:key :swappable?
|
||||
:type :boolean}])
|
||||
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom {:token-symbol :eth
|
||||
:currency "$"
|
||||
:crypto? true
|
||||
:error? false})]
|
||||
(let [state (reagent/atom {:token-symbol :eth
|
||||
:currency "$"
|
||||
:crypto? true
|
||||
:error? false
|
||||
:show-token-icon? true
|
||||
:swappable? true})]
|
||||
(fn []
|
||||
(let [{:keys [currency token-symbol crypto? error?]} @state
|
||||
[input-state set-input-state] (rn/use-state controlled-input/init-state)
|
||||
@@ -67,18 +75,20 @@
|
||||
:component-container-style {:flex 1
|
||||
:justify-content :space-between}}
|
||||
[quo/token-input
|
||||
{:token-symbol token-symbol
|
||||
:currency-symbol (if crypto? token-symbol currency)
|
||||
:error? error?
|
||||
:value input-amount
|
||||
:converted-value converted-value
|
||||
:on-swap (fn []
|
||||
(swap! state assoc :crypto? (not crypto?))
|
||||
(swap-between-fiat-and-crypto))
|
||||
:hint-component [quo/network-tags
|
||||
{:networks networks
|
||||
:title title
|
||||
:status (when (:error? @state) :error)}]}]
|
||||
{:token-symbol token-symbol
|
||||
:currency-symbol (if crypto? token-symbol currency)
|
||||
:error? error?
|
||||
:value input-amount
|
||||
:converted-value converted-value
|
||||
:on-swap (fn []
|
||||
(swap! state assoc :crypto? (not crypto?))
|
||||
(swap-between-fiat-and-crypto))
|
||||
:hint-component [quo/network-tags
|
||||
{:networks networks
|
||||
:title title
|
||||
:status (when (:error? @state) :error)}]
|
||||
:show-token-icon? (:show-token-icon? @state)
|
||||
:swappable? (:swappable? @state)}]
|
||||
[quo/numbered-keyboard
|
||||
{:container-style {:padding-bottom (safe-area/get-top)}
|
||||
:left-action :dot
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
:alchemyOptimismMainnetToken config/ALCHEMY_OPTIMISM_MAINNET_TOKEN
|
||||
:alchemyOptimismSepoliaToken config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN
|
||||
:alchemyArbitrumMainnetToken config/ALCHEMY_ARBITRUM_MAINNET_TOKEN
|
||||
:alchemyArbitrumSepoliaToken config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN})
|
||||
:alchemyArbitrumSepoliaToken config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN
|
||||
:alchemyBaseMainnetToken config/ALCHEMY_BASE_MAINNET_TOKEN
|
||||
:alchemyBaseSepoliaToken config/ALCHEMY_BASE_SEPOLIA_TOKEN})
|
||||
|
||||
(defn create
|
||||
[]
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :profile/update-local-picture
|
||||
(fn [{:keys [db now]} [images]]
|
||||
(fn [{:keys [db]} [images]]
|
||||
{:db (if images
|
||||
(assoc-in db
|
||||
[:profile/profile :images]
|
||||
(map #(assoc % :clock now) images))
|
||||
(assoc-in db [:profile/profile :images] images)
|
||||
(update db :profile/profile dissoc :images))}))
|
||||
|
||||
(rf/reg-event-fx :profile/edit-profile-picture-success
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
(ns status-im.contexts.profile.login.events
|
||||
(:require
|
||||
[legacy.status-im.data-store.settings :as data-store.settings]
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
[native-module.core :as native-module]
|
||||
[oops.core :as oops]
|
||||
[status-im.common.keychain.events :as keychain]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
@@ -10,7 +12,8 @@
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
[utils.security.core :as security]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(rf/reg-event-fx :profile.login/login
|
||||
(fn [{:keys [db]}]
|
||||
@@ -132,9 +135,12 @@
|
||||
:on-error #(log/error "node-info: failed error" %)}]]]})))
|
||||
|
||||
(rf/reg-event-fx :profile.login/messenger-started
|
||||
(fn [{:keys [db]} [_]]
|
||||
(let [new-account? (get db :onboarding/new-account?)]
|
||||
{:db (assoc db :messenger/started? true)
|
||||
(fn [{:keys [db]} [response-js]]
|
||||
(let [mailservers (transforms/js->clj (oops/oget response-js :mailservers))
|
||||
new-account? (get db :onboarding/new-account?)]
|
||||
{:db (-> db
|
||||
(assoc :messenger/started? true)
|
||||
(mailserver/add-mailservers mailservers))
|
||||
:fx [[:fetch-chats-preview
|
||||
{:chat-preview-type constants/chat-preview-type-non-community
|
||||
:on-success (fn [result]
|
||||
|
||||
@@ -129,10 +129,8 @@
|
||||
[:dispatch [:hide-bottom-sheet]]]})))
|
||||
|
||||
(rf/reg-event-fx :profile.settings/update-local-picture
|
||||
(fn [{:keys [db now]} [images]]
|
||||
{:db (assoc-in db
|
||||
[:profile/profile :images]
|
||||
(map #(assoc % :clock now) images))}))
|
||||
(fn [{:keys [db]} [images]]
|
||||
{:db (assoc-in db [:profile/profile :images] images)}))
|
||||
|
||||
(rf/reg-event-fx :profile.settings/mnemonic-was-shown
|
||||
(fn [_]
|
||||
|
||||
@@ -34,15 +34,28 @@
|
||||
[]
|
||||
(let [keycards (rf/sub [:keycard/registered-keycards])]
|
||||
[:<>
|
||||
[quo/divider-label
|
||||
{:counter? false
|
||||
:tight? true
|
||||
:blur? true}
|
||||
(i18n/label :t/registered-keycards)]
|
||||
[rn/view {:style style/registered-keycards-container}
|
||||
(for [keycard keycards]
|
||||
^{:key (:keycard-uid keycard)}
|
||||
[registered-keycard keycard])]]))
|
||||
[rn/view {:style {:flex 1}}
|
||||
[quo/divider-label
|
||||
{:counter? false
|
||||
:tight? true
|
||||
:blur? true}
|
||||
(i18n/label :t/registered-keycards)]
|
||||
[rn/view {:style style/registered-keycards-container}
|
||||
(for [keycard keycards]
|
||||
^{:key (:keycard-uid keycard)}
|
||||
[registered-keycard keycard])]]
|
||||
[quo/text
|
||||
{:size :heading-2
|
||||
:weight :semi-bold
|
||||
:style {:margin-left 20}}
|
||||
(i18n/label :t/scan-keycard-actions)]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/ready-to-scan)
|
||||
:button-one-props {:on-press #(rf/dispatch [:keycard/connect])}}]]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
[{:details (:optimism networks)
|
||||
:testnet-mode? testnet-mode?
|
||||
:testnet-label (i18n/label :t/sepolia-active)}
|
||||
{:details (:base networks)
|
||||
:testnet-mode? testnet-mode?
|
||||
:testnet-label (i18n/label :t/sepolia-active)}
|
||||
{:details (:arbitrum networks)
|
||||
:testnet-mode? testnet-mode?
|
||||
:testnet-label (i18n/label :t/sepolia-active)}])
|
||||
|
||||
@@ -303,7 +303,7 @@
|
||||
;; By doing it, we skip a blink while visiting the collectible detail page.
|
||||
[:dispatch-later
|
||||
{:ms 17
|
||||
:dispatch [:navigate-to :screen/wallet.collectible]}]]})))
|
||||
:dispatch [:open-modal :screen/wallet.collectible]}]]})))
|
||||
|
||||
(defn- keep-not-empty-value
|
||||
[old-value new-value]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im.contexts.wallet.collectible.utils
|
||||
(:require [status-im.config :as config]
|
||||
(:require [clojure.string :as string]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils.networks :as network-utils]
|
||||
[taoensso.timbre :as log]
|
||||
@@ -79,3 +80,12 @@
|
||||
acc)))
|
||||
{})
|
||||
vals))
|
||||
|
||||
(defn sort-collectibles-by-name
|
||||
[collectibles]
|
||||
(sort-by (fn [collectible]
|
||||
(let [name (-> collectible :collectible-data :name)
|
||||
normalized-name (some-> name
|
||||
string/lower-case)]
|
||||
[(if (seq normalized-name) 0 1) normalized-name]))
|
||||
collectibles))
|
||||
|
||||
@@ -44,3 +44,18 @@
|
||||
:token-id token-id
|
||||
:test-networks-enabled? true})
|
||||
"https://testnets.opensea.io/assets/optimism-sepolia/0xC/0xT"))))
|
||||
|
||||
(deftest sort-collectibles-by-name-test
|
||||
(testing "Sorts collectibles by name, moving nil or empty names to the end"
|
||||
(let [collectibles [{:collectible-data {:name "Alpha"}}
|
||||
{:collectible-data {:name nil}}
|
||||
{:collectible-data {:name "Beta"}}
|
||||
{:collectible-data {:name ""}}
|
||||
{:collectible-data {:name "Zeta"}}]
|
||||
sorted-collectibles (utils/sort-collectibles-by-name collectibles)
|
||||
expected [{:collectible-data {:name "Alpha"}}
|
||||
{:collectible-data {:name "Beta"}}
|
||||
{:collectible-data {:name "Zeta"}}
|
||||
{:collectible-data {:name nil}}
|
||||
{:collectible-data {:name ""}}]]
|
||||
(is (= sorted-collectibles expected)))))
|
||||
|
||||
@@ -10,15 +10,11 @@
|
||||
token-name :name
|
||||
total-balance :total-balance
|
||||
disabled? :bridge-disabled?
|
||||
fiat-value :fiat-value
|
||||
:as token}
|
||||
_ _
|
||||
{:keys [currency currency-symbol on-token-press preselected-token-symbol prices-per-token]}]
|
||||
(let [fiat-value (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance total-balance
|
||||
:token token
|
||||
:prices-per-token prices-per-token})
|
||||
crypto-formatted (utils/get-standard-crypto-format token total-balance prices-per-token)
|
||||
{:keys [currency-symbol on-token-press preselected-token-symbol prices-per-token]}]
|
||||
(let [crypto-formatted (utils/get-standard-crypto-format token total-balance prices-per-token)
|
||||
fiat-formatted (utils/fiat-formatted-for-ui currency-symbol fiat-value)]
|
||||
[quo/token-network
|
||||
{:token token-symbol
|
||||
@@ -38,13 +34,11 @@
|
||||
(let [filtered-tokens (rf/sub [:wallet/current-viewing-account-tokens-filtered
|
||||
{:query search-text
|
||||
:chain-ids chain-ids}])
|
||||
currency (rf/sub [:profile/currency])
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
prices-per-token (rf/sub [:wallet/prices-per-token])]
|
||||
[gesture/flat-list
|
||||
{:data filtered-tokens
|
||||
:render-data {:currency currency
|
||||
:currency-symbol currency-symbol
|
||||
:render-data {:currency-symbol currency-symbol
|
||||
:on-token-press on-token-press
|
||||
:preselected-token-symbol preselected-token-symbol
|
||||
:prices-per-token prices-per-token}
|
||||
|
||||
@@ -409,13 +409,15 @@
|
||||
|
||||
(defn sort-tokens
|
||||
[tokens]
|
||||
(let [priority #(get constants/token-sort-priority (:symbol %) ##Inf)]
|
||||
(sort-by (juxt (comp - :balance) priority) tokens)))
|
||||
(sort-by (comp - :balance) tokens))
|
||||
|
||||
(defn sort-tokens-by-fiat-value
|
||||
[tokens]
|
||||
(sort-by (comp - :fiat-value) tokens))
|
||||
|
||||
(defn sort-tokens-by-name
|
||||
[tokens]
|
||||
(let [priority #(get constants/token-sort-priority (:symbol %) ##Inf)]
|
||||
(sort-by (juxt :symbol priority) tokens)))
|
||||
(sort-by :symbol tokens))
|
||||
|
||||
(defn token-with-balance
|
||||
([token networks]
|
||||
|
||||
@@ -37,6 +37,9 @@
|
||||
constants/optimism-mainnet-chain-id
|
||||
config/optimism-mainnet-tx-details-base-link
|
||||
|
||||
constants/base-mainnet-chain-id
|
||||
config/base-mainnet-tx-details-base-link
|
||||
|
||||
constants/ethereum-sepolia-chain-id
|
||||
config/mainnet-sepolia-tx-details-base-link
|
||||
|
||||
@@ -46,6 +49,9 @@
|
||||
constants/optimism-sepolia-chain-id
|
||||
config/optimism-sepolia-tx-details-base-link
|
||||
|
||||
constants/base-sepolia-chain-id
|
||||
config/base-sepolia-tx-details-base-link
|
||||
|
||||
config/mainnet-tx-details-base-link))
|
||||
|
||||
(defn get-link-to-tx-details
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
constants/optimism-mainnet-chain-id constants/optimism-network-name
|
||||
constants/optimism-sepolia-chain-id constants/optimism-network-name
|
||||
constants/arbitrum-mainnet-chain-id constants/arbitrum-network-name
|
||||
constants/arbitrum-sepolia-chain-id constants/arbitrum-network-name})
|
||||
constants/arbitrum-sepolia-chain-id constants/arbitrum-network-name
|
||||
constants/base-mainnet-chain-id constants/base-network-name
|
||||
constants/base-sepolia-chain-id constants/base-network-name})
|
||||
|
||||
(defn- get-chain-id
|
||||
[{:keys [mainnet-chain-id sepolia-chain-id testnet-enabled?]}]
|
||||
@@ -46,6 +48,12 @@
|
||||
(get-chain-id
|
||||
{:mainnet-chain-id constants/arbitrum-mainnet-chain-id
|
||||
:sepolia-chain-id constants/arbitrum-sepolia-chain-id
|
||||
:testnet-enabled? testnet-enabled?})
|
||||
|
||||
#{constants/base-network-name (keyword constants/base-short-name)}
|
||||
(get-chain-id
|
||||
{:mainnet-chain-id constants/base-mainnet-chain-id
|
||||
:sepolia-chain-id constants/base-sepolia-chain-id
|
||||
:testnet-enabled? testnet-enabled?}))))
|
||||
|
||||
(defn network-list
|
||||
@@ -76,12 +84,14 @@
|
||||
{constants/mainnet-network-name constants/mainnet-short-name
|
||||
constants/optimism-network-name constants/optimism-short-name
|
||||
constants/arbitrum-network-name constants/arbitrum-short-name
|
||||
constants/ethereum-network-name constants/ethereum-short-name})
|
||||
constants/ethereum-network-name constants/ethereum-short-name
|
||||
constants/base-network-name constants/base-short-name})
|
||||
|
||||
(def short-name->network
|
||||
{constants/mainnet-short-name constants/mainnet-network-name
|
||||
constants/optimism-short-name constants/optimism-network-name
|
||||
constants/arbitrum-short-name constants/arbitrum-network-name})
|
||||
constants/arbitrum-short-name constants/arbitrum-network-name
|
||||
constants/base-short-name constants/base-network-name})
|
||||
|
||||
(defn short-names->network-preference-prefix
|
||||
[short-names]
|
||||
@@ -152,6 +162,15 @@
|
||||
:view-on-block-explorer-label :t/view-on-oeth
|
||||
:link-to-block-explorer-label :t/share-link-to-oeth})
|
||||
|
||||
(def base-network-details
|
||||
{:source (resources/get-network constants/base-network-name)
|
||||
:short-name constants/base-short-name
|
||||
:full-name constants/base-full-name
|
||||
:network-name constants/base-network-name
|
||||
:abbreviated-name constants/base-abbreviated-name
|
||||
:view-on-block-explorer-label :t/view-on-base
|
||||
:link-to-block-explorer-label :t/share-link-to-base})
|
||||
|
||||
(defn get-network-details
|
||||
[chain-id]
|
||||
(as-> chain-id $
|
||||
@@ -165,6 +184,9 @@
|
||||
#{constants/optimism-mainnet-chain-id constants/optimism-sepolia-chain-id}
|
||||
optimism-network-details
|
||||
|
||||
#{constants/base-mainnet-chain-id constants/base-sepolia-chain-id}
|
||||
base-network-details
|
||||
|
||||
nil)
|
||||
(when $
|
||||
(assoc $ :chain-id chain-id))))
|
||||
|
||||
@@ -345,3 +345,33 @@
|
||||
expected []]
|
||||
(is (= (utils/get-accounts-with-token-balance accounts token)
|
||||
expected)))))
|
||||
|
||||
(deftest sort-tokens-test
|
||||
(testing "Sort tokens by balance in descending order"
|
||||
(let [tokens [{:symbol "BTC" :balance 2}
|
||||
{:symbol "ETH" :balance 5}
|
||||
{:symbol "DAI" :balance 10}]
|
||||
expected [{:symbol "DAI" :balance 10}
|
||||
{:symbol "ETH" :balance 5}
|
||||
{:symbol "BTC" :balance 2}]]
|
||||
(is (= (utils/sort-tokens tokens) expected)))))
|
||||
|
||||
(deftest sort-tokens-by-fiat-value-test
|
||||
(testing "Sort tokens by fiat value in descending order"
|
||||
(let [tokens [{:symbol "BTC" :fiat-value 50000}
|
||||
{:symbol "ETH" :fiat-value 15000}
|
||||
{:symbol "DAI" :fiat-value 1000}]
|
||||
expected [{:symbol "BTC" :fiat-value 50000}
|
||||
{:symbol "ETH" :fiat-value 15000}
|
||||
{:symbol "DAI" :fiat-value 1000}]]
|
||||
(is (= (utils/sort-tokens-by-fiat-value tokens) expected)))))
|
||||
|
||||
(deftest sort-tokens-by-name-test
|
||||
(testing "Sort tokens by symbol in ascending order"
|
||||
(let [tokens [{:symbol "ETH"}
|
||||
{:symbol "DAI"}
|
||||
{:symbol "BTC"}]
|
||||
expected [{:symbol "BTC"}
|
||||
{:symbol "DAI"}
|
||||
{:symbol "ETH"}]]
|
||||
(is (= (utils/sort-tokens-by-name tokens) expected)))))
|
||||
|
||||
@@ -279,7 +279,8 @@
|
||||
:to (:to-chain new-path)
|
||||
:approval-amount-required (:approval-amount-required new-path)
|
||||
;; :cost () ;; tbd not used on desktop
|
||||
:gas-amount (:tx-gas-amount new-path)}))
|
||||
:gas-amount (:tx-gas-amount new-path)
|
||||
:router-input-params-uuid (:router-input-params-uuid new-path)}))
|
||||
|
||||
(defn tokens-never-loaded?
|
||||
[db]
|
||||
|
||||
@@ -120,6 +120,9 @@
|
||||
(rf/reg-fx
|
||||
:effects.wallet/sign-transaction-hashes
|
||||
(fn [{:keys [hashes address password on-success on-error]}]
|
||||
(tap> {:in :effects.wallet/sign-transaction-hashes
|
||||
:hashes hashes
|
||||
:password password})
|
||||
(-> (sign-transaction-hashes hashes address password)
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error))))
|
||||
|
||||
@@ -41,18 +41,18 @@
|
||||
(rf/reg-event-fx :wallet/navigate-to-account
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc-in db [:wallet :current-viewing-account-address] address)
|
||||
:fx [[:dispatch [:navigate-to :screen/wallet.accounts address]]]}))
|
||||
:fx [[:dispatch [:navigate-to :screen/wallet.accounts]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/navigate-to-account-within-stack
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc-in db [:wallet :current-viewing-account-address] address)
|
||||
:fx [[:dispatch [:navigate-to-within-stack [:screen/wallet.accounts :shell-stack] address]]]}))
|
||||
:fx [[:dispatch [:navigate-to-within-stack [:screen/wallet.accounts :shell-stack]]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/navigate-to-new-account
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc-in db [:wallet :current-viewing-account-address] address)
|
||||
:fx [[:dispatch [:hide-bottom-sheet]]
|
||||
[:dispatch [:navigate-to :screen/wallet.accounts address]]
|
||||
[:dispatch [:navigate-to :screen/wallet.accounts]]
|
||||
[:dispatch [:wallet/show-account-created-toast address]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/select-account-tab
|
||||
@@ -762,6 +762,8 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet/sign-transactions-signal-received
|
||||
(fn [{:keys [db]} [{send-details :sendDetails :as data}]]
|
||||
(tap> {:in :wallet/sign-transactions-signal-received
|
||||
:data data})
|
||||
(let [type (if (or (= (:fromToken send-details)
|
||||
(:toToken send-details))
|
||||
(string/blank? (:toToken send-details)))
|
||||
@@ -781,6 +783,7 @@
|
||||
(fn [{:keys [db]}
|
||||
[{sent-transactions :sentTransactions
|
||||
send-details :sendDetails}]]
|
||||
(tap> {:in :wallet/transactions-sent-signal-received})
|
||||
(let [swap? (get-in db [:wallet :ui :swap])]
|
||||
{:fx [[:dispatch
|
||||
(if-let [error-response (:errorResponse send-details)]
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.collectible.utils :as collectible.utils]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[status-im.contexts.wallet.common.utils.networks :as network-utils]
|
||||
[status-im.contexts.wallet.data-store :as data-store]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
@@ -12,7 +13,8 @@
|
||||
[utils.money :as utils.money]
|
||||
[utils.number]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
[utils.security.core :as security]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.typed-data :as typed-data]))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-send-data
|
||||
(fn [{:keys [db]}]
|
||||
@@ -386,7 +388,7 @@
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :amount] amount)
|
||||
(update-in [:wallet :ui :send] dissoc :transaction-for-signing))
|
||||
:fx [[:dispatch [:wallet/build-transactions-from-route {:request-uuid last-request-uuid}]]
|
||||
:fx [#_[:dispatch [:wallet/build-transactions-from-route {:request-uuid last-request-uuid}]]
|
||||
[:dispatch
|
||||
[:wallet/wizard-navigate-forward
|
||||
{:current-screen stack-id
|
||||
@@ -633,6 +635,7 @@
|
||||
(rf/reg-event-fx :wallet/clean-up-transaction-flow
|
||||
(fn [_]
|
||||
{:fx [[:dispatch [:dismiss-modal :screen/wallet.transaction-confirmation]]
|
||||
[:dispatch [:dismiss-modal :screen/wallet.collectible]]
|
||||
[:dispatch [:wallet/clean-scanned-address]]
|
||||
[:dispatch [:wallet/clean-local-suggestions]]
|
||||
[:dispatch [:wallet/clean-send-address]]
|
||||
@@ -650,6 +653,8 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet/build-transactions-from-route
|
||||
(fn [_ [{:keys [request-uuid slippage] :or {slippage constants/default-slippage}}]]
|
||||
(tap> {:in :wallet/build-transactions-from-route
|
||||
:request-uuid request-uuid})
|
||||
{:json-rpc/call [{:method "wallet_buildTransactionsFromRoute"
|
||||
:params [{:uuid request-uuid
|
||||
:slippagePercentage slippage}]
|
||||
@@ -665,6 +670,9 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet/prepare-signatures-for-transactions
|
||||
(fn [{:keys [db]} [type sha3-pwd]]
|
||||
(tap> {:in :wallet/prepare-signatures-for-transactions
|
||||
:type type
|
||||
:sha3-pwd sha3-pwd})
|
||||
(let [{:keys [hashes address signOnKeycard]} (get-in db
|
||||
[:wallet :ui type :transaction-for-signing
|
||||
:signingDetails])
|
||||
@@ -701,6 +709,9 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet/send-router-transactions-with-signatures
|
||||
(fn [{:keys [db]} [type signatures]]
|
||||
(tap> {:in :wallet/send-router-transactions-with-signatures
|
||||
:type type
|
||||
:signatures signatures})
|
||||
(let [transaction-for-signing (get-in db [:wallet :ui type :transaction-for-signing])
|
||||
signatures-map (reduce (fn [acc {:keys [message signature]}]
|
||||
(assoc acc
|
||||
@@ -805,3 +816,64 @@
|
||||
:always (update-in [:wallet :ui :send] dissoc :amount :route)
|
||||
(not keep-tx-data?) (update-in [:wallet :ui :send] dissoc :tx-type))
|
||||
:fx [[:dispatch [:navigate-back]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/init-tx-settings
|
||||
(fn [{db :db}]
|
||||
{:db (assoc-in db
|
||||
[:wallet :ui :send :tx-settings]
|
||||
{:max-base-fee {:low 5
|
||||
:current 8.2
|
||||
:high 9}
|
||||
:priority-fee {:low 0.6
|
||||
:high 5.1
|
||||
:current 1.1}
|
||||
:max-gas-amount {:low 30000
|
||||
:current 31000}
|
||||
:nonce {:last-transaction 21
|
||||
:current 22}})}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/set-max-base-fee
|
||||
(fn [{db :db} [value]]
|
||||
{:db (assoc-in db [:wallet :ui :send :tx-settings :max-base-fee :current] value)}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/set-priority-fee
|
||||
(fn [{db :db} [value]]
|
||||
{:db (assoc-in db [:wallet :ui :send :tx-settings :priority-fee :current] value)}))
|
||||
(rf/reg-event-fx
|
||||
|
||||
:wallet/set-max-gas-amount
|
||||
(fn [{db :db} [value]]
|
||||
{:db (assoc-in db [:wallet :ui :send :tx-settings :max-gas-amount :current] value)}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/set-nonce
|
||||
(fn [{db :db} [value]]
|
||||
{:db (assoc-in db [:wallet :ui :send :tx-settings :nonce :current] value)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/quick-transaction-settings-confirmed
|
||||
(fn [_cofx [path-tx-identity fee-mode]]
|
||||
(let [params [path-tx-identity fee-mode]]
|
||||
{:json-rpc/call [{:method "wallet_setFeeMode"
|
||||
:params params
|
||||
:on-error (fn [error]
|
||||
(log/error "failed to get suggested routes (async)"
|
||||
{:event :wallet/start-get-suggested-routes
|
||||
:error (:message error)
|
||||
:params params}))}]})))
|
||||
|
||||
|
||||
#_(rf/reg-event-fx :wallet/quick-transaction-settings-confirmed
|
||||
(fn [_cofx [path-tx-identity fee-mode]]
|
||||
(let [params [path-tx-identity fee-mode]]
|
||||
{:json-rpc/call [{:method "wallet_setCustomTxDetails"
|
||||
:params params
|
||||
:on-error (fn [error]
|
||||
(tap> {:in :wallet/quick-transaction-settings-confirmed
|
||||
:error error})
|
||||
(log/error "failed to get suggested routes (async)"
|
||||
{:event :wallet/start-get-suggested-routes
|
||||
:error (:message error)
|
||||
:params params}))}]})))
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||
[status-im.common.standard-authentication.core :as standard-auth]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.transaction-confirmation.style :as style]
|
||||
[status-im.contexts.wallet.send.transaction-settings.view :as transaction-settings]
|
||||
@@ -167,11 +168,19 @@
|
||||
:title title
|
||||
:subtitle subtitle}])
|
||||
|
||||
(defn quick-transaction-settings-confirmed
|
||||
[path-identity setting]
|
||||
(let [gas-rate (case setting
|
||||
:normal constants/gas-rate-low
|
||||
:fast constants/gas-rate-medium
|
||||
:urgent constants/gas-rate-high
|
||||
constants/gas-rate-low)]
|
||||
(rf/dispatch [:wallet/quick-transaction-settings-confirmed path-identity gas-rate])))
|
||||
|
||||
(defn- transaction-details
|
||||
[{:keys [estimated-time-min max-fees to-network route
|
||||
transaction-type]}]
|
||||
(let [route-loaded? (and route (seq route))
|
||||
loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
[{:keys [estimated-time-min max-fees to-network
|
||||
transaction-type path-identity route-loaded?]}]
|
||||
(let [loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
amount (rf/sub [:wallet/send-total-amount-formatted])]
|
||||
[rn/view
|
||||
{:style (style/details-container
|
||||
@@ -190,9 +199,14 @@
|
||||
:inner-style {:opacity 1}
|
||||
:accessibility-label :advanced-button
|
||||
:container-style {:margin-right 8}
|
||||
:on-press #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content transaction-settings/settings-sheet}])}
|
||||
:on-press (fn []
|
||||
(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[transaction-settings/settings-sheet
|
||||
#(quick-transaction-settings-confirmed
|
||||
path-identity
|
||||
%)])}]))}
|
||||
:i/advanced])
|
||||
[data-item
|
||||
{:title (i18n/label :t/est-time)
|
||||
@@ -217,6 +231,7 @@
|
||||
{:keys [token-display-name collectible amount
|
||||
route
|
||||
to-address bridge-to-chain-id type
|
||||
last-request-uuid
|
||||
recipient]} send-transaction-data
|
||||
collectible? (some? collectible)
|
||||
image-url (when collectible
|
||||
@@ -248,9 +263,7 @@
|
||||
account))}
|
||||
user-props {:full-name to-address
|
||||
:address (utils/get-shortened-address
|
||||
to-address)}
|
||||
sign-on-keycard? (get-in transaction-for-signing
|
||||
[:signingDetails :signOnKeycard])]
|
||||
to-address)}]
|
||||
(hot-reload/use-safe-unmount #(rf/dispatch [:wallet/clean-route-data-for-collectible-tx]))
|
||||
;; In token send flow we already have transaction built when
|
||||
;; we reach confirmation screen. But in send collectible flow
|
||||
@@ -263,6 +276,10 @@
|
||||
first-route)
|
||||
(rf/dispatch [:wallet/build-transaction-for-collectible-route])))
|
||||
[first-route])
|
||||
(rn/use-mount
|
||||
(fn []
|
||||
(when (ff/enabled? ::ff/wallet.transaction-params)
|
||||
(rf/dispatch [:wallet/init-tx-settings]))))
|
||||
[rn/view {:style {:flex 1}}
|
||||
[floating-button-page/view
|
||||
{:footer-container-padding 0
|
||||
@@ -279,7 +296,9 @@
|
||||
:to-network bridge-to-network
|
||||
:theme theme
|
||||
:route route
|
||||
:transaction-type transaction-type}]
|
||||
:transaction-type transaction-type
|
||||
:path-identity (send-utils/path-identity first-route)
|
||||
:route-loaded? (and route (seq route))}]
|
||||
(when (and (not loading-suggested-routes?) route (seq route))
|
||||
[standard-auth/slide-button
|
||||
{:size :size-48
|
||||
@@ -287,10 +306,11 @@
|
||||
(i18n/label :t/slide-to-bridge)
|
||||
(i18n/label :t/slide-to-send))
|
||||
:container-style {:z-index 2}
|
||||
:disabled? (not transaction-for-signing)
|
||||
;; :disabled? (not transaction-for-signing)
|
||||
:customization-color account-color
|
||||
:auth-button-label (i18n/label :t/confirm)
|
||||
:on-complete (when sign-on-keycard?
|
||||
:on-complete (when (get-in transaction-for-signing
|
||||
[:signingDetails :signOnKeycard])
|
||||
#(rf/dispatch
|
||||
[:wallet/prepare-signatures-for-transactions
|
||||
:send
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
(ns status-im.contexts.wallet.send.transaction-settings.gas-amount.view
|
||||
(:require
|
||||
[quo.theme]
|
||||
[status-im.contexts.wallet.send.transaction-settings.view :as transaction-settings]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn gas-amount-hint-text
|
||||
[{:keys [current]} lower-limit-exceeded? _upper-limit-exceeded?]
|
||||
(cond
|
||||
lower-limit-exceeded? (i18n/label :t/gas-amount-lower {:current current})
|
||||
:else (i18n/label :t/current-units {:current current})))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [suggested-values (rf/sub [:wallet/tx-settings-max-gas-amount])
|
||||
hint-text (partial gas-amount-hint-text suggested-values)]
|
||||
[transaction-settings/custom-setting-screen
|
||||
{:screen-title (i18n/label :t/max-gas-amount)
|
||||
:token-symbol :units
|
||||
:hint-text-fn hint-text
|
||||
:suggested-values suggested-values
|
||||
:info-title (i18n/label :t/gas-amount)
|
||||
:info-content (i18n/label :t/about-gas-amount)
|
||||
:on-save (fn [new-val]
|
||||
(rf/dispatch [:wallet/set-max-gas-amount new-val])
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content transaction-settings/custom-settings-sheet}]))
|
||||
:with-decimals? false}]))
|
||||
@@ -0,0 +1,30 @@
|
||||
(ns status-im.contexts.wallet.send.transaction-settings.max-fee.view
|
||||
(:require
|
||||
[quo.theme]
|
||||
[status-im.contexts.wallet.send.transaction-settings.view :as transaction-settings]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn max-base-fee-hint-text
|
||||
[current lower-limit-exceeded? upper-limit-exceeded?]
|
||||
(cond
|
||||
upper-limit-exceeded? (i18n/label :t/max-base-fee-higher {:current current})
|
||||
lower-limit-exceeded? (i18n/label :t/max-base-fee-lower {:current current})
|
||||
:else (i18n/label :t/fee-current-gwei {:current current})))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [suggested-values (rf/sub [:wallet/tx-settings-max-base-fee])
|
||||
hint-text (partial max-base-fee-hint-text (:current suggested-values))]
|
||||
[transaction-settings/custom-setting-screen
|
||||
{:screen-title (i18n/label :t/max-base-fee)
|
||||
:token-sybmol :gwei
|
||||
:hint-text-fn hint-text
|
||||
:suggested-values suggested-values
|
||||
:info-title (i18n/label :t/max-base-fee)
|
||||
:info-content (i18n/label :t/about-max-base-fee)
|
||||
:on-save (fn [new-val]
|
||||
(rf/dispatch [:wallet/set-max-base-fee new-val])
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content transaction-settings/custom-settings-sheet}]))}]))
|
||||
@@ -0,0 +1,78 @@
|
||||
(ns status-im.contexts.wallet.send.transaction-settings.nonce.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.controlled-input.utils :as controlled-input]
|
||||
[status-im.contexts.wallet.send.transaction-settings.view :as transaction-settings]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [{:keys [last-transaction current]} (rf/sub [:wallet/tx-settings-nonce])
|
||||
suggested-nonce (inc last-transaction)
|
||||
[input-state set-input-state] (rn/use-state (controlled-input/set-value-numeric
|
||||
controlled-input/init-state
|
||||
current))
|
||||
input-value (controlled-input/input-value input-state)
|
||||
warning? (> (controlled-input/value-numeric input-state)
|
||||
suggested-nonce)]
|
||||
[rn/view
|
||||
{:style {:flex 1}}
|
||||
[quo/page-nav
|
||||
{:type :title
|
||||
:title (i18n/label :t/nonce)
|
||||
:text-align :center
|
||||
:right-side [{:icon-name :i/info
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [transaction-settings/info-sheet
|
||||
(i18n/label :t/nonce)
|
||||
(i18n/label :t/about-nonce)])}])}]
|
||||
:icon-name :i/arrow-left
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content transaction-settings/custom-settings-sheet}]))}]
|
||||
[rn/view
|
||||
{:style {:padding-horizontal 20
|
||||
:gap 8}}
|
||||
[quo/input
|
||||
{:type :text
|
||||
:label (i18n/label :t/type-nonce)
|
||||
:label-right (i18n/label :t/last-transaction-is {:number last-transaction})
|
||||
:editable false
|
||||
:default-value input-value
|
||||
:clearable? true
|
||||
:error? warning?
|
||||
:on-clear (fn []
|
||||
(set-input-state controlled-input/delete-all))}]
|
||||
(when warning?
|
||||
[quo/text
|
||||
{:style {:color colors/warning-50}
|
||||
:weight :regular
|
||||
:size :paragraph-2}
|
||||
(i18n/label :t/nonce-higher {:number suggested-nonce})])]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/save-changes)
|
||||
:button-one-props {:disabled? (controlled-input/empty-value? input-state)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:wallet/set-nonce
|
||||
(controlled-input/value-numeric input-state)])
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content
|
||||
transaction-settings/custom-settings-sheet}]))}}]
|
||||
[quo/numbered-keyboard
|
||||
{:container-style {:padding-bottom (safe-area/get-bottom)}
|
||||
:left-action :none
|
||||
:delete-key? true
|
||||
:on-press (fn [c]
|
||||
(set-input-state #(controlled-input/add-character % c)))
|
||||
:on-delete (fn []
|
||||
(set-input-state controlled-input/delete-last))
|
||||
:on-long-press-delete (fn []
|
||||
(set-input-state controlled-input/delete-all))}]]))
|
||||
@@ -0,0 +1,30 @@
|
||||
(ns status-im.contexts.wallet.send.transaction-settings.priority-fee.view
|
||||
(:require
|
||||
[quo.theme]
|
||||
[status-im.contexts.wallet.send.transaction-settings.view :as transaction-settings]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn priority-fee-hint-text
|
||||
[{:keys [current low high]} lower-limit-exceeded? upper-limit-exceeded?]
|
||||
(cond
|
||||
upper-limit-exceeded? (i18n/label :t/priority-fee-higher {:low low :high high})
|
||||
lower-limit-exceeded? (i18n/label :t/priority-fee-lower {:low low :high high})
|
||||
:else (i18n/label :t/fee-current-gwei {:current current})))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [suggested-values (rf/sub [:wallet/tx-settings-priority-fee])
|
||||
hint-text (partial priority-fee-hint-text suggested-values)]
|
||||
[transaction-settings/custom-setting-screen
|
||||
{:screen-title (i18n/label :t/priority-fee)
|
||||
:token-sybmol :gwei
|
||||
:hint-text-fn hint-text
|
||||
:suggested-values suggested-values
|
||||
:info-title (i18n/label :t/priority-fee)
|
||||
:info-content (i18n/label :t/about-priority-fee)
|
||||
:on-save (fn [new-val]
|
||||
(rf/dispatch [:wallet/set-priority-fee new-val])
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content transaction-settings/custom-settings-sheet}]))}]))
|
||||
@@ -2,63 +2,78 @@
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.controlled-input.utils :as controlled-input]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
|
||||
(defn custom-settings-sheet
|
||||
[_]
|
||||
[rn/view
|
||||
[quo/drawer-top
|
||||
{:title "Custom"}]
|
||||
[quo/category
|
||||
{:list-type :settings
|
||||
:data [{:title "Max base fee"
|
||||
:description-props {:text "8.2 GWEI - €1.45"}
|
||||
:image :none
|
||||
:description :text
|
||||
:action :arrow
|
||||
:on-press #()
|
||||
:label :text
|
||||
:preview-size :size-32}
|
||||
{:title "Priority fee"
|
||||
:description-props {:text "0.06 GWEI - €0.03"}
|
||||
:image :none
|
||||
:description :text
|
||||
:action :arrow
|
||||
:on-press #()
|
||||
:label :text
|
||||
:preview-size :size-32}
|
||||
{:title "Gas amount"
|
||||
:description-props {:text "31,500 UNITS"}
|
||||
:image :none
|
||||
:description :text
|
||||
:action :arrow
|
||||
:on-press #()
|
||||
:label :text
|
||||
:preview-size :size-32}
|
||||
{:title "Nonce"
|
||||
:description-props {:text "22"}
|
||||
:image :none
|
||||
:description :text
|
||||
:action :arrow
|
||||
:on-press #()
|
||||
:label :text
|
||||
:preview-size :size-32}]}]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-props {:on-press #(rf/dispatch [:hide-bottom-sheet])}
|
||||
:button-one-label (i18n/label :t/confirm)}]])
|
||||
(let [max-base-fee (:current (rf/sub [:wallet/tx-settings-max-base-fee]))
|
||||
priority-fee (:current (rf/sub [:wallet/tx-settings-priority-fee]))
|
||||
max-gas-amount (:current (rf/sub [:wallet/tx-settings-max-gas-amount]))
|
||||
nonce (:current (rf/sub [:wallet/tx-settings-nonce]))]
|
||||
[rn/view
|
||||
[quo/drawer-top
|
||||
{:title (i18n/label :t/custom)}]
|
||||
[quo/category
|
||||
{:list-type :settings
|
||||
:data [{:title (i18n/label :t/max-base-fee)
|
||||
:description-props {:text (str max-base-fee " GWEI")}
|
||||
:image :none
|
||||
:description :text
|
||||
:action :arrow
|
||||
:on-press #(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/wallet.tx-settings-max-fee
|
||||
:screen/wallet.transaction-confirmation]])
|
||||
:label :text
|
||||
:preview-size :size-32}
|
||||
{:title (i18n/label :t/priority-fee)
|
||||
:description-props {:text (str priority-fee " GWEI")}
|
||||
:image :none
|
||||
:description :text
|
||||
:action :arrow
|
||||
:on-press #(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/wallet.tx-settings-priority-fee
|
||||
:screen/wallet.transaction-confirmation]])
|
||||
:label :text
|
||||
:preview-size :size-32}
|
||||
{:title (i18n/label :t/max-gas-amount)
|
||||
:description-props {:text (str max-gas-amount " UNITS")}
|
||||
:image :none
|
||||
:description :text
|
||||
:action :arrow
|
||||
:on-press #(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/wallet.tx-settings-gas-amount
|
||||
:screen/wallet.transaction-confirmation]])
|
||||
:label :text
|
||||
:preview-size :size-32}
|
||||
{:title (i18n/label :t/nonce)
|
||||
:description-props {:text nonce}
|
||||
:image :none
|
||||
:description :text
|
||||
:action :arrow
|
||||
:on-press #(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/wallet.tx-settings-nonce
|
||||
:screen/wallet.transaction-confirmation]])
|
||||
:label :text
|
||||
:preview-size :size-32}]}]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-props {:on-press #(rf/dispatch [:hide-bottom-sheet])}
|
||||
:button-one-label (i18n/label :t/confirm)}]]))
|
||||
|
||||
(defn settings-sheet
|
||||
[_]
|
||||
[on-quick-settings-confirmed]
|
||||
(let [[selected-id set-selected-id] (rn/use-state :normal)]
|
||||
[rn/view
|
||||
[quo/drawer-top
|
||||
{:title "Transaction settings"}]
|
||||
{:title (i18n/label :t/transaction-settings)}]
|
||||
[quo/category
|
||||
{:list-type :settings
|
||||
:data [{:title "Normal ~60s"
|
||||
:data [{:title (str (i18n/label :t/normal) "~60s")
|
||||
:image-props "🍿"
|
||||
:description-props {:text "€1.45"}
|
||||
:image :emoji
|
||||
@@ -69,7 +84,7 @@
|
||||
:on-press #(set-selected-id :normal)
|
||||
:label :text
|
||||
:preview-size :size-32}
|
||||
{:title "Fast ~40s"
|
||||
{:title (str (i18n/label :t/fast) "~40s")
|
||||
:image-props "🚗"
|
||||
:description-props {:text "€1.65"}
|
||||
:image :emoji
|
||||
@@ -80,7 +95,7 @@
|
||||
:on-press #(set-selected-id :fast)
|
||||
:label :text
|
||||
:preview-size :size-32}
|
||||
{:title "Urgent ~15s"
|
||||
{:title (str (i18n/label :t/urgent) "~15s")
|
||||
:image-props "🚀"
|
||||
:description-props {:text "€1.85"}
|
||||
:image :emoji
|
||||
@@ -91,7 +106,7 @@
|
||||
:on-press #(set-selected-id :urgent)
|
||||
:label :text
|
||||
:preview-size :size-32}
|
||||
{:title "Custom"
|
||||
{:title (i18n/label :t/custom)
|
||||
:image-props :i/edit
|
||||
:description-props {:text "Set your own fees and nonce"}
|
||||
:image :icon
|
||||
@@ -104,5 +119,95 @@
|
||||
:preview-size :size-32}]}]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-props {:on-press #(rf/dispatch [:hide-bottom-sheet])}
|
||||
:button-one-props {:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(when on-quick-settings-confirmed
|
||||
(on-quick-settings-confirmed selected-id))
|
||||
)}
|
||||
:button-one-label (i18n/label :t/confirm)}]]))
|
||||
|
||||
(defn- hint
|
||||
[{:keys [error? text]}]
|
||||
[quo/network-tags
|
||||
{:title text
|
||||
:status (when error? :error)}])
|
||||
|
||||
(defn info-sheet
|
||||
[info-title info-content]
|
||||
[quo/documentation-drawers
|
||||
{:title info-title
|
||||
:shell? true}
|
||||
[rn/view
|
||||
[quo/text {:size :paragraph-2} info-content]
|
||||
[quo/button
|
||||
{:type :outline
|
||||
:size 24
|
||||
:icon-right :i/info
|
||||
:container-style {:padding-top 21
|
||||
:padding-bottom (if platform/ios? 14 24)
|
||||
:align-self :flex-start
|
||||
:justify-content :center}
|
||||
:on-press #()}
|
||||
(i18n/label :t/read-more)]]])
|
||||
|
||||
(defn custom-setting-screen
|
||||
[{:keys [screen-title token-symbol hint-text-fn suggested-values info-title info-content on-save
|
||||
with-decimals?]
|
||||
:or {with-decimals? true}}]
|
||||
(let [[input-state set-input-state] (rn/use-state (controlled-input/set-value-numeric
|
||||
controlled-input/init-state
|
||||
(:current suggested-values)))
|
||||
input-value (controlled-input/input-value input-state)
|
||||
out-of-limits? (controlled-input/input-error input-state)
|
||||
valid-input? (not (or (controlled-input/empty-value? input-state)
|
||||
out-of-limits?))]
|
||||
(rn/use-mount
|
||||
(fn []
|
||||
|
||||
(set-input-state (fn [state]
|
||||
(-> state
|
||||
(controlled-input/set-upper-limit (:high suggested-values))
|
||||
(controlled-input/set-lower-limit (:low suggested-values)))))))
|
||||
[rn/view
|
||||
{:style {:flex 1}}
|
||||
[quo/page-nav
|
||||
{:type :title
|
||||
:title screen-title
|
||||
:text-align :center
|
||||
:right-side [{:icon-name :i/info
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [info-sheet info-title
|
||||
info-content])}])}]
|
||||
:icon-name :i/arrow-left
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content custom-settings-sheet}]))}]
|
||||
[quo/token-input
|
||||
{:token-symbol token-symbol
|
||||
:swappable? false
|
||||
:show-token-icon? false
|
||||
:value input-value
|
||||
:error? out-of-limits?
|
||||
:currency-symbol token-symbol
|
||||
:hint-component [hint
|
||||
{:error? out-of-limits?
|
||||
:text (hint-text-fn
|
||||
(controlled-input/lower-limit-exceeded? input-state)
|
||||
(controlled-input/upper-limit-exceeded? input-state))}]}]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/save-changes)
|
||||
:button-one-props {:disabled? (not valid-input?)
|
||||
:on-press #(on-save (controlled-input/value-numeric input-state))}}]
|
||||
[quo/numbered-keyboard
|
||||
{:container-style {:padding-bottom (safe-area/get-bottom)}
|
||||
:left-action (if with-decimals? :dot :none)
|
||||
:delete-key? true
|
||||
:on-press (fn [c]
|
||||
(set-input-state #(controlled-input/add-character % c)))
|
||||
:on-delete (fn []
|
||||
(set-input-state controlled-input/delete-last))
|
||||
:on-long-press-delete (fn []
|
||||
(set-input-state controlled-input/delete-all))}]]))
|
||||
|
||||
@@ -135,7 +135,8 @@
|
||||
(def ^:private network-priority-score
|
||||
{:ethereum 1
|
||||
:optimism 2
|
||||
:arbitrum 3})
|
||||
:arbitrum 3
|
||||
:base 4})
|
||||
|
||||
(defn reset-loading-network-amounts-to-zero
|
||||
[network-amounts]
|
||||
@@ -223,3 +224,10 @@
|
||||
{:r (subs signature 0 64)
|
||||
:s (subs signature 64 128)
|
||||
:v (subs signature 128 130)})
|
||||
|
||||
(defn path-identity
|
||||
[path]
|
||||
{:routerInputParamsUuid (:router-input-params-uuid path)
|
||||
:pathName (:bridge-name path)
|
||||
:chainID (get-in path [:to :chain-id])
|
||||
:isApprovalTx (:approval-required path)})
|
||||
|
||||
@@ -279,9 +279,7 @@
|
||||
(fn [{:keys [db]} [{:keys [sent-transactions swap-data approval-transaction?]}]]
|
||||
(let [wallet-transactions (get-in db [:wallet :transactions] {})
|
||||
transactions (utils/transactions->hash-to-transaction-map sent-transactions)
|
||||
transaction-ids (->> transactions
|
||||
vals
|
||||
(map :hash))
|
||||
transaction-ids (keys transactions)
|
||||
transaction-id (first transaction-ids)
|
||||
transaction-details (cond-> transactions
|
||||
:always (assoc-in [transaction-id :tx-type] :swap)
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
:peers-summary []
|
||||
:transport/message-envelopes {}
|
||||
:mailserver/mailservers (fleet/default-mailservers {})
|
||||
:mailserver/topics {}
|
||||
:mailserver/pending-requests 0
|
||||
:chat/cooldowns 0
|
||||
:chat/inputs {}
|
||||
:chat/cooldown-enabled? false
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
{:events [:navigate-to-within-stack]}
|
||||
[{:keys [db]} comp-id screen-params]
|
||||
{:db (all-screens-params db (first comp-id) screen-params)
|
||||
:fx [[:navigate-to-within-stack (conj comp-id (:theme db))]]})
|
||||
:fx [[:dispatch [:hide-bottom-sheet]]
|
||||
[:navigate-to-within-stack (conj comp-id (:theme db))]]})
|
||||
|
||||
(re-frame/reg-event-fx :open-modal
|
||||
(fn [{:keys [db]} [component screen-params]]
|
||||
|
||||
@@ -33,8 +33,10 @@
|
||||
[status-im.contexts.keycard.authorise.view :as keycard.authorise]
|
||||
[status-im.contexts.keycard.check.view :as keycard.check]
|
||||
[status-im.contexts.keycard.create.view :as keycard.create]
|
||||
[status-im.contexts.keycard.different-card.view :as keycard.different-card]
|
||||
[status-im.contexts.keycard.empty.view :as keycard.empty]
|
||||
[status-im.contexts.keycard.error.view :as keycard.error]
|
||||
[status-im.contexts.keycard.factory-reset.view :as keycard.factory-reset]
|
||||
[status-im.contexts.keycard.migrate.fail.view :as keycard.migrate.fail]
|
||||
[status-im.contexts.keycard.migrate.profile-keys.view :as keycard.migrate.profile-keys]
|
||||
[status-im.contexts.keycard.migrate.re-encrypting.view :as keycard.re-encrypting]
|
||||
@@ -137,6 +139,12 @@
|
||||
[status-im.contexts.wallet.send.send-amount.view :as wallet-send-input-amount]
|
||||
[status-im.contexts.wallet.send.transaction-confirmation.view :as wallet-transaction-confirmation]
|
||||
[status-im.contexts.wallet.send.transaction-progress.view :as wallet-transaction-progress]
|
||||
[status-im.contexts.wallet.send.transaction-settings.gas-amount.view :as
|
||||
wallet-tx-settings-gas-amount]
|
||||
[status-im.contexts.wallet.send.transaction-settings.max-fee.view :as wallet-tx-settings-max-fee]
|
||||
[status-im.contexts.wallet.send.transaction-settings.nonce.view :as wallet-tx-settings-nonce]
|
||||
[status-im.contexts.wallet.send.transaction-settings.priority-fee.view :as
|
||||
wallet-tx-settings-priority-fee]
|
||||
[status-im.contexts.wallet.swap.select-account.view :as wallet-swap-select-account]
|
||||
[status-im.contexts.wallet.swap.select-asset-to-pay.view :as wallet-swap-select-asset-to-pay]
|
||||
[status-im.contexts.wallet.swap.set-spending-cap.view :as wallet-swap-set-spending-cap]
|
||||
@@ -518,6 +526,7 @@
|
||||
|
||||
{:name :screen/wallet.collectible
|
||||
:metrics {:track? true}
|
||||
:options {:modalPresentationStyle :overCurrentContext}
|
||||
:component wallet-collectible/view}
|
||||
|
||||
{:name :screen/wallet.edit-account
|
||||
@@ -623,7 +632,31 @@
|
||||
:metrics {:track? true
|
||||
:alias-id :wallet-send.select-collectible-amount}
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-select-collectible-amount/view}])
|
||||
:component wallet-select-collectible-amount/view}
|
||||
|
||||
{:name :screen/wallet.tx-settings-max-fee
|
||||
:metrics {:track? true
|
||||
:alias-id :wallet-send.tx-settings-max-fee}
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-tx-settings-max-fee/view}
|
||||
|
||||
{:name :screen/wallet.tx-settings-priority-fee
|
||||
:metrics {:track? true
|
||||
:alias-id :wallet-send.tx-settings-priority-fee}
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-tx-settings-priority-fee/view}
|
||||
|
||||
{:name :screen/wallet.tx-settings-gas-amount
|
||||
:metrics {:track? true
|
||||
:alias-id :wallet-send.tx-settings-gas-amount}
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-tx-settings-gas-amount/view}
|
||||
|
||||
{:name :screen/wallet.tx-settings-nonce
|
||||
:metrics {:track? true
|
||||
:alias-id :wallet-send.tx-settings-nonce}
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-tx-settings-nonce/view}])
|
||||
|
||||
(def wallet-bridge-screens
|
||||
[{:name :screen/wallet.bridge-select-asset
|
||||
@@ -873,99 +906,135 @@
|
||||
(def keycard-screens
|
||||
[{:name :screen/keycard.check
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.check/view}
|
||||
|
||||
{:name :screen/keycard.empty
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.empty/view}
|
||||
|
||||
{:name :screen/keycard.empty-create
|
||||
:metrics {:track? true}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:options {:insets {:top? true :bottom? true}
|
||||
:modalPresentationStyle :fullScreen}
|
||||
:component keycard.empty/create}
|
||||
|
||||
{:name :screen/keycard.error
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.error/view}
|
||||
|
||||
{:name :screen/keycard.different-card
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.different-card/view}
|
||||
|
||||
{:name :screen/keycard.not-keycard
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.not-keycard/view}
|
||||
|
||||
{:name :screen/keycard.authorise
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.authorise/view}
|
||||
|
||||
{:name :screen/keycard.migrate
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.migrate/view}
|
||||
|
||||
{:name :screen/keycard.re-encrypting
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}
|
||||
:popGesture false
|
||||
:hardwareBackButton {:dismissModalOnPress false
|
||||
:popStackOnPress false}}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}
|
||||
:popGesture false
|
||||
:modalPresentationStyle :fullScreen
|
||||
:hardwareBackButton {:dismissModalOnPress false
|
||||
:popStackOnPress false}}
|
||||
:component keycard.re-encrypting/view}
|
||||
|
||||
{:name :screen/keycard.migrate.success
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}
|
||||
:popGesture false
|
||||
:hardwareBackButton {:dismissModalOnPress false
|
||||
:popStackOnPress false}}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}
|
||||
:popGesture false
|
||||
:modalPresentationStyle :fullScreen
|
||||
:hardwareBackButton {:dismissModalOnPress false
|
||||
:popStackOnPress false}}
|
||||
:component keycard.migrate.success/view}
|
||||
|
||||
{:name :screen/keycard.migrate.fail
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}
|
||||
:popGesture false
|
||||
:hardwareBackButton {:dismissModalOnPress false
|
||||
:popStackOnPress false}}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}
|
||||
:popGesture false
|
||||
:modalPresentationStyle :fullScreen
|
||||
:hardwareBackButton {:dismissModalOnPress false
|
||||
:popStackOnPress false}}
|
||||
:component keycard.migrate.fail/view}
|
||||
|
||||
{:name :screen/keycard.pin.create
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.pin.create/view}
|
||||
|
||||
{:name :screen/keycard.pin.enter
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.pin.enter/view}
|
||||
|
||||
{:name :screen/keycard.profile-keys
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.migrate.profile-keys/view}
|
||||
|
||||
{:name :screen/keycard.create-profile
|
||||
:metrics {:track? true}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:options {:insets {:top? true :bottom? true}
|
||||
:modalPresentationStyle :fullScreen}
|
||||
:component keycard.create/view}
|
||||
|
||||
{:name :screen/keycard.create.ready-to-add
|
||||
:metrics {:track? true}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component keycard.create/ready-to-add}])
|
||||
:options {:insets {:top? true :bottom? true}
|
||||
:modalPresentationStyle :fullScreen}
|
||||
:component keycard.create/ready-to-add}
|
||||
|
||||
{:name :screen/keycard.factory-reset.success
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.factory-reset/success-view}
|
||||
|
||||
{:name :screen/keycard.factory-reset.fail
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.factory-reset/failed-view}])
|
||||
|
||||
(defn screens
|
||||
[]
|
||||
|
||||
@@ -82,3 +82,9 @@
|
||||
:<- [:keycard]
|
||||
(fn [keycard]
|
||||
(get-in keycard [:application-info :initialized?])))
|
||||
|
||||
(rf/reg-sub
|
||||
:keycard/key-uid
|
||||
:<- [:keycard]
|
||||
(fn [keycard]
|
||||
(get-in keycard [:application-info :key-uid])))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.contexts.wallet.collectible.utils :as collectible-utils]
|
||||
[utils.collection]))
|
||||
|
||||
(defn- filter-collectibles-in-chains
|
||||
@@ -46,7 +47,10 @@
|
||||
:wallet/current-viewing-account-collectibles
|
||||
:<- [:wallet/current-viewing-account]
|
||||
(fn [current-account]
|
||||
(-> current-account :collectibles add-collectibles-preview-url)))
|
||||
(-> current-account
|
||||
:collectibles
|
||||
add-collectibles-preview-url
|
||||
collectible-utils/sort-collectibles-by-name)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet/current-viewing-account-collectibles-in-selected-networks
|
||||
@@ -71,7 +75,8 @@
|
||||
(apply interleave)
|
||||
(remove nil?)
|
||||
(utils.collection/distinct-by :id)
|
||||
(add-collectibles-preview-url)))))
|
||||
(add-collectibles-preview-url)
|
||||
(collectible-utils/sort-collectibles-by-name)))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet/owned-collectibles-list-in-selected-networks
|
||||
|
||||
@@ -204,3 +204,28 @@
|
||||
fiat-value)]
|
||||
{:crypto (str crypto-formatted " " (:symbol token))
|
||||
:fiat fiat-formatted})))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/tx-settings
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :tx-settings)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/tx-settings-max-base-fee
|
||||
:<- [:wallet/tx-settings]
|
||||
:-> :max-base-fee)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/tx-settings-priority-fee
|
||||
:<- [:wallet/tx-settings]
|
||||
:-> :priority-fee)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/tx-settings-max-gas-amount
|
||||
:<- [:wallet/tx-settings]
|
||||
:-> :max-gas-amount)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/tx-settings-nonce
|
||||
:<- [:wallet/tx-settings]
|
||||
:-> :nonce)
|
||||
|
||||
@@ -505,30 +505,38 @@
|
||||
:<- [:wallet/current-viewing-account-or-default]
|
||||
:<- [:wallet/network-details]
|
||||
:<- [:wallet/wallet-send]
|
||||
(fn [[account networks send-data] [_ {:keys [query chain-ids hide-token-fn]}]]
|
||||
:<- [:profile/currency]
|
||||
:<- [:wallet/prices-per-token]
|
||||
(fn [[account networks send-data currency price-per-token] [_ {:keys [query chain-ids hide-token-fn]}]]
|
||||
(let [tx-type (:tx-type send-data)
|
||||
tokens (->> (:tokens account)
|
||||
(map
|
||||
(fn [token]
|
||||
(assoc token
|
||||
:bridge-disabled? (and (= tx-type :tx/bridge)
|
||||
(send-utils/bridge-disabled? (:symbol
|
||||
token)))
|
||||
:networks (cond->>
|
||||
(network-utils/network-list-with-positive-balance
|
||||
token
|
||||
networks)
|
||||
chain-ids
|
||||
(filter #(some #{(:chain-id %)} chain-ids)))
|
||||
:supported-networks (network-utils/network-list token networks)
|
||||
:available-balance (utils/calculate-total-token-balance token)
|
||||
:total-balance (utils/calculate-total-token-balance
|
||||
token
|
||||
chain-ids))))
|
||||
(let [total-balance (utils/calculate-total-token-balance
|
||||
token
|
||||
chain-ids)]
|
||||
(assoc token
|
||||
:bridge-disabled? (and (= tx-type :tx/bridge)
|
||||
(send-utils/bridge-disabled? (:symbol
|
||||
token)))
|
||||
:networks (cond->>
|
||||
(network-utils/network-list-with-positive-balance
|
||||
token
|
||||
networks)
|
||||
chain-ids
|
||||
(filter #(some #{(:chain-id %)} chain-ids)))
|
||||
:supported-networks (network-utils/network-list token networks)
|
||||
:available-balance (utils/calculate-total-token-balance token)
|
||||
:total-balance total-balance
|
||||
:fiat-value (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance total-balance
|
||||
:token token
|
||||
:prices-per-token price-per-token})))))
|
||||
(filter (fn [{:keys [networks]}]
|
||||
(pos? (count networks))))
|
||||
(remove #(when hide-token-fn (hide-token-fn constants/swap-tokens-my %))))
|
||||
sorted-tokens (utils/sort-tokens tokens)]
|
||||
sorted-tokens (utils/sort-tokens-by-fiat-value tokens)]
|
||||
(if query
|
||||
(let [query-string (string/lower-case query)]
|
||||
(filter #(or (string/starts-with? (string/lower-case (:name %)) query-string)
|
||||
|
||||
@@ -840,7 +840,7 @@
|
||||
(swap! rf-db/app-db #(assoc % :wallet db/defaults))
|
||||
(is
|
||||
(match? (sort [constants/ethereum-mainnet-chain-id constants/arbitrum-mainnet-chain-id
|
||||
constants/optimism-mainnet-chain-id])
|
||||
constants/optimism-mainnet-chain-id constants/base-mainnet-chain-id])
|
||||
(sort (rf/sub [sub-name])))))
|
||||
(testing "selected networks -> chain-ids - specific network"
|
||||
(swap! rf-db/app-db #(assoc-in %
|
||||
|
||||
@@ -54,9 +54,11 @@
|
||||
(is (some #(= constants/ethereum-mainnet-chain-id (get-in % [:Prod :chainId])) response))
|
||||
(is (some #(= constants/optimism-mainnet-chain-id (get-in % [:Prod :chainId])) response))
|
||||
(is (some #(= constants/arbitrum-mainnet-chain-id (get-in % [:Prod :chainId])) response))
|
||||
(is (some #(= constants/base-mainnet-chain-id (get-in % [:Prod :chainId])) response))
|
||||
(is (some #(= constants/ethereum-sepolia-chain-id (get-in % [:Test :chainId])) response))
|
||||
(is (some #(= constants/arbitrum-sepolia-chain-id (get-in % [:Test :chainId])) response))
|
||||
(is (some #(= constants/optimism-sepolia-chain-id (get-in % [:Test :chainId])) response)))
|
||||
(is (some #(= constants/optimism-sepolia-chain-id (get-in % [:Test :chainId])) response))
|
||||
(is (some #(= constants/base-sepolia-chain-id (get-in % [:Test :chainId])) response)))
|
||||
|
||||
(deftest accounts-get-chains-contract-test
|
||||
(h/test-async :contract/wallet_get-ethereum-chains
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
:bsc-testnet {:id BSC-testnet-chain-id
|
||||
:name "BSC testnet"}
|
||||
:arbitrum {:id 42161 :name "Arbitrum"}
|
||||
:optimism {:id 10 :name "Optimism"}})
|
||||
:optimism {:id 10 :name "Optimism"}
|
||||
:base {:id 8453 :name "Base"}})
|
||||
|
||||
(defn chain-id->chain-keyword
|
||||
[i]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v8.1.0",
|
||||
"commit-sha1": "df1c8788e42784ba3b8ed3e7c5bd3ea530028410",
|
||||
"src-sha256": "1yxcswrj7p1m96lx795vbqlgjlmpkgzaw7l8f2k4ni3d7vmlklnw"
|
||||
"version": "v9.1.0",
|
||||
"commit-sha1": "4ec885a91f2857a30d1838213000f0a5a91fd52a",
|
||||
"src-sha256": "1fkvhazv7v2vyqpffx3r4p3aii5ai464nx2pdfgn6b6gmb24bxdq"
|
||||
}
|
||||
|
||||
@@ -11,4 +11,6 @@ Pillow~=10.0.0
|
||||
pytest-xdist==3.2.0
|
||||
pytz~=2020.4
|
||||
PyGithub==1.55
|
||||
typing-extensions==4.12.2
|
||||
typing-extensions==4.12.2
|
||||
mnemonic==0.21
|
||||
bip-utils==2.9.3
|
||||
@@ -0,0 +1,15 @@
|
||||
from bip_utils import Bip39SeedGenerator, Bip44, Bip44Coins, Bip44Changes
|
||||
|
||||
|
||||
def generate_wallet_address(passphrase: str, number: int = 1):
|
||||
# Derive accounts using the standard MetaMask path
|
||||
seed_bytes = Bip39SeedGenerator(passphrase).Generate()
|
||||
bip44_mst_ctx = Bip44.FromSeed(seed_bytes, Bip44Coins.ETHEREUM)
|
||||
|
||||
# Generate first n addresses
|
||||
expected_addresses = list()
|
||||
for i in range(number):
|
||||
bip44_acc_ctx = bip44_mst_ctx.Purpose().Coin().Account(0).Change(Bip44Changes.CHAIN_EXT).AddressIndex(i)
|
||||
expected_addresses.append(bip44_acc_ctx.PublicKey().ToAddress().lower())
|
||||
|
||||
return expected_addresses
|
||||
@@ -2,7 +2,6 @@ import base64
|
||||
import itertools
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from json import JSONDecodeError
|
||||
from os import environ
|
||||
from sys import argv
|
||||
@@ -212,18 +211,10 @@ class TestrailReport(BaseTestReport):
|
||||
except IndexError:
|
||||
continue
|
||||
for res in results:
|
||||
if last_testrun.first_commands:
|
||||
try:
|
||||
pattern = r"%s\?auth=.*#%s" % (device, str(last_testrun.first_commands[device]))
|
||||
except KeyError:
|
||||
pattern = device
|
||||
else:
|
||||
pattern = device
|
||||
if re.findall(pattern, res['comment']):
|
||||
res_id = res['id']
|
||||
if self.get_lambda_test_job_url(job_id=device) in res['comment']:
|
||||
try:
|
||||
for log in test.logs_paths.keys():
|
||||
self.add_attachment(method='add_attachment_to_result/%s' % str(res_id),
|
||||
self.add_attachment(method='add_attachment_to_result/%s' % str(res['id']),
|
||||
path=test.logs_paths[log])
|
||||
except (AttributeError, FileNotFoundError):
|
||||
pass
|
||||
|
||||
@@ -884,9 +884,10 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
|
||||
self.device_1.just_fyi("Admin gets push notification with the mention and tap it")
|
||||
message_received = False
|
||||
if self.home_1.get_pn(self.username_1):
|
||||
pn_element = self.home_1.get_pn(pn_text=self.username_1, wait_time=90)
|
||||
if pn_element:
|
||||
pn_element.click()
|
||||
message_received = True
|
||||
self.device_1.click_upon_push_notification_by_text(self.username_1)
|
||||
if not self.channel_1.chat_element_by_text(self.username_1).is_element_displayed():
|
||||
if self.channel_1.chat_message_input.is_element_displayed():
|
||||
self.errors.append("Message with the mention is not shown in the chat for the admin")
|
||||
@@ -904,11 +905,6 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
if message_received:
|
||||
self.channel_1.just_fyi("Set reaction for the message with a mention")
|
||||
self.channel_1.set_reaction(message=self.username_1, emoji="sad", times_to_long_press=2)
|
||||
try:
|
||||
self.channel_2.chat_element_by_text(self.username_1).emojis_below_message(
|
||||
emoji="sad").wait_for_element_text(1)
|
||||
except (Failed, NoSuchElementException):
|
||||
self.errors.append("Message reaction is not shown for the sender")
|
||||
|
||||
self.device_2.just_fyi("Sender edits the message with a mention")
|
||||
chat_element = self.channel_2.chat_element_by_text(self.username_1)
|
||||
@@ -937,6 +933,13 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
if not element.is_element_displayed(10) or element.text != expected_message:
|
||||
self.errors.append("Edited message is not shown correctly for the (receiver) admin")
|
||||
|
||||
self.device_2.just_fyi("Sender checks the reaction for a message with a mention")
|
||||
try:
|
||||
self.channel_2.chat_element_by_text(self.username_1).emojis_below_message(
|
||||
emoji="sad").wait_for_element_text(1)
|
||||
except (Failed, NoSuchElementException):
|
||||
self.errors.append("Message reaction is not shown for the sender")
|
||||
|
||||
self.home_2.navigate_back_to_home_view()
|
||||
if not self.channel_1.chat_message_input.is_element_displayed():
|
||||
self.channel_1.navigate_back_to_home_view()
|
||||
@@ -949,7 +952,7 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
self.channel_1.send_message_button.click()
|
||||
self.device_2.just_fyi("Invited member gets push notification with the mention and tap it")
|
||||
self.device_2.open_notification_bar()
|
||||
push_notification_element = self.home_2.get_pn(self.username_2)
|
||||
push_notification_element = self.home_2.get_pn(pn_text=self.username_2, wait_time=90)
|
||||
if push_notification_element:
|
||||
push_notification_element.click()
|
||||
if not self.channel_2.chat_element_by_text(self.username_2).is_element_displayed():
|
||||
|
||||
@@ -2,6 +2,7 @@ import pytest
|
||||
from selenium.common import TimeoutException
|
||||
|
||||
from base_test_case import MultipleSharedDeviceTestCase, create_shared_drivers
|
||||
from support.helpers import generate_wallet_address
|
||||
from tests import marks, run_in_parallel, transl
|
||||
from users import transaction_senders
|
||||
from views.sign_in_view import SignInView
|
||||
@@ -162,34 +163,90 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
|
||||
@marks.testrail_id(741054)
|
||||
def test_fallback_add_key_pair(self):
|
||||
expected_addresses = generate_wallet_address(passphrase=self.recovery_phrase, number=4)
|
||||
account_to_add = transaction_senders['ETH_1']
|
||||
self.home_1.navigate_back_to_home_view()
|
||||
self.home_2.navigate_back_to_home_view()
|
||||
wallet_1 = self.home_1.wallet_tab.click()
|
||||
wallet_2 = self.home_2.wallet_tab.click()
|
||||
regular_account_name = "New regular account"
|
||||
key_pair_account_name = "Key pair account"
|
||||
key_pair_name = "New key pair"
|
||||
key_pair_account_address = '0x' + account_to_add['address'].lower()
|
||||
|
||||
wallet_1.just_fyi("Device 1: add a new regular account")
|
||||
regular_account_name = "New regular account"
|
||||
regular_derivation_path = wallet_1.add_regular_account(account_name=regular_account_name)
|
||||
regular_account_wallet_address = wallet_1.get_account_address().split(':')[-1]
|
||||
regular_account_address = wallet_1.get_account_address().split(':')[-1]
|
||||
account_element = wallet_1.get_account_element(account_name=regular_account_name)
|
||||
wallet_1.close_account_button.click_until_presence_of_element(account_element)
|
||||
|
||||
wallet_1.just_fyi("Device 1: add a new key pair account")
|
||||
if regular_account_address != expected_addresses[1]:
|
||||
self.errors.append("Newly added regular account address %s doesn't match expected %s" % (
|
||||
regular_account_address, expected_addresses[1]))
|
||||
if regular_account_address not in expected_addresses:
|
||||
self.errors.append("Newly added regular account address %s is not in the list of expected addresses %s" % (
|
||||
regular_account_address, expected_addresses))
|
||||
|
||||
wallet_1.just_fyi("Device 1: add a new key pair account by importing recovery phrase")
|
||||
account_element.swipe_left_on_element()
|
||||
key_pair_derivation_path = wallet_1.add_key_pair_account(account_name=key_pair_account_name,
|
||||
passphrase=account_to_add['passphrase'],
|
||||
key_pair_name=key_pair_name)
|
||||
imported_key_pair_account_name = "Imported account"
|
||||
imported_key_pair_name = "Imported key pair"
|
||||
imported_key_pair_account_address = '0x' + account_to_add['address'].lower()
|
||||
imported_key_pair_derivation_path = wallet_1.import_key_pair_using_recovery_phrase(
|
||||
account_name=imported_key_pair_account_name,
|
||||
passphrase=account_to_add['passphrase'],
|
||||
key_pair_name=imported_key_pair_name)
|
||||
|
||||
wallet_1.close_account_button.click_until_presence_of_element(account_element)
|
||||
|
||||
wallet_1.just_fyi("Device 1: verify default and added key pairs details")
|
||||
account_element.swipe_left_on_element()
|
||||
wallet_1.get_account_element(account_name=imported_key_pair_account_name).swipe_left_on_element()
|
||||
if not wallet_1.add_account_button.is_element_displayed():
|
||||
wallet_1.get_account_element(account_name=imported_key_pair_account_name).swipe_left_on_element()
|
||||
wallet_1.add_account_button.click()
|
||||
wallet_1.create_account_button.click()
|
||||
wallet_1.edit_key_pair_button.click()
|
||||
expected_texts_regular = [
|
||||
regular_account_name,
|
||||
"%s...%s" % (regular_account_address[:5], regular_account_address[-3:])
|
||||
]
|
||||
for text in expected_texts_regular:
|
||||
if not wallet_1.default_key_pair_container.get_child_element_by_text_part(text).is_element_displayed():
|
||||
self.errors.append("Newly added regular account is not shown in default key pair list")
|
||||
break
|
||||
expected_texts_key_pair = [
|
||||
imported_key_pair_account_name, imported_key_pair_name,
|
||||
"%s...%s" % (imported_key_pair_account_address[:5], imported_key_pair_account_address[-3:])
|
||||
]
|
||||
for text in expected_texts_key_pair:
|
||||
if not wallet_1.added_key_pair_container.get_child_element_by_text_part(text).is_element_displayed():
|
||||
self.errors.append("Newly added regular account is not shown in default key pair list")
|
||||
break
|
||||
|
||||
wallet_1.just_fyi("Device 1: add a new key pair account by generating a new key pair")
|
||||
generated_key_pair_account_name = "Generated account"
|
||||
generated_key_pair_name = "Generated key pair"
|
||||
generated_key_pair_derivation_path, generated_passphrase = wallet_1.generate_new_key_pair(
|
||||
account_name=generated_key_pair_account_name,
|
||||
key_pair_name=generated_key_pair_name)
|
||||
generated_key_pair_account_address = wallet_1.get_account_address().split(':')[-1]
|
||||
wallet_1.close_account_button.click_until_presence_of_element(account_element)
|
||||
|
||||
expected_addresses = generate_wallet_address(passphrase=generated_passphrase, number=4)
|
||||
if generated_key_pair_account_address != expected_addresses[0]:
|
||||
self.errors.append("Generated key pair account address %s doesn't match expected %s" % (
|
||||
generated_key_pair_account_address, expected_addresses[0]))
|
||||
if generated_key_pair_account_address not in expected_addresses:
|
||||
self.errors.append("Generated key pair account address %s is not in the list of expected addresses %s" % (
|
||||
generated_key_pair_account_address, expected_addresses))
|
||||
|
||||
self.home_2.just_fyi("Device 2: check imported accounts are shown before importing key pair")
|
||||
self.home_2.profile_button.click()
|
||||
self.profile_2.profile_wallet_button.click()
|
||||
self.profile_2.key_pairs_and_accounts_button.click()
|
||||
if not self.profile_2.get_missing_key_pair_by_name(key_pair_name=key_pair_name).is_element_displayed():
|
||||
self.errors.append("Key pair is not shown in profile as missing before importing")
|
||||
if not self.profile_2.get_missing_key_pair_by_name(key_pair_name=imported_key_pair_name).is_element_displayed():
|
||||
self.errors.append("New imported key pair is not shown in profile as missing before importing")
|
||||
if not self.profile_2.get_missing_key_pair_by_name(
|
||||
key_pair_name=generated_key_pair_name).is_element_displayed():
|
||||
self.errors.append("Generated key pair is not shown in profile as missing before importing")
|
||||
if not self.profile_2.get_key_pair_account_by_name(account_name=regular_account_name).is_element_displayed():
|
||||
self.errors.append(
|
||||
"Newly added regular account is not shown in profile as on device before importing key pair")
|
||||
@@ -200,7 +257,7 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
|
||||
wallet_2.just_fyi("Device 2: import key pair")
|
||||
wallet_2.get_account_element(account_name=regular_account_name).swipe_left_on_element()
|
||||
wallet_2.get_account_element(account_name=key_pair_account_name).click()
|
||||
wallet_2.get_account_element(account_name=imported_key_pair_account_name).click()
|
||||
wallet_2.element_by_translation_id("import-key-pair").click()
|
||||
self.sign_in_2.passphrase_edit_box.send_keys(account_to_add['passphrase'])
|
||||
wallet_2.slide_and_confirm_with_password()
|
||||
@@ -211,19 +268,28 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
self.profile_2.key_pairs_and_accounts_button.click()
|
||||
if self.profile_2.get_key_pair_account_by_name(account_name=regular_account_name).is_element_displayed():
|
||||
address_text = self.profile_2.get_key_pair_account_by_name(account_name=regular_account_name).address.text
|
||||
if address_text != '...'.join((regular_account_wallet_address[:5], regular_account_wallet_address[-3:])):
|
||||
if address_text != '...'.join((regular_account_address[:5], regular_account_address[-3:])):
|
||||
self.errors.append(
|
||||
"Incorrect wallet address if shown for regular account after importing: " + address_text)
|
||||
else:
|
||||
self.errors.append("Newly added regular account is not shown in profile after importing key pair")
|
||||
|
||||
if self.profile_2.get_key_pair_account_by_name(account_name=key_pair_account_name).is_element_displayed():
|
||||
address_text = self.profile_2.get_key_pair_account_by_name(account_name=key_pair_account_name).address.text
|
||||
if address_text != '...'.join((key_pair_account_address[:5], key_pair_account_address[-3:])):
|
||||
account_element = self.profile_2.get_key_pair_account_by_name(
|
||||
account_name=imported_key_pair_account_name)
|
||||
if account_element.is_element_displayed():
|
||||
address_text = account_element.address.text
|
||||
if address_text != '...'.join(
|
||||
(imported_key_pair_account_address[:5], imported_key_pair_account_address[-3:])):
|
||||
self.errors.append(
|
||||
"Incorrect wallet address if shown for key pair account after importing: " + address_text)
|
||||
"Incorrect wallet address if shown for imported key pair account after importing: " + address_text)
|
||||
else:
|
||||
self.errors.append("Key pair account is not shown in profile as on device after importing key pair")
|
||||
self.errors.append(
|
||||
"Imported key pair account is not shown in profile as on device after importing key pair")
|
||||
|
||||
if not self.profile_2.get_missing_key_pair_by_name(
|
||||
key_pair_name=generated_key_pair_name).is_element_displayed():
|
||||
self.errors.append(
|
||||
"Generated key pair account is not shown in profile as missing after importing the first key pair")
|
||||
self.profile_2.click_system_back_button(times=3)
|
||||
|
||||
# ToDo: Arbiscan API is down, looking for analogue
|
||||
@@ -243,11 +309,25 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
self.errors.append("Incorrect derivation path %s is shown for the regular account" % der_path)
|
||||
wallet_2.close_account_button.click_until_presence_of_element(account_element)
|
||||
account_element.swipe_left_on_element()
|
||||
wallet_2.get_account_element(account_name=key_pair_account_name).click()
|
||||
wallet_2.get_account_element(account_name=imported_key_pair_account_name).click()
|
||||
wallet_2.about_tab.click()
|
||||
der_path = wallet_2.account_about_derivation_path_text.text
|
||||
if der_path != key_pair_derivation_path:
|
||||
self.errors.append("Incorrect derivation path %s is shown for the key pair account" % der_path)
|
||||
if der_path != imported_key_pair_derivation_path:
|
||||
self.errors.append("Incorrect derivation path %s is shown for the imported key pair account" % der_path)
|
||||
wallet_2.close_account_button.click_until_presence_of_element(account_element)
|
||||
account_element.swipe_left_on_element()
|
||||
wallet_2.get_account_element(account_name=generated_key_pair_account_name).click()
|
||||
wallet_2.element_by_translation_id("import-key-pair").click()
|
||||
self.sign_in_2.passphrase_edit_box.send_keys(generated_passphrase)
|
||||
wallet_2.slide_and_confirm_with_password()
|
||||
wallet_2.get_account_element(account_name=generated_key_pair_account_name).click()
|
||||
wallet_2.about_tab.click()
|
||||
der_path = wallet_2.account_about_derivation_path_text.text
|
||||
if der_path != generated_key_pair_derivation_path:
|
||||
self.errors.append("Incorrect derivation path %s is shown for the generated key pair account" % der_path)
|
||||
if not wallet_2.element_by_text_part(generated_key_pair_account_address).is_element_displayed():
|
||||
self.errors.append(
|
||||
"Generated key pair address %s is absent in About tab" % generated_key_pair_account_address)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(740222)
|
||||
|
||||
@@ -352,6 +352,9 @@ class BaseElement(object):
|
||||
def get_child_element_by_text(self, text: str):
|
||||
return BaseElement(self.driver, prefix=self.locator, xpath="//*[@text='%s']" % text)
|
||||
|
||||
def get_child_element_by_text_part(self, text: str):
|
||||
return BaseElement(self.driver, prefix=self.locator, xpath="//*[contains(@text,'%s')]" % text)
|
||||
|
||||
|
||||
class EditBox(BaseElement):
|
||||
|
||||
|
||||
@@ -474,10 +474,10 @@ class HomeView(BaseView):
|
||||
element.double_click()
|
||||
self.element_by_translation_id(mute_period).click()
|
||||
|
||||
def get_pn(self, pn_text: str):
|
||||
def get_pn(self, pn_text: str, wait_time: int = 60):
|
||||
self.driver.info("Getting PN by '%s'" % pn_text)
|
||||
expected_element = PushNotificationElement(self.driver, pn_text)
|
||||
return expected_element if expected_element.is_element_displayed(60) else False
|
||||
return expected_element if expected_element.is_element_displayed(wait_time) else False
|
||||
|
||||
def contact_details_row(self, username=None, index=None):
|
||||
return ContactDetailsRow(self.driver, username=username, index=index)
|
||||
|
||||
@@ -107,11 +107,19 @@ class WalletView(BaseView):
|
||||
# Edit key pair
|
||||
self.edit_key_pair_button = Button(self.driver, accessibility_id="Edit")
|
||||
self.key_pairs_plus_button = Button(self.driver, accessibility_id="standard-title-action")
|
||||
self.default_key_pair_container = BaseElement(self.driver,
|
||||
xpath="//*[@content-desc='user-avatar, title, details']")
|
||||
self.added_key_pair_container = BaseElement(self.driver,
|
||||
xpath="//*[@content-desc='icon, title, details']")
|
||||
self.generate_new_keypair_button = Button(self.driver, accessibility_id="generate-new-keypair")
|
||||
self.import_using_recovery_phrase_button = Button(self.driver, accessibility_id="import-using-phrase")
|
||||
self.key_pair_continue_button = Button(self.driver, accessibility_id="Continue")
|
||||
self.key_pair_name_input = EditBox(
|
||||
self.driver, xpath="//*[@text='Key pair name']/..//following-sibling::*/*[@content-desc='input']")
|
||||
self.passphrase_text_element = Text(
|
||||
self.driver, xpath="//*[@resource-id='counter-component']/following-sibling::android.widget.TextView")
|
||||
self.passphrase_word_number_container = Text(
|
||||
self.driver, xpath="//*[@content-desc='number-container']/android.widget.TextView")
|
||||
|
||||
def set_network_in_wallet(self, network_name: str):
|
||||
self.network_drop_down.click()
|
||||
@@ -198,25 +206,40 @@ class WalletView(BaseView):
|
||||
def get_activity_element(self, index=1):
|
||||
return ActivityElement(self.driver, index=index)
|
||||
|
||||
def add_key_pair_account(self, account_name, passphrase=None, key_pair_name=None):
|
||||
def generate_new_key_pair(self, account_name: str, key_pair_name: str):
|
||||
self.key_pairs_plus_button.click()
|
||||
self.generate_new_keypair_button.click()
|
||||
for checkbox in self.checkbox_button.find_elements():
|
||||
checkbox.click()
|
||||
self.element_by_translation_id("reveal-phrase").click()
|
||||
passphrase = [i.text for i in self.passphrase_text_element.find_elements()]
|
||||
self.element_by_translation_id("i-have-written").click()
|
||||
for _ in range(4):
|
||||
element = self.passphrase_word_number_container.find_element()
|
||||
number = int(element.text)
|
||||
Button(self.driver, accessibility_id=passphrase[number - 1]).click()
|
||||
self.wait_for_staleness_of_element(element)
|
||||
self.checkbox_button.click()
|
||||
self.element_by_translation_id("done").click()
|
||||
self.key_pair_name_input.send_keys(key_pair_name)
|
||||
self.key_pair_continue_button.click()
|
||||
derivation_path = self.add_account_derivation_path_text.text
|
||||
SignInView(self.driver).profile_title_input.send_keys(account_name)
|
||||
self.slide_and_confirm_with_password()
|
||||
return derivation_path.replace(' ', ''), ' '.join(passphrase)
|
||||
|
||||
def import_key_pair_using_recovery_phrase(self, account_name: str, passphrase: str, key_pair_name: str):
|
||||
self.add_account_button.click()
|
||||
self.create_account_button.click()
|
||||
signin_view = SignInView(self.driver)
|
||||
signin_view.profile_title_input.send_keys(account_name)
|
||||
self.edit_key_pair_button.click()
|
||||
self.key_pairs_plus_button.click()
|
||||
if passphrase:
|
||||
self.import_using_recovery_phrase_button.click()
|
||||
signin_view.passphrase_edit_box.send_keys(passphrase)
|
||||
self.key_pair_continue_button.click()
|
||||
self.key_pair_name_input.send_keys(key_pair_name)
|
||||
self.key_pair_continue_button.click()
|
||||
else:
|
||||
self.generate_new_keypair_button.click()
|
||||
for checkbox in self.checkbox_button.find_elements():
|
||||
checkbox.click()
|
||||
self.element_by_translation_id("reveal-phrase").click()
|
||||
# ToDo: can't be done in current small size emulators, add when moved to LambdaTest
|
||||
self.import_using_recovery_phrase_button.click()
|
||||
signin_view.passphrase_edit_box.send_keys(passphrase)
|
||||
self.key_pair_continue_button.click()
|
||||
self.key_pair_name_input.send_keys(key_pair_name)
|
||||
self.key_pair_continue_button.click()
|
||||
derivation_path = self.add_account_derivation_path_text.text
|
||||
self.slide_and_confirm_with_password()
|
||||
return derivation_path.replace(' ', '')
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
{
|
||||
"about": "About",
|
||||
"about-app": "About",
|
||||
"about-gas-amount": "AKA gas limit. Refers to the maximum number of computational steps (or units of gas) that a transaction can consume. It represents the complexity or amount of work required to execute a transaction or smart contract.\n\nThe gas limit is a cap on how much work the transaction can do on the blockchain. If the gas limit is set too low, the transaction may fail due to insufficient gas.",
|
||||
"about-key-storage-content": "Status will never access your private key. Be sure to backup your seed phrase. If you lose your phone it is the only way to access your keys.",
|
||||
"about-key-storage-title": "About key storage",
|
||||
"about-max-base-fee": "When your transaction gets included in the block, any difference between your max base fee and the actual base fee will be refunded.",
|
||||
"about-names-content": "No one can pretend to be you! You’re anonymous by default and never have to reveal your real name. You can register a custom name for a small fee.",
|
||||
"about-names-title": "Names can’t be changed",
|
||||
"about-nonce": "Transaction counter ensuring transactions from your account are processed in the correct order and can’t be replayed. Each new transaction increments the nonce by 1, ensuring uniqueness and preventing double-spending.\n\nIf a transaction with a lower nonce is pending, higher nonce transactions will remain in the queue until the earlier one is confirmed.",
|
||||
"about-priority-fee": "AKA miner tip. A voluntary fee you can add to incentivise miners or validators to prioritise your transaction.\n\nThe higher the tip, the faster your transaction is likely to be processed, especially curing periods of higher network congestion.",
|
||||
"about-sharing-data": "About sharing data",
|
||||
"accent-colour": "Accent colour",
|
||||
"accent-colour-updated": "Accent colour updated",
|
||||
@@ -191,6 +195,7 @@
|
||||
"backup-through-waku": "Backup through waku",
|
||||
"bad-fees-description": "Your priority fee is below our suggested parameters.",
|
||||
"balance": "Balance",
|
||||
"base": "Base",
|
||||
"be-safe-with-secure-cold-wallet": "Be safe with secure cold wallet",
|
||||
"begin-set-up": "Begin setup",
|
||||
"below-base-fee": "max fee below base fee",
|
||||
@@ -654,6 +659,7 @@
|
||||
"current-password": "Current password",
|
||||
"current-pin": "Enter 6-digit passcode",
|
||||
"current-pin-description": "Enter your 6-digit passcode to proceed",
|
||||
"current-units": "Current: {{current}} UNITS",
|
||||
"custom": "Custom",
|
||||
"custom-node": "You are using custom RPC endpoint. Your local transfers history might be incomplete.",
|
||||
"custom-seed-phrase": "Invalid seed phrase",
|
||||
@@ -779,6 +785,7 @@
|
||||
"device-syncing": "Device syncing",
|
||||
"devices": "Devices",
|
||||
"devices-count": "{{number}} devices",
|
||||
"different-keycard": "It’s a different Keycard",
|
||||
"disable": "disable",
|
||||
"disable-all": "Disable all",
|
||||
"disable-later-in-settings": "You can disable this later in Settings",
|
||||
@@ -1028,6 +1035,9 @@
|
||||
"export-key": "Export private key",
|
||||
"external-link": "External link",
|
||||
"external-storage-denied": "Access to external storage is denied",
|
||||
"factory-reset": "Factory reset",
|
||||
"factory-reset-keycard": "Factory reset this Keycard",
|
||||
"factory-reset-warning": "Please ensure you have a backup of your recovery phrase before proceeding with the factory reset. If you want to switch to password authentication instead of Keycard, remove the profile from the device and log in with your recovery phrase.",
|
||||
"failed": "Failed",
|
||||
"failed-on": "Failed on",
|
||||
"failed-to-fetch-community": "Failed to fetch community",
|
||||
@@ -1045,6 +1055,7 @@
|
||||
"featured": "Featured",
|
||||
"feb": "Feb",
|
||||
"fee-cap": "Fee cap",
|
||||
"fee-current-gwei": "Current: {{current}} GWEI",
|
||||
"fee-explanation": "Maximum overall price for the transaction. If the block base fee exceeds this, it will be included in a following block with a lower base fee.",
|
||||
"fee-options": "Suggested fee options",
|
||||
"fees": "Fees",
|
||||
@@ -1086,7 +1097,9 @@
|
||||
"from-all-profiles-on-device": "From all profiles on device",
|
||||
"from-capitalized": "From",
|
||||
"from-label": "From",
|
||||
"gas-amount": "Gas amount",
|
||||
"gas-amount-limit": "Gas amount limit",
|
||||
"gas-amount-lower": "Too low. Recommended: {{current}} UNITS",
|
||||
"gas-limit": "Gas limit",
|
||||
"gas-price": "Gas price",
|
||||
"gas-used": "Gas used",
|
||||
@@ -1346,6 +1359,7 @@
|
||||
"key-name-error-taken": "Key pair name already in use",
|
||||
"key-name-error-too-short": "Key pair name must be at least {{count}} characters",
|
||||
"key-on-device": "Private key is saved on this device",
|
||||
"key-pair-erased": "Key pair will be erased from Keycard",
|
||||
"key-pair-imported-successfully": "{{name}} key pair imported successfully",
|
||||
"key-pair-migrated-successfully": "Profile key pair successfully migrated",
|
||||
"key-pair-name-updated": "Key pair name updated",
|
||||
@@ -1369,6 +1383,7 @@
|
||||
"keycard-desc": "Own a Keycard? Store your keys on it; you’ll need it for transactions",
|
||||
"keycard-dont-ask-card": "Don't ask for card to sign in",
|
||||
"keycard-empty": "Keycard is empty",
|
||||
"keycard-empty-ready": "Keycard is empty and ready to be used",
|
||||
"keycard-enter-new-passcode": "Enter new passcode {{step}}/2",
|
||||
"keycard-error-description": "Connect the card again to continue",
|
||||
"keycard-error-title": "Connection lost",
|
||||
@@ -1427,7 +1442,9 @@
|
||||
"keycard-redeem-title": "Redeem to",
|
||||
"keycard-redeem-tx": "Redeem assets",
|
||||
"keycard-redeem-tx-desc": "Tap the card to sign and receive assets",
|
||||
"keycard-reset-failed": "Failed to reset Keycard",
|
||||
"keycard-reset-passcode": "Reset passcode",
|
||||
"keycard-reset-success": "Keycard has been reset",
|
||||
"keycard-success-description": "You may remove the card now",
|
||||
"keycard-success-title": "Success",
|
||||
"keycard-unauthorized-operation": "You're unauthorized to perform this operation.\n Please tap valid card and try again.",
|
||||
@@ -1446,6 +1463,7 @@
|
||||
"language-and-currency": "Language and currency",
|
||||
"last-backup-performed": "Last backup performed:",
|
||||
"last-transaction": "Last transaction",
|
||||
"last-transaction-is": "Last transaction: {{number}}",
|
||||
"layer-2": "Layer 2",
|
||||
"learn-more": "Learn more",
|
||||
"learn-more-about-keycard": "Learn more about Keycard",
|
||||
@@ -1552,8 +1570,12 @@
|
||||
"master-account": "Master account",
|
||||
"max": "Max: {{number}}",
|
||||
"max-2-decimals": "Max. 2 decimals",
|
||||
"max-base-fee": "Max base fee",
|
||||
"max-base-fee-higher": "Higher than necessary. Current: {{current}} GWEI",
|
||||
"max-base-fee-lower": "Too low. Current: {{current}} GWEI ",
|
||||
"max-fee": "Max fee",
|
||||
"max-fees": "Max fees",
|
||||
"max-gas-amount": "Max gas amount",
|
||||
"max-priority-fee": "Max priority fee",
|
||||
"max-slippage": "Max slippage",
|
||||
"max-token": "Max: {{number}} {{token-symbol}}",
|
||||
@@ -1797,6 +1819,7 @@
|
||||
"non-archival-node": "RPC endpoint doesn't support archival requests. Your local transfers history might be incomplete.",
|
||||
"non-contacts": "Non contacts",
|
||||
"nonce": "Nonce",
|
||||
"nonce-higher": "Higher than suggested nonce of {{number}}",
|
||||
"none": "None",
|
||||
"normal": "Normal",
|
||||
"not-a-chatkey": "This is not a chatkey",
|
||||
@@ -2023,6 +2046,9 @@
|
||||
"price-impact-too-high": "Price impact too high. Lower token amount or try again later.",
|
||||
"principles": "Principles",
|
||||
"priority": "Priority",
|
||||
"priority-fee": "Priority fee",
|
||||
"priority-fee-higher": "More than necessary. Current: {{low}} - {{high}} GWEI",
|
||||
"priority-fee-lower": "Too low. Current: {{low}} - {{high}} GWEI",
|
||||
"privacy": "Privacy",
|
||||
"privacy-and-security": "Privacy and security",
|
||||
"privacy-photos": "Profile Photo Privacy",
|
||||
@@ -2140,6 +2166,7 @@
|
||||
"remove-from-contacts-text": "By removing a user from your contact list you do not hide your wallet address from them",
|
||||
"remove-group": "Remove group",
|
||||
"remove-key-pair-and-derived-accounts": "Remove key pair and derived accounts",
|
||||
"remove-keycard-content": "Remove all content from this Keycard",
|
||||
"remove-network": "Remove network",
|
||||
"remove-nickname": "Remove nickname",
|
||||
"remove-nickname-toast": "You have removed {{secondary-name}}'s nickname",
|
||||
@@ -2232,9 +2259,11 @@
|
||||
"scan-an-address-qr-code": "Scan an address QR code",
|
||||
"scan-key-pairs-qr-code": "Scan key pairs QR code",
|
||||
"scan-keycard": "Scan Keycard",
|
||||
"scan-keycard-actions": "Scan Keycard to see available actions",
|
||||
"scan-or-enter-a-sync-code": "Scan or enter a sync code",
|
||||
"scan-or-enter-sync-code": "Scan or enter sync code",
|
||||
"scan-or-enter-sync-code-seen-on-this-device": "Scan or enter sync code seen on this device",
|
||||
"scan-previous-keycard": "Please scan Keycard you previously scanned",
|
||||
"scan-qr": "Scan QR",
|
||||
"scan-qr-code": "Scan QR code",
|
||||
"scan-sync-code": "Scan Sync Code",
|
||||
@@ -2362,6 +2391,7 @@
|
||||
"share-invite-link": "Share an invite link",
|
||||
"share-link": "Share link",
|
||||
"share-link-to-arb": "Share link to Arbiscan",
|
||||
"share-link-to-base": "Share link to Basescan",
|
||||
"share-link-to-eth": "Share link to Etherscan",
|
||||
"share-link-to-oeth": "Share link to Optimism Explorer",
|
||||
"share-logs": "Share logs",
|
||||
@@ -2617,6 +2647,7 @@
|
||||
"transaction-history": "Transaction history",
|
||||
"transaction-request": "Transaction Request",
|
||||
"transaction-sent": "Transaction sent",
|
||||
"transaction-settings": "Transaction settings",
|
||||
"transaction-signed": "The transaction has been successfully signed",
|
||||
"transactions": "Transactions",
|
||||
"transactions-filter-select-all": "Select all",
|
||||
@@ -2677,6 +2708,7 @@
|
||||
"type": "Type",
|
||||
"type-a-message": "Message",
|
||||
"type-nickname": "Type nickname",
|
||||
"type-nonce": "Type nonce",
|
||||
"type-pairing-code": "Type or paste pairing code",
|
||||
"type-slippage": "Type slippage",
|
||||
"type-some-chat-key": "zQ3...1sgt5N",
|
||||
@@ -2733,6 +2765,7 @@
|
||||
"updates-to-tos": "Updates to Terms of Use",
|
||||
"updates-to-tos-desc": "Before you continue, please review the Terms of Use and confirm you take full responsibility for how you use the app.",
|
||||
"upvote-it": "upvote it",
|
||||
"urgent": "Urgent",
|
||||
"url": "URL",
|
||||
"usage-data-shared-from-all-profiles": "Usage data will be shared from all profiles added to device. ",
|
||||
"usd-currency": "USD",
|
||||
@@ -2787,6 +2820,7 @@
|
||||
"view-gitcoin": "View in Gitcoin",
|
||||
"view-members": "View members",
|
||||
"view-on-arb": "View on Arbiscan",
|
||||
"view-on-base": "View on Basescan",
|
||||
"view-on-eth": "View on Etherscan",
|
||||
"view-on-oeth": "View on Optimism Explorer",
|
||||
"view-on-opensea": "View on OpenSea",
|
||||
|
||||
Reference in New Issue
Block a user