Compare commits

...
Author SHA1 Message Date
Prem Chaitanya Prathi f399b7887c fix: filter bad peer removal and missing message verifier fixes 2024-12-19 16:10:52 +05:30
Mohamed Javid 0f036ca9c4 fix_: slider reset in standard authentication (#21831)
This commit fixes the slider-button doesn't reset after the completion of slider in standard authentication with keycard keypairs.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-12-17 17:46:16 +05:30
flexsurfer c19128e8b1 [#21828] Close the flows for adding accounts in keycard accounts (#21829) 2024-12-16 17:49:59 +01:00
Brian Sztamfater 8d615801d1 feat_: optimize endpoint calls when fetching balances (#21802)
Signed-off-by: Brian Sztamfater <brian@status.im>
2024-12-16 12:11:09 -03:00
Mohsen 4f6e1897fe [#21135] fix: handle unsupported wallet address (#21820) 2024-12-16 17:54:16 +03:00
Ulises ManuelandShivek Khurana 93b5f8d180 Hide viewing community token requirements under a feature flag (#21814)
Co-authored-by: Shivek Khurana <khuranashivek@outlook.com>
2024-12-16 18:17:06 +05:30
Parvesh Monu 0e607dc293 fix Privacy policy button in learn more sheet open terms-of-use sheet (#21823) 2024-12-16 15:42:17 +05:30
flexsurfer 9ced0e4131 [#21708] [Android] Login with Keycard stucks on Preparing screen from time to time (#21811) 2024-12-13 19:57:26 +01:00
Sean Hagstrom 55ee800e18 feature: add keycard metric events (#21794)
This change adds some metrics events for tracking when keycard users have reached an unavailable feature, when keycard users have successfully logged in, and when keycard users have succeeded or failed to migrate to keycard.
2024-12-12 09:21:09 -08:00
flexsurfer 676998b83b [#21803] Cannot perform transactions/create derived account via keycard using NON default keypairs which existed before keycard migration (#21808) 2024-12-12 16:31:54 +01:00
Ulises Manuel 755ef19315 feat(profile): Make terms of use and privacy policy easily accessible (#21759)
* Fix `:true` keyword being used in navigation screens.

* Add about screen, terms of use and privacy policy links

* Remove old about app screen
2024-12-11 13:15:26 -06:00
Ulises Manuel bc9b0f8c87 feat(oboarding): Update ilustrations (#21781)
* Share usage data screen image done

* Update login by syncing and login using recovery phrase images

*  Small refactor: remove `merge` and add a `let` binding

* Fix modal entering expected animation
2024-12-11 11:05:23 -06:00
Yevheniia Berdnyk c8b063493b e2e: False failures fixes 2024-12-11 00:38:34 +02:00
flexsurfer 949e78a17e [#21577] Keycard [Wallet] - Derives next account for profile key pair (#21753) 2024-12-10 18:07:45 +01:00
Mohsen a821ec5a14 [#21763] feat: add feature unavailable for dapps interaction (#21771) 2024-12-10 11:35:44 +01:00
cuiyourong 4648066ec7 chore: fix some typos in comment (#21775) 2024-12-10 09:27:32 +01:00
79 changed files with 989 additions and 544 deletions
+1 -1
View File
@@ -150,7 +150,7 @@ This one is straightforward, just evaluate a navigation dispatch form from anywh
#### REPL-ing a component
This is also straighforward, but there are some small differences. Just like above, we only have to evaluate a dispatch form, as follows:
This is also straightforward, but there are some small differences. Just like above, we only have to evaluate a dispatch form, as follows:
```cljs
;; example debugging a quo component, although it could be any other component e.g. from the `status-im2` ns.
+1 -1
View File
@@ -26,4 +26,4 @@ These log files are uploaded to Jenkins as CI job artifacts on failure using `ar
* `set_xcode_version.log` - Output from `node_modules/react-native/scripts/react-native-xcode.sh`.
- Created by redirecting output of `shellScript` in `ios/StatusIm.xcodeproj/project.pbxproj` for "Run Script" build Phase.
* `Status PR-StatusImPR.log - Created by [Fastlane Gym](https://docs.fastlane.tools/actions/gym/).
- Configred via [`Fastfile`](../Fastfile) using `buildlog_path` argument for `build_ios_app`.
- Configured via [`Fastfile`](../Fastfile) using `buildlog_path` argument for `build_ios_app`.
+1 -1
View File
@@ -66,7 +66,7 @@
"react-native-shake": "^3.3.1",
"react-native-share": "10.0.2",
"react-native-static-safe-area-insets": "^2.2.0",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.6.3",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.6.4",
"react-native-svg": "13.10.0",
"react-native-webview": "13.6.3",
"react-syntax-highlighter": "^15.5.0"
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 306 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

+4
View File
@@ -71,6 +71,10 @@
[callback]
(.addListener ^js event-emitter "keyCardOnDisconnected" callback))
(defn on-card-new-pairing
[callback]
(.addListener ^js event-emitter "keyCardNewPairing" callback))
(defn on-nfc-user-cancelled
[callback]
(.addListener ^js event-emitter "keyCardOnNFCUserCancelled" callback))
@@ -1,67 +0,0 @@
(ns legacy.status-im.ui.screens.about-app.views
(:require
[legacy.status-im.ui.components.colors :as colors]
[legacy.status-im.ui.components.copyable-text :as copyable-text]
[legacy.status-im.ui.components.icons.icons :as icons]
[legacy.status-im.ui.components.list.item :as list.item]
[legacy.status-im.ui.components.react :as react]
[quo.core :as quo]
[utils.i18n :as i18n]
[utils.re-frame :as rf])
(:require-macros [legacy.status-im.utils.views :as views]))
(views/defview about-app
[]
(views/letsubs [app-version [:get-app-short-version]
commit-hash [:get-commit-hash]
node-version [:get-app-node-version]]
[:<>
[quo/page-nav
{:type :title
:title (i18n/label :t/about-app)
:background :blur
:icon-name :i/close
:on-press #(rf/dispatch [:navigate-back])}]
[react/scroll-view
[copyable-text/copyable-text-view
{:copied-text app-version}
[list.item/list-item
{:size :small
:accessibility-label :app-version
:title (i18n/label :t/version)
:accessory :text
:accessory-text app-version}]]
[copyable-text/copyable-text-view
{:copied-text commit-hash}
[list.item/list-item
{:size :small
:accessibility-label :commit-hash
:title (i18n/label :t/app-commit)
:accessory :text
:accessory-text commit-hash}]]
[copyable-text/copyable-text-view
{:copied-text node-version}
[list.item/list-item
{:size :small
:accessibility-label :node-version
:title (i18n/label :t/node-version)
:accessory :text
:accessory-text node-version}]]]]))
(views/defview learn-more-sheet
[]
(views/letsubs [{:keys [title content]} [:bottom-sheet/options]]
[react/view
{:style {:padding-left 16
:padding-top 16
:padding-right 34
:padding-bottom 0}}
[react/view {:style {:align-items :center :flex-direction :row :margin-bottom 16}}
[icons/icon :main-icons/info
{:color colors/blue
:container-style {:margin-right 13}}]
[react/text {:style {:typography :title-bold}} title]]
[react/text {:style {:color colors/gray}} content]]))
(def learn-more
{:content learn-more-sheet})
@@ -1,7 +1,6 @@
(ns legacy.status-im.ui.screens.screens
(:require
[legacy.status-im.ui.components.colors :as colors]
[legacy.status-im.ui.screens.about-app.views :as about-app]
[legacy.status-im.ui.screens.advanced-settings.views :as advanced-settings]
[legacy.status-im.ui.screens.appearance.views :as appearance]
[legacy.status-im.ui.screens.backup-settings.view :as backup-settings]
@@ -93,12 +92,6 @@
:insets {:top? platform/android?}}
:component sync-settings/sync-settings}
;; ABOUT
{:name :about-app
:options {:topBar {:visible false}
:insets {:top? platform/android?}}
:component about-app/about-app}
;; STATUS HELP
{:name :help-center
:options {:topBar {:visible false}
@@ -16,7 +16,8 @@
[rn/view {:style (style/loading-container size blur? theme)}]))
(defn- left-subtitle
[{:keys [size subtitle-type subtitle-color icon icon-color blur? subtitle customization-color emoji
[{:keys [size subtitle-text-props subtitle-type subtitle-color icon icon-color blur? subtitle
customization-color emoji
network-image]
:or {subtitle-type :default}}]
(let [theme (quo.theme/use-theme)]
@@ -39,9 +40,10 @@
:style style/image}]
nil)])
[text/text
{:weight :medium
:size :paragraph-2
:style (style/description subtitle-color blur? theme)}
(merge {:weight :medium
:size :paragraph-2
:style (style/description subtitle-color blur? theme)}
subtitle-text-props)
subtitle]
(when (= subtitle-type :editable)
[icons/icon :i/edit
@@ -75,7 +77,8 @@
(defn- left-side
"The description can either be given as a string `subtitle-type` or a component `custom-subtitle`"
[{:keys [title status size blur? custom-subtitle icon subtitle subtitle-type subtitle-color icon-color
[{:keys [title subtitle-text-props status size blur? custom-subtitle icon subtitle subtitle-type
subtitle-color icon-color
customization-color network-image emoji title-icon]
:as props}]
(let [theme (quo.theme/use-theme)]
@@ -94,6 +97,7 @@
[custom-subtitle props]
[left-subtitle
{:theme theme
:subtitle-text-props subtitle-text-props
:size size
:subtitle-type subtitle-type
:subtitle-color subtitle-color
@@ -140,6 +144,7 @@
[:size {:optional true} [:maybe [:enum :default :small :large]]]
[:title :string]
[:subtitle {:optional true} [:maybe [:or :string :double]]]
[:subtitle-text-props {:optional true} [:maybe :map]]
[:custom-subtitle {:optional true} [:maybe fn?]]
[:icon {:optional true} [:maybe :keyword]]
[:title-icon {:optional true} [:maybe :keyword]]
@@ -79,11 +79,11 @@
[rn/view {:style style/community-logo-ring}]])
(defn- description-container
[{:keys [description description-text collection-text community-text
collection-image community-image blur?]
[{:keys [description description-text collection-text community-text blur?
collection-image community-image description-accessibility-label]
context-tag-props :context-tag
summary-props :summary}]
[rn/view
[rn/view {:accessibility-label description-accessibility-label}
(cond
(and (= description :text) (not (string/blank? description-text)))
[text/text
+11 -2
View File
@@ -1,11 +1,20 @@
(ns status-im.common.privacy.view
(:require-macros [legacy.status-im.utils.slurp :refer [slurp]])
(:require [quo.core :as quo]
[react-native.gesture :as gesture]))
[react-native.gesture :as gesture]
[status-im.contexts.settings.common.header :as header]
[utils.i18n :as i18n]))
(def privacy-statement-text (slurp "resources/privacy.mdwn"))
(defn privacy-statement
[]
[gesture/scroll-view {:margin 20}
[gesture/scroll-view {:style {:margin 20}}
[quo/text privacy-statement-text]])
(defn view
[]
[quo/overlay {:type :shell}
[header/view {:title (i18n/label :t/privacy-policy)}]
[gesture/scroll-view {:style {:padding-horizontal 20}}
[quo/text privacy-statement-text]]])
+2
View File
@@ -3,6 +3,8 @@
(def ui
{:add-new-contact (js/require "../resources/images/ui2/add-contact.png")
:biometrics (js/require "../resources/images/ui2/biometrics.png")
:usage-data (js/require "../resources/images/ui2/usage-data.png")
:login-syncing (js/require "../resources/images/ui2/login-syncing.png")
:chat-privately-with-friends (js/require "../resources/images/ui2/chat-privately-with-friends.png")
:desktop-how-to-pair-sign-in (js/require "../resources/images/ui2/desktop-how-to-pair-sign-in.png")
:desktop-how-to-pair-logged-in (js/require
@@ -10,24 +10,43 @@
[utils.re-frame :as rf]
[utils.security.core :as security]))
(rf/reg-fx :effects.keycard/call-on-auth-success
(fn [on-auth-success]
(when on-auth-success (on-auth-success ""))))
(defn- handle-password-success
[has-partially-operable-accounts? on-auth-success masked-password]
(let [on-auth-success-callback #(on-auth-success masked-password)]
(rf/dispatch [:standard-auth/set-success true])
(rf/dispatch [:standard-auth/reset-login-password])
(if has-partially-operable-accounts?
(rf/dispatch [:wallet/make-partially-operable-accounts-fully-operable
{:password masked-password
:on-success on-auth-success-callback
:on-error on-auth-success-callback}])
(on-auth-success-callback))))
(defn authorize
[{:keys [db]} [{:keys [on-auth-success keycard-supported?] :as args}]]
(let [key-uid (get-in db [:profile/profile :key-uid])
keycard? (get-in db [:profile/profile :keycard-pairing])]
[{:keys [db]} [{:keys [on-auth-success] :as args}]]
(let [key-uid (get-in db [:profile/profile :key-uid])
keycard-profile? (get-in db [:profile/profile :keycard-pairing])]
{:fx
[(if keycard?
(if keycard-supported?
[:effects.keycard/call-on-auth-success on-auth-success]
[:effects.utils/show-popup
{:title "This feature is not supported yet "
:content
"Keycard support is limited to logging in
and signing the sending transaction.
Use Status Desktop to access all functions."}])
[(if keycard-profile?
[:dispatch
[:standard-auth/authorize-with-keycard
{:on-complete
(fn [pin]
(rf/dispatch
[:keycard/connect
{:key-uid key-uid
:on-success
(fn []
(rf/dispatch
[:keycard/get-keys
{:pin pin
:on-success (fn [{:keys [encryption-public-key]}]
(rf/dispatch [:keycard/disconnect])
(handle-password-success false
on-auth-success
(security/mask-data encryption-public-key)))
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error
%])}]))}]))}]]
[:effects.biometric/check-if-available
{:key-uid key-uid
:on-success #(rf/dispatch [:standard-auth/authorize-with-biometric args])
@@ -89,21 +108,12 @@
(defn- bottom-sheet-password-view
[{:keys [on-press-biometric on-auth-success auth-button-icon-left auth-button-label]}]
(fn []
(let [has-partially-operable-accounts? (rf/sub [:wallet/has-partially-operable-accounts?])
handle-password-success
(fn [password]
(let [sha3-pwd (security/hash-masked-password password)
on-auth-success-callback #(on-auth-success sha3-pwd)]
(rf/dispatch [:standard-auth/set-success true])
(rf/dispatch [:standard-auth/reset-login-password])
(if has-partially-operable-accounts?
(rf/dispatch [:wallet/make-partially-operable-accounts-fully-operable
{:password sha3-pwd
:on-success on-auth-success-callback
:on-error on-auth-success-callback}])
(on-auth-success-callback))))]
(let [has-partially-operable-accounts? (rf/sub [:wallet/has-partially-operable-accounts?])]
[enter-password/view
{:on-enter-password handle-password-success
{:on-enter-password #(handle-password-success
has-partially-operable-accounts?
on-auth-success
(security/hash-masked-password %))
:on-press-biometrics on-press-biometric
:button-icon-left auth-button-icon-left
:button-label auth-button-label}])))
@@ -9,31 +9,35 @@
(defn view
[{:keys [track-text customization-color auth-button-label on-auth-success on-auth-fail
auth-button-icon-left size blur? container-style disabled? dependencies keycard-supported?]
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 (rn/use-callback
(fn [reset-slider-fn]
(js/setTimeout #(reset-slider-fn false) 500)
(rf/dispatch
[:standard-auth/authorize
{:auth-button-icon-left auth-button-icon-left
:theme theme
:blur? blur?
:keycard-supported? keycard-supported?
: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)))
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)
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])]
[quo/slide-button
{:container-style container-style
:size size
:customization-color customization-color
:on-complete on-complete
:on-complete on-slider-complete
:track-icon (if biometric-auth?
(biometric/get-icon-by-type biometric-type)
:password)
+11 -2
View File
@@ -1,11 +1,20 @@
(ns status-im.common.terms.view
(:require-macros [legacy.status-im.utils.slurp :refer [slurp]])
(:require [quo.core :as quo]
[react-native.gesture :as gesture]))
[react-native.gesture :as gesture]
[status-im.contexts.settings.common.header :as header]
[utils.i18n :as i18n]))
(def terms-of-use-text (slurp "resources/terms-of-use.mdwn"))
(defn terms-of-use
[]
[gesture/scroll-view {:margin 20}
[gesture/scroll-view {:style {:margin 20}}
[quo/text terms-of-use-text]])
(defn view
[]
[quo/overlay {:type :shell}
[header/view {:title (i18n/label :t/terms-of-service)}]
[gesture/scroll-view {:style {:padding-horizontal 20}}
[quo/text terms-of-use-text]]])
+7
View File
@@ -334,6 +334,7 @@
(def ^:const privacy-policy-link "https://status.im/privacy-policy/")
(def ^:const terms-of-service-link "https://status.im/terms-of-use")
(def ^:const create-account-link "https://status.app/help/wallet/create-wallet-accounts")
(def ^:const mobile-upvote-link "https://status-mobile.featureupvote.com")
(def ^:const visibility-status-unknown 0)
(def ^:const visibility-status-automatic 1)
@@ -641,3 +642,9 @@
(def ^:const wallet-connect-transaction-refresh-interval-ms 10000)
(def ^:const native-token-symbol "ETH")
;; About app links
(def ^:const status-app-url "http://status.app")
(def ^:const go-waku-url "https://github.com/waku-org/go-waku")
(def ^:const status-go-url "https://github.com/status-im/status-go")
(def ^:const status-mobile-url "https://github.com/status-im/status-mobile")
@@ -53,7 +53,13 @@
(conj (navigation-event (name view-id)))
(= :screen/onboarding.syncing-results view-id)
(conj (key-value-event "onboarding-completed")))))
(conj (key-value-event "onboarding-completed"))
(= :screen/keycard.migrate.success view-id)
(conj (key-value-event "keycard-migration-succeeded"))
(= :screen/keycard.migrate.fail view-id)
(conj (key-value-event "keycard-migration-failed")))))
(defn navigated-to-collectibles-tab-event
[location]
@@ -11,30 +11,35 @@
[{:keys [contact-id]}]
(let [{:keys [contact-request-state
community-id
chat-name]} (rf/sub [:chats/current-chat-chat-view])
chat-type (rf/sub [:chats/chat-type])
[primary-name _] (if (= chat-type :public-chat)
[(str "#" chat-name) ""]
(rf/sub [:contacts/contact-two-names-by-identity contact-id]))
community-chat? (= chat-type :community-chat)
joined (when community-chat?
(rf/sub [:communities/community-joined community-id]))
pending? (when community-chat?
(rf/sub [:communities/my-pending-request-to-join community-id]))
contact-request-send? (or (not contact-request-state)
(= contact-request-state
constants/contact-request-state-none))
contact-request-received? (= contact-request-state
constants/contact-request-state-received)
contact-request-pending? (= contact-request-state
constants/contact-request-state-sent)]
chat-name]} (rf/sub [:chats/current-chat-chat-view])
chat-type (rf/sub [:chats/chat-type])
[primary-name _] (if (= chat-type :public-chat)
[(str "#" chat-name) ""]
(rf/sub [:contacts/contact-two-names-by-identity contact-id]))
community-chat? (= chat-type :community-chat)
joined (when community-chat?
(rf/sub [:communities/community-joined community-id]))
pending? (when community-chat?
(rf/sub [:communities/my-pending-request-to-join community-id]))
contact-request-send? (or (not contact-request-state)
(= contact-request-state
constants/contact-request-state-none))
contact-request-received? (= contact-request-state
constants/contact-request-state-received)
contact-request-pending? (= contact-request-state
constants/contact-request-state-sent)
keycard? (rf/sub [:keycard/keycard-profile?])
keycard-feature-unavailable (rn/use-callback
#(rf/dispatch [:keycard/feature-unavailable-show]))]
[rn/view {:style style/container}
[quo/permission-context
{:blur? true
:on-press (cond
(and community-chat? (not pending?) (not joined))
#(rf/dispatch [:open-modal :community-account-selection-sheet
{:community-id community-id}])
(if keycard?
keycard-feature-unavailable
#(rf/dispatch [:open-modal :community-account-selection-sheet
{:community-id community-id}]))
(not community-chat?)
#(rf/dispatch [:chat.ui/show-profile contact-id]))
@@ -10,72 +10,73 @@
[status-im.contexts.communities.actions.community-rules.view :as community-rules]
[status-im.contexts.communities.actions.permissions-sheet.view :as permissions-sheet]
[status-im.contexts.communities.utils :as communities.utils]
[status-im.feature-flags :as ff]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn view
[]
(let [theme (quo.theme/use-theme)
{id :community-id} (rf/sub [:get-screen-params])
(let [theme (quo.theme/use-theme)
{id :community-id} (rf/sub [:get-screen-params])
{:keys [name color images joined]} (rf/sub [:communities/community id])
has-permissions? (rf/sub [:communities/has-permissions? id])
airdrop-account (rf/sub [:communities/airdrop-account id])
revealed-accounts (rf/sub [:communities/accounts-to-reveal id])
revealed-accounts-count (count revealed-accounts)
wallet-accounts-count (count (rf/sub [:wallet/operable-accounts]))
addresses-shared-text (if (= revealed-accounts-count wallet-accounts-count)
(i18n/label :t/all-addresses)
(i18n/label-pluralize
revealed-accounts-count
:t/address-count))
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
highest-role-text (i18n/label (communities.utils/role->translation-key
highest-permission-role
:t/member))
can-edit-addresses? (rf/sub [:communities/can-edit-shared-addresses? id])
navigate-back (rn/use-callback #(rf/dispatch [:navigate-back]))
show-addresses-for-permissions
(rn/use-callback
(fn []
(if can-edit-addresses?
(rf/dispatch [:open-modal :addresses-for-permissions {:community-id id}])
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content (fn [] [addresses-for-permissions/view])}])))
[can-edit-addresses?])
show-airdrop-addresses
(rn/use-callback
(fn []
(if can-edit-addresses?
(rf/dispatch [:open-modal :address-for-airdrop {:community-id id}])
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content (fn [] [airdrop-addresses/view])}])))
[can-edit-addresses?])
confirm-choices
(rn/use-callback
(fn []
(rf/dispatch
[:standard-auth/authorize
{:auth-button-label (if can-edit-addresses?
(i18n/label :t/edit-shared-addresses)
(i18n/label :t/request-to-join))
:on-auth-success (fn [password]
(rf/dispatch
[:communities/request-to-join-with-addresses
{:community-id id
:password password}]))}])
(navigate-back))
[can-edit-addresses?])
open-permission-sheet
(rn/use-callback (fn []
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [permissions-sheet/view id])}]))
[id])]
has-permissions? (rf/sub [:communities/has-permissions? id])
airdrop-account (rf/sub [:communities/airdrop-account id])
revealed-accounts (rf/sub [:communities/accounts-to-reveal id])
revealed-accounts-count (count revealed-accounts)
wallet-accounts-count (count (rf/sub [:wallet/operable-accounts]))
addresses-shared-text (if (= revealed-accounts-count wallet-accounts-count)
(i18n/label :t/all-addresses)
(i18n/label-pluralize
revealed-accounts-count
:t/address-count))
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
highest-role-text (i18n/label (communities.utils/role->translation-key
highest-permission-role
:t/member))
can-edit-addresses? (rf/sub [:communities/can-edit-shared-addresses? id])
navigate-back (rn/use-callback #(rf/dispatch [:navigate-back]))
show-addresses-for-permissions (rn/use-callback
(fn []
(if can-edit-addresses?
(rf/dispatch [:open-modal :addresses-for-permissions
{:community-id id}])
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content
addresses-for-permissions/view}])))
[can-edit-addresses?])
show-airdrop-addresses (rn/use-callback
(fn []
(if can-edit-addresses?
(rf/dispatch [:open-modal :address-for-airdrop
{:community-id id}])
(rf/dispatch [:show-bottom-sheet
{:community-id id
:content airdrop-addresses/view}])))
[can-edit-addresses?])
confirm-choices (rn/use-callback
(fn []
(rf/dispatch
[:standard-auth/authorize
{:auth-button-label (if can-edit-addresses?
(i18n/label
:t/edit-shared-addresses)
(i18n/label :t/request-to-join))
:on-auth-success
(fn [password]
(rf/dispatch
[:communities/request-to-join-with-addresses
{:community-id id
:password password}]))}])
(navigate-back))
[can-edit-addresses?])
open-permission-sheet (rn/use-callback
(fn []
(rf/dispatch
[:show-bottom-sheet
{:content (fn []
[permissions-sheet/view id])}]))
[id])]
(rn/use-mount
(fn []
(rf/dispatch [:communities/initialize-permission-addresses id])))
@@ -86,7 +87,7 @@
:icon-name :i/close
:on-press navigate-back
:accessibility-label :back-button}
has-permissions?
(and has-permissions? (ff/enabled? ::ff/community.view-token-requirements))
(assoc :right-side
[{:icon-left :i/unlocked
:on-press open-permission-sheet
@@ -7,6 +7,7 @@
[status-im.constants :as constants]
[status-im.contexts.communities.actions.addresses-for-permissions.style :as style]
[status-im.contexts.communities.actions.permissions-sheet.view :as permissions-sheet]
[status-im.feature-flags :as ff]
[utils.i18n :as i18n]
[utils.money :as money]
[utils.re-frame :as rf]))
@@ -122,23 +123,23 @@
(defn- page-top
[{:keys [community-id identical-choices? can-edit-addresses?]}]
(let [{:keys [name logo color]} (rf/sub [:communities/for-context-tag community-id])
has-permissions? (rf/sub [:communities/has-permissions? community-id])
confirm-discard-changes
(rn/use-callback
(fn []
(if identical-choices?
(rf/dispatch [:dismiss-modal :addresses-for-permissions])
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [confirm-discard-drawer
community-id])}])))
[identical-choices? community-id])
open-permission-sheet
(rn/use-callback (fn []
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [permissions-sheet/view
community-id])}]))
[community-id])]
has-permissions? (rf/sub [:communities/has-permissions? community-id])
confirm-discard-changes (rn/use-callback
(fn []
(if identical-choices?
(rf/dispatch [:dismiss-modal :addresses-for-permissions])
(rf/dispatch [:show-bottom-sheet
{:content (fn []
[confirm-discard-drawer
community-id])}])))
[identical-choices? community-id])
open-permission-sheet (rn/use-callback
(fn []
(rf/dispatch [:show-bottom-sheet
{:content (fn []
[permissions-sheet/view
community-id])}]))
[community-id])]
[:<>
(when can-edit-addresses?
[quo/page-nav
@@ -161,7 +162,7 @@
:community-name name
:community-logo logo
:customization-color color}
has-permissions?
(and has-permissions? (ff/enabled? ::ff/community.view-token-requirements))
(assoc :button-icon :i/info
:button-type :grey
:on-button-press open-permission-sheet))])]))
@@ -40,7 +40,8 @@
:right-icon :i/chevron-right
:accessibility-label :view-token-gating
:on-press #(rf/dispatch [:show-bottom-sheet
{:content (fn [] [permissions-sheet/view id])
{:content (fn []
[permissions-sheet/view id])
:padding-bottom-override 16}])
:label (i18n/label :t/view-token-gating)})
@@ -146,7 +147,9 @@
[{:keys [id join-pending? spectated? token-gated? intro-message test-networks-enabled?]}]
(let [common [(show-qr id) (share-community id)]
specific (cond
(and token-gated? (not test-networks-enabled?))
(and token-gated?
(not test-networks-enabled?)
(ff/enabled? ::ff/community.view-token-requirements))
[(invite-contacts id) (view-token-gating id)]
token-gated?
@@ -172,7 +175,8 @@
[{:keys [id token-gated? muted? muted-till color intro-message]}]
[[(view-members id)
(view-rules id intro-message)
(when token-gated? (view-token-gating id))
(when (and token-gated? (ff/enabled? ::ff/community.view-token-requirements))
(view-token-gating id))
(when (ff/enabled? ::ff/community.edit-account-selection)
(edit-shared-addresses id))
(mark-as-read id)
@@ -27,7 +27,11 @@
(fn []
(let [theme (quo.theme/use-theme)
{:keys [id]} (rf/sub [:get-screen-params])
{:keys [color name images]} (rf/sub [:communities/community id])]
{:keys [color name images]} (rf/sub [:communities/community id])
keycard? (rf/sub [:keycard/keycard-profile?])
keycard-feature-unavailable (rn/use-callback
#(rf/dispatch [:keycard/feature-unavailable-show
{:feature-name :community.request-to-join}]))]
[rn/safe-area-view {:flex 1}
[gesture/scroll-view {:style style/container}
[rn/view style/page-container
@@ -59,7 +63,9 @@
(i18n/label :t/cancel)]
[quo/button
{:accessibility-label :join-community-button
:on-press #(join-community-and-navigate-back id)
:on-press (if keycard?
keycard-feature-unavailable
#(join-community-and-navigate-back id))
:container-style {:flex 1}
:inner-style {:background-color (colors/resolve-color color theme)}}
(i18n/label :t/request-to-join)]]
@@ -106,12 +106,14 @@
[quo/text (i18n/label :t/network-not-supported)])
(defn- request-access-button
[id color]
[id color keycard? keycard-feature-unavailable]
[quo/button
{:on-press (if config/community-accounts-selection-enabled?
#(rf/dispatch [:open-modal :community-account-selection-sheet
{:community-id id}])
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
{:on-press (if keycard?
keycard-feature-unavailable
(if config/community-accounts-selection-enabled?
#(rf/dispatch [:open-modal :community-account-selection-sheet
{:community-id id}])
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}])))
:accessibility-label :show-request-to-join-screen-button
:customization-color color
:container-style {:margin-bottom 12}
@@ -126,27 +128,34 @@
(defn- token-requirements
[{:keys [id color role-permissions?]}]
(let [{:keys [can-request-access? no-member-permission? networks-not-supported?
highest-permission-role
tokens]} (rf/sub [:community/token-gated-overview id])
highest-role-text (i18n/label
(communities.utils/role->translation-key highest-permission-role :t/member))
on-press (rn/use-callback
(fn []
(if config/community-accounts-selection-enabled?
(rf/dispatch [:open-modal :community-account-selection-sheet
{:community-id id}])
(rf/dispatch [:open-modal :community-requests-to-join
{:id id}])))
[id])
on-press-info #(rf/dispatch
[:show-bottom-sheet {:content token-gated-communities-info}])]
(let
[{:keys [can-request-access? no-member-permission? networks-not-supported?
highest-permission-role
tokens]} (rf/sub [:community/token-gated-overview id])
highest-role-text (i18n/label
(communities.utils/role->translation-key highest-permission-role
:t/member))
on-press (rn/use-callback
(fn []
(if config/community-accounts-selection-enabled?
(rf/dispatch [:open-modal :community-account-selection-sheet
{:community-id id}])
(rf/dispatch [:open-modal :community-requests-to-join
{:id id}])))
[id])
on-press-info #(rf/dispatch
[:show-bottom-sheet {:content token-gated-communities-info}])
keycard? (rf/sub [:keycard/keycard-profile?])
keycard-feature-unavailable (rn/use-callback
#(rf/dispatch [:keycard/feature-unavailable-show
{:feature-name :community.request-to-join}]))]
(cond
networks-not-supported?
[network-not-supported]
(or (not role-permissions?) no-member-permission?)
[request-access-button id color]
[request-access-button id color keycard? keycard-feature-unavailable]
:else
[quo/community-token-gating
@@ -154,7 +163,7 @@
:tokens tokens
:community-color color
:satisfied? can-request-access?
:on-press on-press
:on-press (if keycard? keycard-feature-unavailable on-press)
:on-press-info on-press-info}])))
(defn- join-community
+3 -1
View File
@@ -8,7 +8,8 @@
[status-im.contexts.keycard.utils :as keycard.utils]
[status-im.contexts.profile.config :as profile.config]
[utils.hex :as hex]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
(defonce ^:private active-listeners (atom []))
@@ -24,6 +25,7 @@
(reset! active-listeners
[(keycard/on-card-connected #(rf/dispatch [:keycard/on-card-connected]))
(keycard/on-card-disconnected #(rf/dispatch [:keycard/on-card-disconnected]))
(keycard/on-card-new-pairing #(rf/dispatch [:keycard/on-card-new-pairing (transforms/js->clj %)]))
(when platform/ios?
(keycard/on-nfc-user-cancelled #(rf/dispatch [:keycard.ios/on-nfc-user-cancelled])))
(when platform/ios?
+39 -14
View File
@@ -9,7 +9,9 @@
status-im.contexts.keycard.pin.events
status-im.contexts.keycard.sign.events
[status-im.contexts.keycard.utils :as keycard.utils]
utils.datetime))
[utils.address :as address]
utils.datetime
[utils.ethereum.eip.eip55 :as eip55]))
(rf/reg-event-fx :keycard/on-card-connected
(fn [{:keys [db]} _]
@@ -23,21 +25,22 @@
:fx [(when-let [event (get-in db [:keycard :on-card-disconnected-event-vector])]
[:dispatch event])]}))
(rf/reg-event-fx :keycard/on-card-new-pairing
(fn [{:keys [db]} [{:keys [pairing instanceUID]}]]
(when (and instanceUID pairing)
(let [pairings (get-in db [:keycard :pairings])
new-pairings (assoc pairings
instanceUID
{:pairing pairing
:paired-on (utils.datetime/timestamp)})]
{:db (assoc-in db [:keycard :pairings] new-pairings)
:keycard/persist-pairings new-pairings}))))
(rf/reg-event-fx :keycard/on-retrieve-pairings-success
(fn [{:keys [db]} [pairings]]
{:db (assoc-in db [:keycard :pairings] pairings)
:fx [[:effects.keycard/set-pairing-to-keycard pairings]]}))
(rf/reg-event-fx :keycard/update-pairings
(fn [{:keys [db]} [instance-uid pairing]]
(let [pairings (get-in db [:keycard :pairings])
new-pairings (assoc pairings
instance-uid
{:pairing pairing
:paired-on (utils.datetime/timestamp)})]
{:db (assoc-in db [:keycard :pairings] new-pairings)
:keycard/persist-pairings new-pairings})))
(rf/reg-event-fx :keycard/on-action-with-pin-error
(fn [{:keys [db]} [error]]
(let [tag-was-lost? (keycard.utils/tag-lost? (:error error))
@@ -65,6 +68,30 @@
(fn [_ [data]]
{:effects.keycard/export-key data}))
(rf/reg-event-fx :keycard/connect-derive-address-and-add-account
(fn [_ [{:keys [pin derivation-path key-uid account-preferences]}]]
{:fx [[:dispatch
[:keycard/connect
{:key-uid key-uid
:on-success
(fn []
(rf/dispatch
[:keycard/export-key
{:pin pin
:path derivation-path
:on-success (fn [public-key]
(let [derived-account {:public-key (str "0x" public-key)
:address (eip55/address->checksum
(str "0x"
(address/public-key->address
(subs public-key 2))))
:path derivation-path}]
(rf/dispatch [:keycard/disconnect])
(rf/dispatch [:wallet/add-account
(assoc account-preferences :key-uid key-uid)
derived-account])))
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]))}]]]}))
(rf/reg-event-fx :keycard/cancel-connection
(fn [{:keys [db]}]
{:db (update db
@@ -100,10 +127,8 @@
(rf/reg-event-fx :keycard/get-application-info
(fn [_ [{:keys [key-uid on-success on-error]}]]
{:effects.keycard/get-application-info
{:on-success (fn [{:keys [instance-uid new-pairing] :as app-info}]
{:on-success (fn [app-info]
(rf/dispatch [:keycard/update-application-info app-info])
(when (and instance-uid new-pairing)
(rf/dispatch [:keycard/update-pairings instance-uid new-pairing]))
(if-let [error (keycard.utils/validate-application-info key-uid app-info)]
(if on-error
(on-error error)
@@ -0,0 +1,27 @@
(ns status-im.contexts.keycard.feature-unavailable.events
(:require
[status-im.constants :as constants]
[status-im.contexts.keycard.feature-unavailable.view :as feature-unavailable]
[utils.re-frame :as rf]))
(rf/reg-event-fx
:keycard/feature-unavailable-upvote
(fn [_ [{:keys [feature-name]}]]
{:fx [[:dispatch [:open-url constants/mobile-upvote-link]]
[:dispatch
[:centralized-metrics/track
:metric/feature-unavailable-upvote
{:feature-name feature-name}]]]}))
(rf/reg-event-fx
:keycard/feature-unavailable-show
(fn [_ [{:keys [feature-name theme] :as options}]]
{:fx [[:dispatch
[:show-bottom-sheet
{:theme theme
:content (fn []
(feature-unavailable/view options))}]]
[:dispatch
[:centralized-metrics/track
:metric/feature-unavailable
{:feature-name feature-name}]]]}))
@@ -0,0 +1,27 @@
(ns status-im.contexts.keycard.feature-unavailable.view
(:require
[quo.core :as quo]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn on-upvote
[feature-name]
(rf/dispatch [:keycard/feature-unavailable-upvote {:feature-name feature-name}]))
(defn view
[{:keys [feature-name]}]
[:<>
[quo/drawer-top
{:title (i18n/label :t/feature-unavailable)
:description (i18n/label :t/feature-unavailable-for-keycard-description)}]
[quo/information-box
{:type :default
:icon :i/info
:style {:margin-top 8 :margin-horizontal 20}}
[:<>
(i18n/label :t/feature-unavailable-info)
[quo/text
{:style {:text-decoration-line :underline}
:size :paragraph-2
:on-press #(on-upvote feature-name)}
(i18n/label :t/upvote-it)]]]])
@@ -91,7 +91,7 @@
:title (i18n/label :t/log-in-by-syncing)
:subtitle (i18n/label :t/log-in-by-syncing-subtitle)
:accessibility-label :log-in-by-syncing-icon-card
:image (resources/get-image :ethereum-address)
:image (resources/get-image :login-syncing)
:on-press show-check-before-syncing}])
(defn- use-empty-keycard-icon-card
@@ -4,7 +4,7 @@
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.core :as rn]
[status-im.common.terms.view :as terms]
[status-im.common.privacy.view :as privacy]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -26,7 +26,7 @@
[quo/text
{:size :paragraph-2
:weight :bold
:on-press #(rf/dispatch [:show-bottom-sheet {:content terms/terms-of-use :shell? true}])}
:on-press #(rf/dispatch [:show-bottom-sheet {:content privacy/privacy-statement :shell? true}])}
(i18n/label :t/more-details-in-privacy-policy-2)]]])
(defn- bullet-points
@@ -1,4 +1,5 @@
(ns status-im.contexts.onboarding.share-usage.style)
(ns status-im.contexts.onboarding.share-usage.style
(:require [quo.foundations.colors :as colors]))
(def title-container
{:margin-horizontal 20
@@ -16,3 +17,7 @@
[insets]
{:margin 20
:margin-bottom (+ 12 (:bottom insets))})
(def page
{:flex 1
:background-color colors/neutral-100})
@@ -17,35 +17,38 @@
(rf/dispatch [:navigate-to-within-stack [next-screen :screen/onboarding.share-usage]]) ;; Onboarding
(rf/dispatch [:navigate-back]))) ;; Login Screen
(defn- learn-more
[]
(rf/dispatch [:show-bottom-sheet
{:content learn-more-sheet/view
:shell? true}]))
(defn view
[]
(let [insets (safe-area/get-insets)
next-screen (:next-screen (rf/sub [:get-screen-params :screen/onboarding.share-usage]))
share-usage-data (rn/use-callback #(share-usage-data-fn true next-screen))
maybe-later (rn/use-callback #(share-usage-data-fn false next-screen))
learn-more (rn/use-callback #(rf/dispatch [:show-bottom-sheet
{:content learn-more-sheet/view
:shell? true}]))]
[:<>
maybe-later (rn/use-callback #(share-usage-data-fn false next-screen))]
[rn/view {:style style/page}
[quo/page-nav
{:margin-top (:top insets)
:background :blur
:icon-name :i/arrow-left
:icon-name :i/close
:on-press events-helper/navigate-back
:right-side [{:icon-left :i/info
:accessibility-label :learn-more
:label (i18n/label :t/learn-more)
:on-press learn-more}]}]
[quo/text-combinations
{:container-style style/title-container
:title (i18n/label :t/help-us-improve-status)
[quo/page-top
{:title (i18n/label :t/help-us-improve-status)
:title-accessibility-label :share-usage-title
:description (i18n/label :t/collecting-usage-data)
:description :text
:description-text (i18n/label :t/collecting-usage-data)
:description-accessibility-label :share-usage-subtitle}]
[rn/image
{:resize-mode :contain
:style (style/page-illustration (:width (rn/get-window)))
:source (resources/get-image :biometrics)}]
:source (resources/get-image :usage-data)}]
[rn/view {:style (style/buttons insets)}
[quo/button
{:size 40
@@ -47,7 +47,8 @@
settings
{:log-level log-level}))
(assoc-in [:activity-center :loading?] true)
(dissoc :centralized-metrics/onboarding-enabled?))]
(dissoc :centralized-metrics/onboarding-enabled?))
keycard? (get-in new-db [:profile/profile :keycard-pairing])]
{:db (cond-> new-db
pairing-completed? (dissoc :syncing))
:fx (into [[:json-rpc/call
@@ -75,8 +76,10 @@
[:effects.chat/open-last-chat (:key-uid profile-overview)])
(when (:centralized-metrics/onboarding-enabled? db)
[:dispatch [:profile.settings/toggle-telemetry true]])]
[:dispatch [:profile.settings/toggle-telemetry true]])
(when keycard?
[:dispatch [:centralized-metrics/track :metric/keycard-login]])]
(cond
pairing-completed?
[[:dispatch [:update-theme-and-init-root :screen/onboarding.syncing-results]]]
@@ -125,7 +125,7 @@
:blur? true
:image-props :i/light})]
[{:title (i18n/label :t/about)
:on-press #(rf/dispatch [:open-modal :about-app])
:on-press #(rf/dispatch [:open-modal :screen/settings.about])
:action :arrow
:blur? true}
{:title (i18n/label :t/status-help)
@@ -7,33 +7,39 @@
[utils.re-frame :as rf]))
(defn- on-press-biometric-enable
[button-label theme]
[button-label theme keycard-profile?]
(fn []
(rf/dispatch
[:standard-auth/authorize-with-password
{:blur? true
:theme theme
:auth-button-label (i18n/label :t/biometric-enable-button {:bio-type-label button-label})
:on-auth-success (fn [password]
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch
[:biometric/authenticate
{:on-success #(rf/dispatch [:biometric/enable password])
:on-fail #(rf/dispatch [:biometric/show-message (ex-cause %)])}]))}])))
(if keycard-profile?
(rf/dispatch [:keycard/feature-unavailable-show
{:theme :dark
:feature-name :settings.enable-biometrics}])
(rf/dispatch
[:standard-auth/authorize-with-password
{:blur? true
:theme theme
:auth-button-label (i18n/label :t/biometric-enable-button {:bio-type-label button-label})
:on-auth-success (fn [password]
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch
[:biometric/authenticate
{:on-success #(rf/dispatch [:biometric/enable password])
:on-fail #(rf/dispatch [:biometric/show-message
(ex-cause %)])}]))}]))))
(defn- get-biometric-item
[theme]
(let [auth-method (rf/sub [:auth-method])
biometric-type (rf/sub [:biometrics/supported-type])
label (biometric/get-label-by-type biometric-type)
icon (biometric/get-icon-by-type biometric-type)
supported? (boolean biometric-type)
enabled? (= auth-method constants/auth-method-biometric)
biometric-on? (and supported? enabled?)
press-handler (when supported?
(if biometric-on?
(fn [] (rf/dispatch [:biometric/disable]))
(on-press-biometric-enable label theme)))]
(let [auth-method (rf/sub [:auth-method])
biometric-type (rf/sub [:biometrics/supported-type])
keycard-profile? (rf/sub [:keycard/keycard-profile?])
label (biometric/get-label-by-type biometric-type)
icon (biometric/get-icon-by-type biometric-type)
supported? (boolean biometric-type)
enabled? (= auth-method constants/auth-method-biometric)
biometric-on? (and supported? enabled?)
press-handler (when supported?
(if biometric-on?
(fn [] (rf/dispatch [:biometric/disable]))
(on-press-biometric-enable label theme keycard-profile?)))]
{:title label
:image-props icon
:image :icon
@@ -58,7 +64,8 @@
(defn view
[]
(let [theme (quo.theme/use-theme)]
(let [theme (quo.theme/use-theme)
keycard-profile? (rf/sub [:keycard/keycard-profile?])]
[quo/overlay {:type :shell :top-inset? true}
[quo/page-nav
{:background :blur
@@ -68,6 +75,7 @@
[quo/category
{:key :category
:data [(get-biometric-item theme)
(get-change-password-item)]
(when-not keycard-profile?
(get-change-password-item))]
:blur? true
:list-type :settings}]]))
@@ -0,0 +1,9 @@
(ns status-im.contexts.settings.about.style)
(def category-spacing {:padding-bottom 12})
(def app-info-container
{:padding-horizontal 20
:padding-top 8
:padding-bottom 16
:row-gap 16})
@@ -0,0 +1,101 @@
(ns status-im.contexts.settings.about.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.constants :as constants]
[status-im.contexts.settings.about.style :as style]
[status-im.contexts.settings.common.header :as header]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- open-link
[url]
(rf/dispatch [:browser.ui/open-url url]))
(defn- copy
[data item-name]
(rf/dispatch [:share/copy-text-and-show-toast
{:text-to-copy data
:post-copy-message (str item-name
" "
(i18n/label :t/sharing-copied-to-clipboard))}]))
(def about-data
[{:app-info? true}
{:category-label (i18n/label :t/website)
:items [{:title "status.app"
:on-press #(open-link constants/status-app-url)
:blur? true
:action :arrow
:action-props {:icon :i/external}}]}
{:category-label (i18n/label :t/github-repos)
:items [{:title "status-mobile"
:on-press #(open-link constants/status-mobile-url)
:blur? true
:action :arrow
:action-props {:icon :i/external}}
{:title "status-go"
:on-press #(open-link constants/status-go-url)
:blur? true
:action :arrow
:action-props {:icon :i/external}}
{:title "go-waku"
:on-press #(open-link constants/go-waku-url)
:blur? true
:action :arrow
:action-props {:icon :i/external}}]}
{:category-label (i18n/label :t/documents)
:items [{:title (i18n/label :t/privacy-policy)
:on-press #(rf/dispatch [:open-modal :screen/settings.privacy-policy])
:blur? true
:action :arrow}
{:title (i18n/label :t/terms-of-service)
:on-press #(rf/dispatch [:open-modal :screen/settings.terms-of-use])
:blur? true
:action :arrow}]}])
(defn info-item
[{:keys [title info]}]
[quo/data-item
{:size :default
:status :default
:right-icon :i/copy
:card? true
:blur? true
:title title
:on-press #(copy info title)
:subtitle info
:subtitle-type :default
:subtitle-text-props {:number-of-lines 1
:ellipsize-mode :middle}}])
(defn- app-info
[]
(let [app-version (rf/sub [:get-app-short-version])
commit-hash (rf/sub [:get-commit-hash])
node-version (rf/sub [:get-app-node-version])]
[rn/view {:style style/app-info-container}
[info-item {:title (i18n/label :t/version) :info app-version}]
[info-item {:title (i18n/label :t/app-commit) :info commit-hash}]
[info-item {:title (i18n/label :t/node-version) :info node-version}]]))
(defn category
[{:keys [app-info? category-label items]}]
(if app-info?
[app-info]
[quo/category
{:label category-label
:list-type :settings
:container-style style/category-spacing
:blur? true
:data items}]))
(defn view
[]
[quo/overlay {:type :shell}
[header/view {:title (i18n/label :t/about)}]
[rn/flat-list
{:data about-data
:shows-vertical-scroll-indicator false
:render-fn category
:bounces false
:over-scroll-mode :never}]])
@@ -0,0 +1,14 @@
(ns status-im.contexts.settings.common.header
(:require [quo.core :as quo]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.common.events-helper :as events-helper]))
(defn view
[{:keys [title]}]
[rn/view {:style {:padding-top (safe-area/get-top)}}
[quo/page-nav
{:background :blur
:icon-name :i/arrow-left
:on-press events-helper/navigate-back}]
[quo/page-top {:title title}]])
@@ -41,7 +41,7 @@
(defn- keypair
[{keypair-type :type
:keys [accounts name]
:keys [accounts name keycard?]
:as item}
_ _
{:keys [profile-picture compressed-key customization-color]}]
@@ -59,7 +59,7 @@
:type (if default-keypair?
:default-keypair
:keypair)
:stored :on-device
:stored (if keycard? :on-keycard :on-device)
:shortened-key shortened-key
:customization-color customization-color
:profile-picture profile-picture})}))
@@ -68,7 +68,7 @@
[quo/keypair
{:blur? true
:status-indicator false
:stored :on-device
:stored (if keycard? :on-keycard :on-device)
:action (if default-keypair? :none :options)
:accounts accounts
:customization-color customization-color
@@ -10,7 +10,6 @@
[status-im.feature-flags :as ff]
[utils.address :as utils-address]
[utils.debounce :as debounce]
[utils.ethereum.eip.eip681 :as eip681]
[utils.i18n :as i18n]
[utils.url :as url]))
@@ -28,13 +27,6 @@
(let [index (string/index-of scanned-text "#")]
(subs scanned-text (inc index))))
(defn eip681-address?
[scanned-text]
(-> scanned-text
eip681/parse-uri
:address
boolean))
(defn pairing-qr-code?
[_]
false)
@@ -88,10 +80,10 @@
(debounce/debounce-and-dispatch [:generic-scanner/scan-success address] 300)
(debounce/debounce-and-dispatch [:shell/change-tab :wallet-stack] 300))
(eip681-address? scanned-text)
(utils-address/eip-681-address? scanned-text)
(do
(debounce/debounce-and-dispatch [:wallet-legacy/request-uri-parsed
(eip681/parse-uri scanned-text)]
(debounce/debounce-and-dispatch [:generic-scanner/scan-success
(utils-address/eip-681-address->eth-address scanned-text)]
300)
(debounce/debounce-and-dispatch [:shell/change-tab :wallet-stack] 300))
@@ -38,7 +38,13 @@
#(if (:enabled? %)
:paired-devices
:unpaired-devices)
other-devices)]
other-devices)
keycard? (rf/sub [:keycard/keycard-profile?])
keycard-feature-unavailable (rn/use-callback
#(rf/dispatch
[:keycard/feature-unavailable-show
{:theme :dark
:feature-name :settings.setup-syncing}]))]
[quo/overlay {:type :shell :top-inset? true}
[quo/page-nav
{:type :no-title
@@ -60,7 +66,9 @@
:type :primary
:customization-color profile-color
:icon-only? true
:on-press open-setup-syncing-with-customization-color}
:on-press (if keycard?
keycard-feature-unavailable
open-setup-syncing-with-customization-color)}
:i/add]]
[device/view (merge user-device {:this-device? true})]
(when (seq paired-devices)
@@ -69,7 +69,9 @@
(let [{:keys [customization-color] :as profile} (rf/sub [:profile/profile-with-image])
{:keys [address path watch-only?]} (rf/sub [:wallet/current-viewing-account])
{keypair-name :name
keypair-type :type} (rf/sub [:wallet/current-viewing-account-keypair])
keypair-type :type
keycards :keycards} (rf/sub [:wallet/current-viewing-account-keypair])
keypair-keycard? (boolean (seq keycards))
networks (rf/sub [:wallet/network-preference-details])
origin-type (case keypair-type
:seed
@@ -98,7 +100,7 @@
(when (not watch-only?)
[quo/account-origin
{:type origin-type
:stored :on-device
:stored (if keypair-keycard? :on-keycard :on-device)
:profile-picture (profile.utils/photo profile)
:customization-color customization-color
:derivation-path path
@@ -58,13 +58,14 @@
[item _ _
{:keys [profile-picture compressed-key selected-key-uid set-selected-key-uid customization-color]}]
(let [profile-keypair? (= (:type item) :profile)
keycard? (boolean (seq (:keycards item)))
accounts (parse-accounts (:accounts item))]
[quo/keypair
{:customization-color customization-color
:profile-picture (when profile-keypair? profile-picture)
:status-indicator false
:type (if profile-keypair? :default-keypair :other)
:stored :on-device
:stored (if keycard? :on-keycard :on-device)
:on-options-press #(js/alert "Options pressed")
:action :selector
:blur? false
@@ -22,7 +22,7 @@
[utils.string]))
(defn- get-keypair-data
[{:keys [title primary-keypair? new-keypair? derivation-path customization-color]}]
[{:keys [title primary-keypair? new-keypair? derivation-path customization-color keycard?]}]
[{:title title
:image (if primary-keypair? :avatar :icon)
:image-props (if primary-keypair?
@@ -35,7 +35,7 @@
:button-text (i18n/label :t/edit)
:alignment :flex-start}
:description :text
:description-props {:text (i18n/label :t/on-device)}}
:description-props {:text (i18n/label (if keycard? :on-keycard :on-device))}}
(when-not (string/blank? derivation-path)
(let [formatted-path (string/replace derivation-path #"/" " / ")
on-auth-success (fn [password]
@@ -123,7 +123,7 @@
:container-style color-picker-style}]])])))
(defn- new-account-origin
[{:keys [keypair-title derivation-path customization-color]}]
[{:keys [keypair-title derivation-path customization-color keycard?]}]
(let [{keypair-name :name} (rf/sub [:wallet/selected-keypair])
primary? (rf/sub [:wallet/selected-primary-keypair?])
keypair-name (or keypair-title
@@ -135,7 +135,8 @@
[quo/category
{:list-type :settings
:label (i18n/label :t/origin)
:data (get-keypair-data {:primary-keypair? primary?
:data (get-keypair-data {:keycard? keycard?
:primary-keypair? primary?
:title keypair-name
:derivation-path derivation-path
:customization-color customization-color})}]]))
@@ -229,20 +230,37 @@
set-derivation-path #(reset! derivation-path %)]
(fn [{:keys [on-change-text set-account-color set-emoji customization-color error]}]
(let [{:keys [derived-from
key-uid]} (rf/sub [:wallet/selected-keypair])
on-auth-success (rn/use-callback
(fn [password]
(let [preferences {:account-name @account-name
:color @account-color
:emoji @emoji}]
(rf/dispatch
[:wallet/derive-address-and-add-account
{:password password
:derived-from-address derived-from
:key-uid key-uid
:derivation-path @derivation-path
:account-preferences preferences}])))
[derived-from])]
key-uid keycards]} (rf/sub [:wallet/selected-keypair])
keycard? (boolean (seq keycards))
on-auth-success (rn/use-callback
(fn [password]
(let [preferences {:account-name @account-name
:color @account-color
:emoji @emoji}]
(rf/dispatch
[:wallet/derive-address-and-add-account
{:password password
:derived-from-address derived-from
:key-uid key-uid
:derivation-path @derivation-path
:account-preferences preferences}])))
[derived-from])
on-complete (rn/use-callback
(fn []
(let [preferences {:account-name @account-name
:color @account-color
:emoji @emoji}]
(rf/dispatch
[:standard-auth/authorize-with-keycard
{:on-complete
#(rf/dispatch
[:keycard/connect-derive-address-and-add-account
{:pin %
:derived-from-address derived-from
:key-uid key-uid
:derivation-path @derivation-path
:account-preferences preferences}])}])))
[derived-from])]
(rn/use-effect
#(rf/dispatch
[:wallet/next-derivation-path
@@ -252,10 +270,13 @@
[floating-button
{:account-color @account-color
:slide-button-props {:on-auth-success on-auth-success
:disabled? (or (empty? @account-name)
(string/blank? @derivation-path)
(some? error))}}
:slide-button-props {:on-auth-success (when-not keycard? on-auth-success)
:on-complete
(when keycard? on-complete)
:disabled?
(or (empty? @account-name)
(string/blank? @derivation-path)
(some? error))}}
[avatar
{:account-color @account-color
:emoji @emoji
@@ -269,7 +290,8 @@
{:account-color @account-color
:set-account-color set-account-color}]
[new-account-origin
{:derivation-path @derivation-path
{:keycard? keycard?
:derivation-path @derivation-path
:customization-color customization-color}]]))))
(defn view
@@ -30,7 +30,8 @@
type :no-title}}]
(let [{:keys [color emoji watch-only?]} (rf/sub [:wallet/current-viewing-account])
networks (rf/sub [:wallet/selected-network-details])
sending-collectible? (rf/sub [:wallet/sending-collectible?])]
sending-collectible? (rf/sub [:wallet/sending-collectible?])
keycard? (rf/sub [:wallet/selected-keypair-keycard?])]
[quo/page-nav
{:type type
:icon-name icon-name
@@ -45,7 +46,11 @@
(not watch-only?)
show-dapps-button?)
{:icon-name :i/dapps
:on-press #(rf/dispatch [:navigate-to :screen/wallet.connected-dapps])})
:on-press #(rf/dispatch
(if keycard?
[:keycard/feature-unavailable-show
{:feature-name :wallet.show-connected-dapps}]
[:navigate-to :screen/wallet.connected-dapps]))})
(when-not sending-collectible?
{:content-type :account-switcher
:customization-color color
@@ -13,7 +13,7 @@
{:title (i18n/label :t/scan-qr)
:subtitle (i18n/label :t/scan-an-address-qr-code)
:error-message (i18n/label :t/oops-this-qr-does-not-contain-an-address)
:validate-fn #(utils-address/supported-address? %)
:validate-fn #(utils-address/supported-scan-address? %)
:on-success-scan (fn [result]
(let [address (utils-address/supported-address->eth-address result)]
(when on-result (on-result address))
@@ -291,3 +291,10 @@
(cske/transform-keys transforms/->kebab-case-keyword)
(map #(assoc % :unique-id (collectible-utils/get-collectible-unique-id %)))
vec))
(defn selected-keypair-keycard?
[db]
(let [keypairs (get-in db [:wallet :keypairs])
selected-keypair-uid (get-in db [:wallet :ui :create-account :selected-keypair-uid])
keypair (get keypairs selected-keypair-uid)]
(boolean (seq (:keycards keypair)))))
@@ -231,3 +231,37 @@
:wallet true
:default-account? true})]}}}
(sut/reconcile-keypairs [raw-keypair-profile])))))
(def mock-db
{:wallet {:keypairs
{"0x123" {:type "key"
:key-uid "0x123"
:keycards [{:id "keycard1"}]}
"0x456" {:type "key"
:key-uid "0x456"
:keycards []}}
:ui {:create-account {:selected-keypair-uid "0x123"}}}})
(deftest selected-keypair-keycard?-test
(testing "returns true when the selected keypair has keycards"
(is (true? (sut/selected-keypair-keycard? mock-db))))
(testing "returns false when the selected keypair does not have keycards"
(let [db (assoc-in mock-db [:wallet :ui :create-account :selected-keypair-uid] "0x456")]
(is (false? (sut/selected-keypair-keycard? db)))))
(testing "returns false when the selected keypair does not exist"
(let [db (assoc-in mock-db [:wallet :ui :create-account :selected-keypair-uid] "0x789")]
(is (false? (sut/selected-keypair-keycard? db)))))
(testing "returns false when keypairs map is empty"
(let [db (assoc-in mock-db [:wallet :keypairs] {})]
(is (false? (sut/selected-keypair-keycard? db)))))
(testing "returns false when no keypair is selected"
(let [db (assoc-in mock-db [:wallet :ui :create-account :selected-keypair-uid] nil)]
(is (false? (sut/selected-keypair-keycard? db)))))
(testing "returns false when db does not contain wallet data"
(let [db {}]
(is (false? (sut/selected-keypair-keycard? db))))))
+38 -26
View File
@@ -114,7 +114,7 @@
(rf/reg-event-fx
:wallet/fetch-assets-for-address
(fn [_ [address]]
{:fx [[:dispatch [:wallet/get-wallet-token-for-account address]]
{:fx [[:dispatch [:wallet/get-wallet-token-for-accounts [address]]]
[:dispatch [:wallet/request-collectibles-for-account address]]]}))
(defn- reconcile-accounts
@@ -204,34 +204,42 @@
(rf/reg-event-fx :wallet/get-wallet-token-for-all-accounts
(fn [{:keys [db]}]
{:fx (->> (get-in db [:wallet :accounts])
vals
(mapv
(fn [{:keys [address]}]
[:dispatch [:wallet/get-wallet-token-for-account address]])))}))
(let [addresses (->> (get-in db [:wallet :accounts])
(vals)
(keep :address)
(vec))]
{:fx [[:dispatch [:wallet/get-wallet-token-for-accounts addresses]]]})))
(rf/reg-event-fx :wallet/get-wallet-token-for-account
(fn [{:keys [db]} [address]]
{:db (assoc-in db [:wallet :ui :tokens-loading address] true)
(rf/reg-event-fx :wallet/get-wallet-token-for-accounts
(fn [{:keys [db]} [addresses]]
{:db (reduce
(fn [db address]
(assoc-in db [:wallet :ui :tokens-loading address] true))
db
addresses)
:fx [[:json-rpc/call
[{:method "wallet_fetchOrGetCachedWalletBalances"
:params [[address] true]
:on-success [:wallet/store-wallet-token address]
:on-error [:wallet/get-wallet-token-for-account-failed address]}]]]}))
:params [addresses true]
:on-success [:wallet/store-wallet-token addresses]
:on-error [:wallet/get-wallet-token-for-accounts-failed addresses]}]]]}))
(rf/reg-event-fx
:wallet/get-wallet-token-for-account-failed
(fn [{:keys [db]} [address error]]
:wallet/get-wallet-token-for-accounts-failed
(fn [{:keys [db]} [addresses error]]
(log/info "failed to get wallet token "
{:error error
:event :wallet/get-wallet-token-for-account
:params address})
:event :wallet/get-wallet-token-for-accounts
:params addresses})
{:fx [[:dispatch [:wallet/get-last-wallet-token-update-if-needed]]]
:db (assoc-in db [:wallet :ui :tokens-loading address] false)}))
:db (reduce
(fn [db address]
(assoc-in db [:wallet :ui :tokens-loading address] false))
db
addresses)}))
(rf/reg-event-fx
:wallet/store-wallet-token
(fn [{:keys [db]} [address raw-tokens-data]]
(fn [{:keys [db]} [addresses raw-tokens-data]]
(let [supported-chains-by-token-symbol (get-in db [:wallet :tokens :supported-chains-by-symbol])
profile-currency (get-in db [:profile/profile :currency])
tokens (data-store/rpc->tokens raw-tokens-data
@@ -244,13 +252,18 @@
accounts))
stored-accounts
tokens-per-account))
symbols (reduce-kv (fn [acc _ v]
(into acc (map :symbol v)))
#{}
tokens)]
symbols (reduce-kv
(fn [acc _ tokens-data]
(into acc (map :symbol tokens-data)))
#{}
tokens)]
{:db (-> db
(update-in [:wallet :accounts] add-tokens tokens)
(assoc-in [:wallet :ui :tokens-loading address] false))
((fn [db]
(reduce (fn [db address]
(assoc-in db [:wallet :ui :tokens-loading address] false))
db
addresses))))
:fx [[:dispatch [:wallet/get-last-wallet-token-update-if-needed]]
[:effects.wallet.tokens/fetch-market-values
{:symbols symbols
@@ -307,9 +320,8 @@
(rf/reg-event-fx :wallet/add-account
(fn [_
[{:keys [key-uid password account-name emoji color type]
:or {type :generated}}
{:keys [public-key address path] :as _derived-account}]]
[{:keys [key-uid password account-name emoji color type] :or {type :generated}}
{:keys [public-key address path]}]]
(let [lowercase-address (some-> address
string/lower-case)
account-config {:key-uid (when (= type :generated) key-uid)
@@ -116,20 +116,19 @@
address-2 "0x2"]
(reset! rf-db/app-db {:wallet {:accounts {address-1 {:address address-1}
address-2 {:address address-2}}}})
(is (match? [[:dispatch [:wallet/get-wallet-token-for-account address-1]]
[:dispatch [:wallet/get-wallet-token-for-account address-2]]]
(is (match? [[:dispatch [:wallet/get-wallet-token-for-accounts [address-1 address-2]]]]
(:fx (dispatch [event-id]))))))
(h/deftest-event :wallet/get-wallet-token-for-account
(h/deftest-event :wallet/get-wallet-token-for-accounts
[event-id dispatch]
(let [expected-effects {:db {:wallet {:ui {:tokens-loading {address true}}}}
:fx [[:json-rpc/call
[{:method "wallet_fetchOrGetCachedWalletBalances"
:params [[address] true]
:on-success [:wallet/store-wallet-token address]
:on-error [:wallet/get-wallet-token-for-account-failed
address]}]]]}]
(is (match? expected-effects (dispatch [event-id address])))))
:on-success [:wallet/store-wallet-token [address]]
:on-error [:wallet/get-wallet-token-for-accounts-failed
[address]]}]]]}]
(is (match? expected-effects (dispatch [event-id [address]])))))
(h/deftest-event :wallet/reconcile-keypairs
[event-id dispatch]
+18 -13
View File
@@ -15,19 +15,24 @@
(defn new-account
[]
[quo/action-drawer
[[{:icon :i/add
:accessibility-label :start-a-new-chat
:label (i18n/label :t/add-account)
:sub-label (i18n/label :t/add-account-description)
:on-press #(rf/dispatch [:navigate-to :screen/wallet.create-account])}
(when (ff/enabled? ::ff/wallet.add-watched-address)
{:icon :i/reveal
:accessibility-label :add-a-contact
:label (i18n/label :t/add-address-to-watch)
:sub-label (i18n/label :t/add-address-to-watch-description)
:on-press #(rf/dispatch [:navigate-to :screen/wallet.add-address-to-watch])
:add-divider? true})]]])
(let [keycard? (rf/sub [:keycard/keycard-profile?])]
[quo/action-drawer
[[{:icon :i/add
:accessibility-label :start-a-new-chat
:label (i18n/label :t/add-account)
:sub-label (i18n/label :t/add-account-description)
:on-press (fn []
(if keycard?
(rf/dispatch [:keycard/feature-unavailable-show
{:feature-name :wallet.new-account}])
(rf/dispatch [:navigate-to :screen/wallet.create-account])))}
(when (ff/enabled? ::ff/wallet.add-watched-address)
{:icon :i/reveal
:accessibility-label :add-a-contact
:label (i18n/label :t/add-address-to-watch)
:sub-label (i18n/label :t/add-address-to-watch-description)
:on-press #(rf/dispatch [:navigate-to :screen/wallet.add-address-to-watch])
:add-divider? true})]]]))
(defn- new-account-card-data
[]
@@ -102,6 +102,7 @@
:wallet/wallet-send-tx-type :tx/send
:wallet/wallet-send-fee-fiat-formatted "$5,00"
:wallet/sending-collectible? false
:wallet/selected-keypair-keycard? false
:wallet/send-total-amount-formatted "250 ETH"
:wallet/total-amount (money/bignumber "250")
:wallet/prices-per-token {:ETH {:usd 10}}
@@ -248,7 +248,9 @@
account))}
user-props {:full-name to-address
:address (utils/get-shortened-address
to-address)}]
to-address)}
sign-on-keycard? (get-in transaction-for-signing
[:signingDetails :signOnKeycard])]
;; In token send flow we already have transaction built when
;; we reach confirmation screen. But in send collectible flow
;; routes request happens at the same time with navigation to
@@ -279,20 +281,24 @@
:transaction-type transaction-type}]
(when (and (not loading-suggested-routes?) route (seq route))
[standard-auth/slide-button
{:keycard-supported? true
:size :size-48
{:size :size-48
:track-text (if (= transaction-type :tx/bridge)
(i18n/label :t/slide-to-bridge)
(i18n/label :t/slide-to-send))
:container-style {:z-index 2}
:disabled? (not transaction-for-signing)
:customization-color account-color
:auth-button-label (i18n/label :t/confirm)
:on-complete (when sign-on-keycard?
#(rf/dispatch
[:wallet/prepare-signatures-for-transactions
:send
""]))
:on-auth-success
(fn [data]
(fn [psw]
(rf/dispatch
[:wallet/prepare-signatures-for-transactions
:send data]))
:auth-button-label (i18n/label :t/confirm)}])]
[:wallet/prepare-signatures-for-transactions :send
psw]))}])]
:gradient-cover? true
:customization-color (:color account)}
[rn/view
@@ -217,18 +217,23 @@
(defn- slide-button
[]
(let [loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
swap-proposal (rf/sub [:wallet/swap-proposal-without-fees])
account (rf/sub [:wallet/current-viewing-account])
on-auth-success (rn/use-callback
#(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap %]))]
(let [loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
swap-proposal (rf/sub [:wallet/swap-proposal-without-fees])
account (rf/sub [:wallet/current-viewing-account])
transaction-for-signing (rf/sub [:wallet/swap-transaction-for-signing])
sign-on-keycard? (get-in transaction-for-signing
[:signingDetails :signOnKeycard])
on-auth-success (rn/use-callback
#(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap %]))
on-complete (rn/use-callback
#(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap ""]))]
[standard-auth/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-sign)
:container-style {:z-index 2}
:customization-color (:color account)
:disabled? (or loading-swap-proposal? (not swap-proposal))
:keycard-supported? true
:on-complete (when sign-on-keycard? on-complete)
:on-auth-success on-auth-success
:auth-button-label (i18n/label :t/confirm)}]))
@@ -168,7 +168,9 @@
transaction-for-signing (rf/sub [:wallet/swap-transaction-for-signing])
swap-proposal (rf/sub [:wallet/swap-proposal-without-fees])
account (rf/sub [:wallet/current-viewing-account])
account-color (:color account)]
account-color (:color account)
sign-on-keycard? (get-in transaction-for-signing
[:signingDetails :signOnKeycard])]
[standard-auth/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-swap)
@@ -178,7 +180,11 @@
(not swap-proposal)
(not transaction-for-signing))
:auth-button-label (i18n/label :t/confirm)
:keycard-supported? true
:on-complete (when sign-on-keycard?
#(rf/dispatch
[:wallet/prepare-signatures-for-transactions
:swap
""]))
:on-auth-success (fn [data]
(rf/dispatch [:wallet/stop-get-swap-proposal])
(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap data]))}]))
@@ -2,6 +2,7 @@
(:require [clojure.string :as string]
[re-frame.core :as rf]
[react-native.wallet-connect :as wallet-connect]
[status-im.contexts.wallet.data-store :as wallet-data-store]
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
data-store]
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
@@ -30,11 +31,19 @@
expired? (-> parsed-uri
:expiryTimestamp
uri/timestamp-expired?)
version-supported? (uri/version-supported? version)]
(if (or (not valid-wc-uri?)
(not version-supported?)
(= network-status :offline)
expired?)
version-supported? (uri/version-supported? version)
keycard? (wallet-data-store/selected-keypair-keycard? db)]
(cond
keycard?
{:fx [[:dispatch
[:keycard/feature-unavailable-show
{:feature-name :wallet.scan-dapp-connection}]]]}
(or (not valid-wc-uri?)
(not version-supported?)
(= network-status :offline)
expired?)
{:fx [[:dispatch
[:toasts/upsert
{:type :negative
@@ -54,6 +63,8 @@
:else
(i18n/label :t/something-went-wrong))}]]]}
:else
{:fx [[:dispatch [:wallet-connect/pair scanned-text]]]}))))
(rf/reg-event-fx
+1
View File
@@ -27,6 +27,7 @@
status-im.contexts.contact.blocking.events
status-im.contexts.keycard.effects
status-im.contexts.keycard.events
status-im.contexts.keycard.feature-unavailable.events
status-im.contexts.network.effects
status-im.contexts.network.events
status-im.contexts.onboarding.common.overlay.events
+2 -2
View File
@@ -11,13 +11,13 @@
(def ^:private initial-flags
{::community.edit-account-selection (enabled-in-env? :FLAG_EDIT_ACCOUNT_SELECTION_ENABLED)
::community.view-token-requirements (enabled-in-env? :FLAG_VIEW_TOKEN_REQUIREMENTS)
;; Feature toggled (off by default) because the desktop app disabled this
;; feature and we want both clients in sync. We keep the code because it
;; works and we may re-enable it by default.
::profile-pictures-visibility (enabled-in-env? :FLAG_PROFILE_PICTURES_VISIBILITY_ENABLED)
::settings.import-all-keypairs (enabled-in-env?
:FLAG_WALLET_SETTINGS_IMPORT_ALL_KEYPAIRS)
::settings.import-all-keypairs (enabled-in-env? :FLAG_WALLET_SETTINGS_IMPORT_ALL_KEYPAIRS)
::wallet.add-watched-address (enabled-in-env? :FLAG_ADD_WATCHED_ADDRESS)
::wallet.advanced-sending (enabled-in-env? :FLAG_ADVANCED_SENDING)
::wallet.assets-modal-hide (enabled-in-env? :FLAG_ASSETS_MODAL_HIDE)
+9 -10
View File
@@ -25,16 +25,15 @@
(defn root-options
[{:keys [background-color theme status-bar-theme nav-bar-color]}]
(merge
(statusbar-and-navbar-options theme status-bar-theme nav-bar-color)
{:topBar {:visible false}
:layout {:componentBackgroundColor (or background-color
(colors/theme-colors colors/white colors/neutral-100 theme))
:orientation ["portrait"]
:backgroundColor (or background-color
(colors/theme-colors colors/white
colors/neutral-100
theme))}}))
(let [layout-background (or background-color
(colors/theme-colors colors/white colors/neutral-100 theme))
component-background (or background-color
(colors/theme-colors colors/white colors/neutral-100 theme))]
(assoc (statusbar-and-navbar-options theme status-bar-theme nav-bar-color)
:topBar {:visible false}
:layout {:componentBackgroundColor component-background
:orientation ["portrait"]
:backgroundColor layout-background})))
(defn dark-root-options
[]
+84 -68
View File
@@ -6,6 +6,8 @@
[status-im.common.enter-seed-phrase.view :as enter-seed-phrase]
[status-im.common.lightbox.view :as lightbox]
[status-im.common.pdf-viewer.view :as pdf-viewer]
[status-im.common.privacy.view :as privacy-policy]
[status-im.common.terms.view :as terms-of-use]
[status-im.config :as config]
[status-im.contexts.chat.group.create.view :as group.create]
[status-im.contexts.chat.group.details.view :as group.details]
@@ -73,6 +75,7 @@
[status-im.contexts.profile.settings.screens.password.view :as settings-password]
[status-im.contexts.profile.settings.screens.syncing.view :as settings.syncing]
[status-im.contexts.profile.settings.view :as settings]
[status-im.contexts.settings.about.view :as settings.about]
[status-im.contexts.settings.keycard.view :as settings.keycard]
[status-im.contexts.settings.language-and-currency.currency.view :as settings.currency-selection]
[status-im.contexts.settings.language-and-currency.view :as settings.language-and-currency]
@@ -153,39 +156,39 @@
(def chat-screens
[{:name :start-a-new-chat
:metrics {:track? :true
:metrics {:track? true
:alias-id :messenger.new-chat}
:options {:sheet? true}
:component new-chat/view}
{:name :chat
:metrics {:track? :true
:metrics {:track? true
:alias-id :messenger.chat}
:options {:popGesture false
:animations transitions/stack-transition-from-bottom}
:component chat/chat}
{:name :screen/group-create
:metrics {:track? :true
:metrics {:track? true
:alias-id :messenger.new-group}
:options {:sheet? true
:skip-background? true}
:component group.create/view}
{:name :screen/group-details
:metrics {:track? :true
:metrics {:track? true
:alias-id :messenger.group-details}
:component group.details/view}
{:name :screen/group-update
:metrics {:track? :true
:metrics {:track? true
:alias-id :messenger.group-update}
:options {:sheet? true
:skip-background? true}
:component group.update/view}
{:name :screen/group-add-manage-members
:metrics {:track? :true
:metrics {:track? true
:flow :messenger
:alias-id :messenger.group-manage-members}
:options {:sheet? true}
@@ -193,12 +196,12 @@
(def community-screens
[{:name :discover-communities
:metrics {:track? :true
:metrics {:track? true
:alias-id :community.discover}
:component communities.discover/view}
{:name :community-overview
:metrics {:track? :true
:metrics {:track? true
:alias-id :community.overview}
:options {:animations transitions/stack-transition-from-bottom}
:component communities.overview/view}
@@ -207,79 +210,79 @@
;; joining a community. The non-sheet screen is used when editing shared
;; addresses after the join request was sent.
{:name :community-account-selection-sheet
:metrics {:track? :true
:metrics {:track? true
:alias-id :community.select-addresses-for-joining-community}
:options {:sheet? true}
:component communities.accounts-selection/view}
{:name :community-account-selection
:metrics {:track? :true
:metrics {:track? true
:alias-id :community.select-addresses-for-community}
:options {:insets {:top? true}}
:component communities.accounts-selection/view}
{:name :community-requests-to-join
:metrics {:track? :true
:metrics {:track? true
:alias-id :community.request-to-join}
:options {:sheet? true}
:component join-menu/view}
{:name :screen/share-community
:metrics {:track? :true
:metrics {:track? true
:alias-id :community.share-community}
:options options/transparent-screen-options
:component share-community/view}
{:name :invite-people-community
:metrics {:track? :true
:metrics {:track? true
:alias-id :community.invite-people}
:options {:sheet? true}
:component communities.invite/view}
{:name :share-community-channel
:metrics {:track? :true
:metrics {:track? true
:alias-id :community.share-channel}
:options options/transparent-screen-options
:component share-community-channel/view}
{:name :screen/chat.view-channel-members-and-details
:metrics {:track? :true
:metrics {:track? true
:alias-id :community.view-channel-members-and-details}
:options {:insets {:top? true}}
:component channel-view-channel-members-and-details/view}
{:name :addresses-for-permissions
:metrics {:track? :true
:metrics {:track? true
:alias-id :community.choose-addresses-for-permissions}
:options {:insets {:top? true}}
:component addresses-for-permissions/view}
{:name :address-for-airdrop
:metrics {:track? :true
:metrics {:track? true
:alias-id :community.choose-addresses-for-airdrop}
:options {:insets {:top? true}}
:component airdrop-addresses/view}])
(def contact-screens
[{:name :new-contact
:metrics {:track? :true
:metrics {:track? true
:alias-id :contact.new-contact}
:options {:sheet? true}
:component add-new-contact/new-contact}
{:name :scan-profile-qr-code
:metrics {:track? :true
:metrics {:track? true
:alias-id :contact.scan-profile-qr-code}
:options options/dark-screen
:component scan-profile-qr-page/view}
{:name :contact-profile
:metrics {:track? :true
:metrics {:track? true
:alias-id :contact.contact-profile}
:options {:modalPresentationStyle :overCurrentContext}
:component contact-profile/view}
{:name :share-contact
:metrics {:track? :true
:metrics {:track? true
:alias-id :contact.share-profile}
:options options/transparent-screen-options
:component share-contact/view}])
@@ -311,56 +314,56 @@
(def settings-screens
[{:name :settings
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.profile-settings}
:options options/transparent-screen-options
:component settings/view}
{:name :screen/settings.keycard
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.keycard}
:options {:theme :dark
:insets {:top? true :bottom? true}}
:component settings.keycard/view}
{:name :edit-profile
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.edit-profile}
:options options/transparent-modal-screen-options
:component edit-profile/view}
{:name :edit-accent-colour
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.edit-profile-accent-colour}
:options options/transparent-modal-screen-options
:component edit-accent-colour/view}
{:name :edit-name
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.edit-profile-name}
:options options/transparent-modal-screen-options
:component edit-name/view}
{:name :edit-bio
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.edit-profile-bio}
:options options/transparent-modal-screen-options
:component edit-bio/view}
{:name :screen/settings-password
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.password}
:options options/transparent-modal-screen-options
:component settings-password/view}
{:name :screen/change-password
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.change-password}
:options (assoc options/transparent-modal-screen-options :theme :dark)
:component change-password/view}
{:name :screen/change-password-loading
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.change-password-loading}
:options (assoc
options/transparent-modal-screen-options
@@ -371,25 +374,25 @@
:component change-password-loading/view}
{:name :screen/settings-messages
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.messages}
:options options/transparent-modal-screen-options
:component settings.messages/view}
{:name :screen/settings-blocked-users
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.blocked-users}
:options options/transparent-modal-screen-options
:component settings.blocked-users/view}
{:name :screen/settings-privacy-and-security
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.private-and-security}
:options options/transparent-modal-screen-options
:component settings.privacy-and-security/view}
{:name :screen/settings.share-usage-data
:metrics {:track? :true}
:metrics {:track? true}
:options options/transparent-modal-screen-options
:component settings.share-usage/view}
@@ -405,89 +408,104 @@
:component syncing-devices-list/view}
{:name :screen/settings.language-and-currency
:metrics {:track? :true}
:metrics {:track? true}
:options options/transparent-modal-screen-options
:component settings.language-and-currency/view}
{:name :screen/settings.currency-selection
:metrics {:track? :true}
:metrics {:track? true}
:options options/transparent-modal-screen-options
:component settings.currency-selection/view}])
:component settings.currency-selection/view}
{:name :screen/settings.about
:metrics {:track? true}
:options options/transparent-modal-screen-options
:component settings.about/view}
{:name :screen/settings.privacy-policy
:metrics {:track? true}
:options options/transparent-modal-screen-options
:component privacy-policy/view}
{:name :screen/settings.terms-of-use
:metrics {:track? true}
:options options/transparent-modal-screen-options
:component terms-of-use/view}])
(def wallet-settings-screens
[{:name :screen/settings.wallet
:metrics {:track? :true}
:metrics {:track? true}
:options options/transparent-modal-screen-options
:component wallet-options/view}
{:name :screen/settings.rename-keypair
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.wallet-rename-keypair}
:options options/transparent-screen-options
:component keypair-rename/view}
{:name :screen/settings.encrypted-keypair-qr
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.wallet-encrypted-keypair-qr}
:options options/transparent-screen-options
:component encrypted-keypair-qr/view}
{:name :screen/settings.saved-addresses
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.wallet-saved-addresses}
:options options/transparent-modal-screen-options
:component saved-addresses-settings/view}
{:name :screen/settings.keypairs-and-accounts
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.wallet-keypairs-and-accounts}
:options options/transparent-modal-screen-options
:component keypairs-and-accounts/view}
{:name :screen/settings.scan-keypair-qr
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.wallet-scan-keypair-qr}
:options options/transparent-screen-options
:component scan-keypair-qr/view}
{:name :screen/settings.missing-keypair.import-seed-phrase
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.wallet-missing-keypair-import-seed-phrase}
:options options/transparent-screen-options
:component missing-keypairs.import-seed-phrase/view}
{:name :screen/settings.missing-keypair-import-private-key
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.wallet-missing-keypair-import-private-key}
:options options/transparent-screen-options
:component missing-keypairs.import-private-key/view}
{:name :screen/settings.network-settings
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.wallet-network-settings}
:options options/transparent-modal-screen-options
:component network-settings/view}
{:name :screen/settings.save-address
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.wallet-saved-addresses}
:options options/transparent-modal-screen-options
:component wallet-save-address/view}
{:name :screen/settings.edit-saved-address
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.wallet-edit-saved-addresses}
:options (assoc options/dark-screen :sheet? true)
:component wallet-save-address/view}
{:name :screen/settings.add-address-to-save
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.wallet-add-saved-address}
:options options/transparent-modal-screen-options
:component wallet-add-address-to-save/view}
{:name :screen/settings.share-saved-address
:metrics {:track? :true
:metrics {:track? true
:alias-id :settings.wallet-share-saved-address}
:options options/transparent-screen-options
:component share-saved-address/view}])
@@ -757,9 +775,7 @@
:metrics {:track? true}
:options {:theme :dark
:layout options/onboarding-transparent-layout
:animations (merge
transitions/new-to-status-modal-animations
transitions/push-animations-for-transparent-background)
:animations transitions/modal-animations-vertical
:popGesture false
:modalPresentationStyle :overCurrentContext}
:component onboarding.share-usage/view})
@@ -876,48 +892,48 @@
(def keycard-screens
[{:name :screen/keycard.check
:metrics {:track? :true}
:metrics {:track? true}
:options {:theme :dark
:insets {:top? true :bottom? true}}
:component keycard.check/view}
{:name :screen/keycard.empty
:metrics {:track? :true}
:metrics {:track? true}
:options {:theme :dark
:insets {:top? true :bottom? true}}
:component keycard.empty/view}
{:name :screen/keycard.empty-create
:metrics {:track? :true}
:metrics {:track? true}
:options {:insets {:top? true :bottom? true}}
:component keycard.empty/create}
{:name :screen/keycard.error
:metrics {:track? :true}
:metrics {:track? true}
:options {:theme :dark
:insets {:top? true :bottom? true}}
:component keycard.error/view}
{:name :screen/keycard.not-keycard
:metrics {:track? :true}
:metrics {:track? true}
:options {:theme :dark
:insets {:top? true :bottom? true}}
:component keycard.not-keycard/view}
{:name :screen/keycard.authorise
:metrics {:track? :true}
:metrics {:track? true}
:options {:theme :dark
:insets {:top? true :bottom? true}}
:component keycard.authorise/view}
{:name :screen/keycard.migrate
:metrics {:track? :true}
:metrics {:track? true}
:options {:theme :dark
:insets {:top? true :bottom? true}}
:component keycard.migrate/view}
{:name :screen/keycard.re-encrypting
:metrics {:track? :true}
:metrics {:track? true}
:options {:theme :dark
:insets {:top? true :bottom? true}
:popGesture false
@@ -926,7 +942,7 @@
:component keycard.re-encrypting/view}
{:name :screen/keycard.migrate.success
:metrics {:track? :true}
:metrics {:track? true}
:options {:theme :dark
:insets {:top? true :bottom? true}
:popGesture false
@@ -935,7 +951,7 @@
:component keycard.migrate.success/view}
{:name :screen/keycard.migrate.fail
:metrics {:track? :true}
:metrics {:track? true}
:options {:theme :dark
:insets {:top? true :bottom? true}
:popGesture false
@@ -944,30 +960,30 @@
:component keycard.migrate.fail/view}
{:name :screen/keycard.pin.create
:metrics {:track? :true}
:metrics {:track? true}
:options {:theme :dark
:insets {:top? true :bottom? true}}
:component keycard.pin.create/view}
{:name :screen/keycard.pin.enter
:metrics {:track? :true}
:metrics {:track? true}
:options {:theme :dark
:insets {:top? true :bottom? true}}
:component keycard.pin.enter/view}
{:name :screen/keycard.profile-keys
:metrics {:track? :true}
:metrics {:track? true}
:options {:theme :dark
:insets {:top? true :bottom? true}}
:component keycard.migrate.profile-keys/view}
{:name :screen/keycard.create-profile
:metrics {:track? :true}
:metrics {:track? true}
:options {:insets {:top? true :bottom? true}}
:component keycard.create/view}
{:name :screen/keycard.create.ready-to-add
:metrics {:track? :true}
:metrics {:track? true}
:options {:insets {:top? true :bottom? true}}
:component keycard.create/ready-to-add}])
@@ -40,6 +40,14 @@
:to (:width (rn/get-window))
:duration constants/onboarding-modal-animation-duration}}})
(def modal-animations-vertical
{:showModal {:translationY {:from (:height (rn/get-window))
:to 0
:duration constants/onboarding-modal-animation-duration}}
:dismissModal {:translationY {:from 0
:to (:height (rn/get-window))
:duration constants/onboarding-modal-animation-duration}}})
;;;; Stack Transitions
(def stack-slide-transition
{:push {:content {:translationX {:from (:width (rn/get-window))
+9 -1
View File
@@ -286,6 +286,12 @@
:<- [:wallet/create-account]
:-> :selected-keypair-uid)
(rf/reg-sub
:wallet/selected-keypair-keycard?
:<- [:wallet/selected-keypair]
(fn [{:keys [keycards]}]
(boolean (seq keycards))))
(rf/reg-sub
:wallet/selected-keypair
:<- [:wallet/keypairs]
@@ -343,12 +349,13 @@
:<- [:wallet/keypairs-list]
(fn [keypairs [_ format-options]]
(reduce
(fn [acc {:keys [accounts name type key-uid lowest-operability]}]
(fn [acc {:keys [accounts name type key-uid lowest-operability keycards]}]
(if (= lowest-operability :no)
(update acc
:missing
conj
{:type type
:keycard? (boolean (seq keycards))
:name name
:key-uid key-uid
:accounts (format-settings-missing-keypair-accounts accounts)})
@@ -356,6 +363,7 @@
:operable
conj
{:type type
:keycard? (boolean (seq keycards))
:name name
:key-uid key-uid
:accounts (format-settings-keypair-accounts accounts format-options)})))
@@ -1133,3 +1133,25 @@
"0")
:has-error false}}}]}}))
(is (false? (rf/sub [sub-name])))))
(h/deftest-sub :wallet/selected-keypair-keycard?
[sub-name]
(testing "returns true if the selected keypair has keycards"
(swap! rf-db/app-db
#(assoc-in %
[:wallet :keypairs]
{:keypair-1 {:id :keypair-1
:keycards [:keycard-1 :keycard-2]}}))
(swap! rf-db/app-db
#(assoc-in % [:wallet :ui :create-account :selected-keypair-uid] :keypair-1))
(is (true? (rf/sub [sub-name]))))
(testing "returns false if the selected keypair has no keycards"
(swap! rf-db/app-db
#(assoc-in %
[:wallet :keypairs]
{:keypair-2 {:id :keypair-2
:keycards []}}))
(swap! rf-db/app-db
#(assoc-in % [:wallet :ui :create-account :selected-keypair-uid] :keypair-2))
(is (false? (rf/sub [sub-name])))))
+34 -1
View File
@@ -2,7 +2,8 @@
(:require
[clojure.string :as string]
[native-module.core :as native-module]
[utils.ethereum.eip.eip55 :as eip55]))
[utils.ethereum.eip.eip55 :as eip55]
[utils.ethereum.eip.eip681 :as eip681]))
(def hex-prefix "0x")
@@ -105,11 +106,23 @@
[address]
(re-find regx-eip-3770-address address))
(defn eip-681-address?
[scanned-text]
(-> scanned-text
eip681/parse-uri
:address
boolean))
(defn supported-address?
[s]
(boolean (or (eip-3770-address? s)
(metamask-address? s))))
(defn supported-scan-address?
[s]
(boolean (or (eip-681-address? s)
(supported-address? s))))
(defn metamask-address->eip-3770-address
[metamask-address]
(when-let [[_ address metamask-network-suffix] (split-metamask-address metamask-address)]
@@ -129,9 +142,18 @@
[eip-3770-address]
(extract-address-without-chains-info eip-3770-address))
(defn eip-681-address->eth-address
[eip-681-address]
(-> eip-681-address
eip681/parse-uri
:address))
(defn supported-address->eth-address
[address]
(cond
(eip-681-address? address)
(eip-681-address->eth-address address)
(eip-3770-address? address)
(eip-3770-address->eth-address address)
@@ -141,3 +163,14 @@
(defn zero-address?
[address]
(= address zero-address))
(defn public-key->address
[public-key]
(let [length (count public-key)
normalized-key (case length
132 (str "0x" (subs public-key 4))
130 public-key
128 (str "0x" public-key)
nil)]
(when normalized-key
(subs (native-module/sha3 normalized-key) 26))))
+10 -6
View File
@@ -6,7 +6,7 @@
e.g. ethereum:0x1234@1/transfer?to=0x5678&value=1e18&gas=5000"
(:require
[clojure.string :as string]
[utils.address :as address]
[native-module.core :as native-module]
[utils.ens.core :as utils.ens]
[utils.ethereum.chain :as chain]))
@@ -18,6 +18,10 @@
(def parameter-separator "&")
(def key-value-separator "=")
(defn- address?
[address]
(native-module/address? address))
(def uri-pattern
(re-pattern (str scheme scheme-separator "([^" query-separator "]*)(?:\\" query-separator "(.*))?")))
(def authority-path-pattern
@@ -63,16 +67,16 @@
Invalid URI will be parsed as `nil`."
[s]
(when (string? s)
(if (address/address? s)
(if (address? s)
{:address s}
(let [[_ authority-path query] (re-find uri-pattern s)]
(when authority-path
(let [[_ raw-address chain-id function-name] (re-find authority-path-pattern authority-path)]
(when (or (or (utils.ens/is-valid-eth-name? raw-address) (address/address? raw-address))
(when (or (or (utils.ens/is-valid-eth-name? raw-address) (address? raw-address))
(when (string/starts-with? raw-address "pay-")
(let [pay-address (string/replace-first raw-address "pay-" "")]
(or (utils.ens/is-valid-eth-name? pay-address)
(address/address? pay-address)))))
(address? pay-address)))))
(let [address (if (string/starts-with? raw-address "pay-")
(string/replace-first raw-address "pay-" "")
raw-address)]
@@ -80,7 +84,7 @@
(let [contract-address (get-in arguments [:function-arguments :address])]
(if-not (or (not contract-address)
(or (utils.ens/is-valid-eth-name? contract-address)
(address/address? contract-address)))
(address? contract-address)))
nil
(merge {:address address
:chain-id (if chain-id
@@ -98,7 +102,7 @@
"Generate a EIP 681 URI based on `address` and a map (keywords / {bignumbers/strings} ) of extra properties.
No validation of address format is performed."
[address {:keys [chain-id function-name function-arguments] :as m}]
(when (address/address? address)
(when (address? address)
(let [parameters (dissoc (into {} (filter second m)) :chain-id)] ;; filter nil values
(str scheme
scheme-separator
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v7.0.0",
"commit-sha1": "84493728d9ac41553297e8084943c1429cdfe59a",
"src-sha256": "11dwdlk9svmc6f8wmya43fis9jfigvh5idxpiwmia9gkad1zal6y"
"version": "8acd48240bfeacd119bb4a41985f52be5ef00038",
"commit-sha1": "8acd48240bfeacd119bb4a41985f52be5ef00038",
"src-sha256": "0hn350bxs14gnm39dg9x588142nj7n79k313487y659yk1142ksx"
}
@@ -148,14 +148,6 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
@marks.testrail_id(702777)
def test_add_contact_field_validation(self):
# Profile link encoded data validation
encoded_data = re.findall("u/(.*)#", self.profile_link_2)[0]
decoded_string = base64.b64decode(encoded_data).decode("utf-8", "ignore")
decoded_username = re.sub('[^A-Za-z0-9]+', '', decoded_string)
if decoded_username != self.username_2:
self.errors.append(
"Can't find username '%s' in data which profile link '%s' contains. String '%s' is found instead" % (
self.username_2, self.profile_link_2, decoded_username))
public_key_2 = self.profile_link_2.split("#")[-1]
def _device_1_creates_user():
@@ -453,7 +453,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
current_time = datetime.datetime.strptime(device_time, "%Y-%m-%dT%H:%M:%S%z")
expected_times = [current_time + datetime.timedelta(minutes=i) for i in range(479, 482)]
expected_texts = [
"Muted until %s %s" % (exp_time.strftime('%H:%M'), "today" if current_time.hour < 23 else "tomorrow") for
"Muted until %s %s" % (exp_time.strftime('%H:%M'), "today" if current_time.hour < 16 else "tomorrow") for
exp_time in expected_times]
chat = self.homes[1].get_chat(self.chat_name)
chat.long_press_element()
@@ -483,7 +483,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
if after_mute_counter > initial_counter:
self.errors.append("New messages counter near chats tab button is %s after mute, but should be %s" % (
after_mute_counter, initial_counter))
if not chat.chat_preview.text.startswith("%s: %s" % (self.usernames[0], muted_message)):
if not chat.chat_preview.text.startswith("%s: %s" % (self.usernames[0], muted_message[:25])):
self.errors.append("Message text '%s' is not shown in chat preview after mute" % muted_message)
chat.click()
if not self.chats[1].chat_element_by_text(muted_message).is_element_displayed(30):
@@ -1021,6 +1021,8 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
self.errors.append('Community is still shown in the list after leave')
self.errors.verify_no_errors()
@marks.xfail(reason="Can't navigate to a community channel before joining the community, "
"https://github.com/status-im/status-mobile/issues/21776")
@marks.testrail_id(702948)
def test_community_hashtag_links_to_community_channels(self):
for home in self.homes:
@@ -1121,6 +1123,8 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
self.errors.verify_no_errors()
@marks.xfail(reason="Can't navigate to a community channel before joining the community, "
"https://github.com/status-im/status-mobile/issues/21776")
@marks.testrail_id(703629)
def test_community_join_when_node_owner_offline(self):
for home in self.homes:
@@ -89,7 +89,7 @@ class TestDeepLinksOneDevice(MultipleSharedDeviceTestCase):
self.home.get_chat(snt_community_name, community=True).click()
snt_community_url = self.community_view.copy_community_link()
self.home.reopen_app(sign_in=False)
self.sign_in.create_user(username="second user", first_user=False)
self.sign_in.create_user(first_user=False)
self.home.browser_tab.click()
old, new = "https://status.app/", "status-app://"
+1 -1
View File
@@ -269,7 +269,7 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
self.sign_in_2.passphrase_edit_box.clear()
self.sign_in_2.passphrase_edit_box.send_keys(transaction_senders['A']['passphrase'])
self.sign_in_2.continue_button.click()
if not self.sign_in_2.profile_title_input.is_element_displayed():
if not self.sign_in_2.password_input.is_element_displayed():
self.errors.append("Can't recover an access with a valid passphrase")
self.sign_in_2.click_system_back_button()
+4 -4
View File
@@ -59,19 +59,19 @@ class TestWalletMultipleDevice(MultipleSharedDeviceTestCase):
def wait_for_wallet_balance_to_update(wallet_view, user_name, initial_eth_amount):
wallet_view.just_fyi("Getting ETH amount in the wallet of the %s after transaction" % user_name)
if user_name == 'sender':
if user_name == self.sender_username:
exp_amount = round(initial_eth_amount - amount_to_send, 4)
else:
exp_amount = round(initial_eth_amount + amount_to_send, 4)
# for _ in range(12): # ToDo: 120 sec wait time, enable when autoupdate feature is ready
new_eth_amount = round(wallet_view.get_asset(asset_name='Ether').get_amount(), 4)
if user_name == 'sender' and new_eth_amount <= exp_amount:
if user_name == self.sender_username and new_eth_amount <= exp_amount:
return
if user_name == 'receiver' and new_eth_amount >= exp_amount:
if user_name == self.receiver_username and new_eth_amount >= exp_amount:
return
self.errors.append(
"Eth amount in the %ss wallet is %s but should be %s" % (user_name, new_eth_amount, exp_amount))
"Eth amount in the %s's wallet is %s but should be %s" % (user_name, new_eth_amount, exp_amount))
# ToDo: disable relogin when autoupdate feature is ready
self.home_1.just_fyi("Relogin for getting an updated balance")
+1
View File
@@ -626,6 +626,7 @@ class HomeView(BaseView):
return element.text
def get_username(self):
self.toast_content_element.wait_for_invisibility_of_element()
profile_view = self.get_profile_view()
profile_view = self.profile_button.click_until_presence_of_element(profile_view.default_username_text)
profile_view.default_username_text.wait_for_element(3)
+4 -2
View File
@@ -361,8 +361,10 @@ class SignInView(BaseView):
def get_user_profile_by_name(self, username: str):
self.driver.info("Getting username card by '%s'" % username)
expected_element = UserProfileElement(self.driver, username=username)
return expected_element if expected_element.is_element_displayed(10) else self.driver.fail(
"User %s is not found!" % username)
if expected_element.is_element_displayed(10):
return expected_element
else:
raise NoSuchElementException(msg="User %s is not found!" % username)
def get_user_profile_by_index(self, index: int):
self.driver.info("Getting username card by index %s" % index)
+7
View File
@@ -801,6 +801,7 @@
"do-not-quit": "Do not quit the application or turn off your device. Doing so will lead to data corruption, loss of your Status profile and the inability to use Status.",
"do-not-share": "Do not share",
"documents": "Documents",
"done": "Done",
"dont-ask": "Don't ask me again",
"dont-auto-recalculate-network": "Don't auto recalculate {{network}}",
@@ -1037,6 +1038,9 @@
"favourite-description": "Your favourite websites will appear here",
"favourites": "Favourites",
"favourites-empty": "Addresses added to favourites will appear here",
"feature-unavailable": "Feature unavailable",
"feature-unavailable-for-keycard-description": "Its not currently supported for Keycard users.",
"feature-unavailable-info": "If you'd like this feature on mobile, feel free to ",
"featured": "Featured",
"feb": "Feb",
"fee-cap": "Fee cap",
@@ -1113,6 +1117,7 @@
"getting-started-generate-keys-on-keycard-description": "A Keycard is a physical card (similar to a credit card) that securely stores your Status keys. Using a Keycard adds an extra layer of security to your digital assets and identity. This option creates a new Ethereum address.",
"getting-started-with-status": "Getting started with Status",
"gif": "GIF",
"github-repos": "GitHub repos",
"give-a-short-description": "Give a short description",
"give-a-short-description-community": "Give it a short description",
"give-permissions-camera": "Give permission\nto access camera",
@@ -2719,6 +2724,7 @@
"update-to-see-sticker": "Update to latest version to see a nice sticker here!",
"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",
"url": "URL",
"usage-data-shared-from-all-profiles": "Usage data will be shared from all profiles added to device. ",
"usd-currency": "USD",
@@ -2868,6 +2874,7 @@
"we-will-receive-from-all-profiles": "We will receive from all profiles:",
"we-will-receive-from-the-current-profile": "We will receive from the current profile:",
"web-view-error": "Unable to load page",
"website": "Website",
"websites": "Websites",
"webview-camera-permission-requests": "Webview camera permission requests",
"webview-camera-permission-requests-subtitle": "When enabled, websites and dapps can ask to use your camera",
+2 -2
View File
@@ -9584,9 +9584,9 @@ react-native-static-safe-area-insets@^2.2.0:
resolved "https://registry.yarnpkg.com/react-native-static-safe-area-insets/-/react-native-static-safe-area-insets-2.2.0.tgz#dd86b6a38f43964fac8df8c0e6bc8e062527786c"
integrity sha512-TLTW2e2kRK3COSK8gMZzwp4wHguFCtcO18itDLn5av/xQblXt9ylu84o+qD9aKJCBfvtNzGOvqqTKqC5GJRZ/g==
"react-native-status-keycard@git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.6.3":
"react-native-status-keycard@git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.6.4":
version "2.6.2"
resolved "git+https://github.com/status-im/react-native-status-keycard.git#735bed7f9838b87712f1fd2978208186d28ea61c"
resolved "git+https://github.com/status-im/react-native-status-keycard.git#e78f46de10d65cfef2df2f62b6f41e64e0c332b9"
react-native-svg@13.10.0:
version "13.10.0"