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
Ulises ManuelandYevheniia Berdnyk e85bc539d3 feat(onboarding): Remove color and username steps (#21715)
* Remove password disclaimer, update copy and simplify implementation

* Remove non-existing wallet event

* Skip profile configuration for the "create profile" onboarding flow

* Include flow for new profiles when another profile already exists

* Add explanation about temp username

* Point 20 to a constant

* Simplify create profile password screen

* Fix password creation screen jump on mount

* e2e: updated tests

* Completely remove the "create profile" onboarding screen

* e2e: updated tests with recovering user

---------

Co-authored-by: Yevheniia Berdnyk <ie.berdnyk@gmail.com>
2024-12-09 13:55:47 -06:00
Mohamed Javid c26d298573 fix_: slider reset in standard authentication (#21779)
This commit resets the slider-button after the completion of slider in standard authentication.


Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-12-10 00:56:57 +05:30
Mohamed Javid cdde36ca28 fix(wallet)_: logic for calculating zero balance (#21777)
This commit fixes logic to calculate whether the user has zero balance in all non-watched accounts.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-12-10 00:21:00 +05:30
113 changed files with 1441 additions and 1207 deletions
-1
View File
@@ -36,4 +36,3 @@ SHOW_NOT_IMPLEMENTED_FEATURES=0
ENABLE_ALERT_BANNER=0
FLAG_WALLET_CONNECT_ENABLED=1
API_LOGGING_ENABLED=1
SENTRY_ENVIRONMENT=ci-main
-1
View File
@@ -40,4 +40,3 @@ ENABLE_ALERT_BANNER=0
FLAG_WALLET_CONNECT_ENABLED=1
MOBILE_DATA_SYNCING_TOGGLE_ENABLE=0
API_LOGGING_ENABLED=1
SENTRY_ENVIRONMENT=ci-main
-1
View File
@@ -37,4 +37,3 @@ TEST_NETWORKS_ENABLED=1
ENABLE_ALERT_BANNER=1
FLAG_WALLET_CONNECT_ENABLED=1
API_LOGGING_ENABLED=1
SENTRY_ENVIRONMENT=ci-main
-1
View File
@@ -24,4 +24,3 @@ TEST_NETWORKS_ENABLED=0
ENABLE_ALERT_BANNER=1
FLAG_WALLET_CONNECT_ENABLED=1
API_LOGGING_ENABLED=0
SENTRY_ENVIRONMENT=ci-nightly
-1
View File
@@ -21,4 +21,3 @@ TEST_NETWORKS_ENABLED=0
STATUS_PROXY_STAGE_NAME=prod
FLAG_WALLET_CONNECT_ENABLED=1
API_LOGGING_ENABLED=0
SENTRY_ENVIRONMENT=production
+1 -1
View File
@@ -1 +1 @@
2.32.21682
2.32.0
+1 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.15'
library 'status-jenkins-lib@v1.9.13'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
@@ -41,7 +41,6 @@ pipeline {
BUILD_ENV = 'prod'
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
FASTLANE_DISABLE_COLORS = 1
SENTRY_PRODUCTION = "${utils.isReleaseBuild() ? 'true' : 'false'}"
}
stages {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.15'
library 'status-jenkins-lib@v1.9.13'
import groovy.json.JsonBuilder
+1 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.15'
library 'status-jenkins-lib@v1.9.13'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
@@ -41,7 +41,6 @@ pipeline {
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
FASTLANE_DISABLE_COLORS = 1
BUNDLE_PATH = "${HOME}/.bundle"
SENTRY_PRODUCTION = "${utils.isReleaseBuild() ? 'true' : 'false'}"
}
stages {
+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`.
@@ -108,15 +108,6 @@ class StatusModule(private val reactContext: ReactApplicationContext, private va
)
}
@ReactMethod
fun intendedPanic(message: String) {
StatusBackendClient.executeStatusGoRequest(
endpoint = "IntendedPanic",
requestBody = "",
statusgoFunction = { Statusgo.intendedPanic(message) },
)
}
@ReactMethod
fun addCentralizedMetric(request: String, callback: Callback) {
StatusBackendClient.executeStatusGoRequestWithCallback(
@@ -109,13 +109,6 @@ RCT_EXPORT_METHOD(getNodeConfig:(RCTResponseSenderBlock)callback) {
callback:callback];
}
RCT_EXPORT_METHOD(intendedPanic:(NSString *)message) {
#if DEBUG
NSLog(@"IntendedPanic() method called");
#endif
StatusgoIntendedPanic(message);
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(fleets) {
return [StatusBackendClient executeStatusGoRequestWithResult:@"Fleets"
body:@""
+1 -5
View File
@@ -11,7 +11,7 @@
, outputFileName ? "status-go-${source.shortRev}-${platform}.aar" }:
let
inherit (lib) concatStringsSep optionalString optional splitString fileContents;
inherit (lib) concatStringsSep optionalString optional splitString;
isIOS = platform == "ios";
isAndroid = platform == "android";
enforceXCodeAvailable = callPackage ./enforceXCodeAvailable.nix { };
@@ -46,10 +46,6 @@ in buildGoPackage rec {
# TODO: try removing when go is upgraded to 1.22
GODEBUG = "netdns=cgo+2";
# Sentry for status-go
SENTRY_CONTEXT_NAME = "status-mobile";
SENTRY_CONTEXT_VERSION = fileContents ../../../VERSION;
preBuild = ''
echo 'Generate static files'
pushd go/src/$goPackagePath
+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

-1
View File
@@ -45,7 +45,6 @@ SECRETS_ENV_VARS=(
'MIXPANEL_APP_ID'
'MIXPANEL_TOKEN'
'POKT_TOKEN'
'SENTRY_DSN_STATUS_GO'
)
# Secrets like this can't be passed via args or they end up in derivation.
+1 -2
View File
@@ -123,8 +123,7 @@
status-im.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"
status-im.config/SENTRY_DSN_STATUS_GO #shadow/env "SENTRY_DSN_STATUS_GO"}
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"}
:compiler-options {:output-feature-set :es6
;;disable for android build as there
;;is an intermittent warning with deftype
+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,13 +1,10 @@
(ns legacy.status-im.ui.screens.advanced-settings.views
(:require
[clojure.string :as string]
[legacy.status-im.ui.components.core :as components]
[legacy.status-im.ui.components.list.item :as list.item]
[legacy.status-im.ui.components.list.views :as list]
[quo.core :as quo]
[re-frame.core :as re-frame]
[status-im.config :as config]
[status-im.feature-flags :as ff]
[utils.i18n :as i18n]
[utils.re-frame :as rf])
(:require-macros [legacy.status-im.utils.views :as views]))
@@ -25,23 +22,7 @@
peer-syncing-enabled?]}]
(keep
identity
[;; TODO(ilmotta): REMOVE BEFORE MERGE
{:size :small
:title (str "Is MixPanel token set?"
(if (string/blank? config/mixpanel-token)
"No"
"Yes"))
:on-press identity}
(when (ff/enabled? ::ff/app-monitoring.intentional-crash)
{:size :small
:title (str "Force crash immediately"
(when (string/blank? config/sentry-dsn-status-go)
" (Sentry DSN is not set)"))
:accessibility-label :intended-panic
:on-press (fn []
(re-frame/dispatch [:app-monitoring/intended-panic
"status-mobile intentional panic"]))})
{:size :small
[{:size :small
:title (i18n/label :t/log-level)
:accessibility-label :log-level-settings-button
:on-press
@@ -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}
-4
View File
@@ -581,7 +581,3 @@
(.createAccountFromPrivateKey ^js (account-manager)
(types/clj->json {:privateKey private-key})
callback)))
(defn intended-panic
[message]
(.intendedPanic ^js (status) message))
@@ -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
@@ -1,8 +0,0 @@
(ns status-im.common.app-monitoring.effects
(:require
[native-module.core :as native-module]
[utils.re-frame :as rf]))
(rf/reg-fx :effects.app-monitoring/intended-panic
(fn [message]
(native-module/intended-panic message)))
@@ -1,8 +0,0 @@
(ns status-im.common.app-monitoring.events
(:require
status-im.common.app-monitoring.effects
[utils.re-frame :as rf]))
(rf/reg-event-fx :app-monitoring/intended-panic
(fn [_ [message]]
{:fx [[:effects.app-monitoring/intended-panic message]]}))
@@ -61,14 +61,17 @@
(defn view
[{:keys [header footer customization-color footer-container-padding header-container-style
content-container-style gradient-cover? keyboard-should-persist-taps shell-overlay?
blur-options content-avoid-keyboard? automatically-adjust-keyboard-insets]
blur-options content-avoid-keyboard? automatically-adjust-keyboard-insets
;; Note: Provide `initial-header-height` to avoid a jump due to the on-layout 1-frame
;; delay. Revisit this on RN 0.76 since the on-layout delay has been fixed.
initial-header-height]
:or {footer-container-padding (safe-area/get-top)}}
& children]
(reagent/with-let [scroll-view-ref (atom nil)
set-scroll-ref #(reset! scroll-view-ref %)
window-height (:height (rn/get-window))
footer-container-height (reagent/atom 0)
header-height (reagent/atom 0)
header-height (reagent/atom nil)
content-container-height (reagent/atom 0)
content-scroll-y (reagent/atom 0)
keyboard-height (reagent/atom 0)
@@ -112,7 +115,7 @@
{:style
(if content-avoid-keyboard?
(style/content-keyboard-avoiding-view
{:top @header-height
{:top (or @header-height initial-header-height)
:bottom (if keyboard-shown?
@footer-container-height
(+ bottom-safe-area @footer-container-height))})
+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]
(rf/dispatch [:standard-auth/authorize
{:on-close (fn [success?]
(js/setTimeout #(reset success?) 200))
: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]]])
@@ -28,9 +28,10 @@
:long-enough?
:short-enough?)))))
(def password-tip? (set constants/password-tips))
(defn strength
[validations]
(->> (select-keys validations constants/password-tips)
(vals)
(filter true?)
count))
(->> validations
(filter #(and (password-tip? (key %)) (val %)))
(count)))
-5
View File
@@ -150,8 +150,3 @@
(goog-define STATUS_BACKEND_SERVER_ROOT_DATA_DIR "")
;; if you're using android simulator, I suggest set the env variable to "http://10.0.2.2:"
(goog-define STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX "https://localhost:")
;;;; Sentry
;; Documentation: status-go/internal/sentry/README.md
(goog-define SENTRY_DSN_STATUS_GO "")
(def sentry-dsn-status-go SENTRY_DSN_STATUS_GO)
+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]
@@ -52,8 +52,8 @@
{:eventName "navigation"
:platform platform-os
:appVersion app-version
:eventValue {:viewId "onboarding.create-profile-info"}}}]
(tracking/track-view-id-event :screen/onboarding.create-profile)))
:eventValue {:viewId "onboarding.create-profile-password"}}}]
(tracking/track-view-id-event :screen/onboarding.create-profile-password)))
(is (= [] (tracking/track-view-id-event :unknown-stack)))))
(deftest tracked-event-test
@@ -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
@@ -1,6 +1,7 @@
(ns status-im.contexts.onboarding.create-password.style
(:require
[quo.foundations.colors :as colors]))
[quo.foundations.colors :as colors]
[react-native.platform :as platform]))
(def heading {:margin-bottom 20})
(def heading-subtitle {:color colors/white})
@@ -21,6 +22,18 @@
:padding-top 12
:padding-horizontal 20})
(def disclaimer-container {:padding-horizontal 20})
(def footer-container {:padding-bottom 12})
(def footer-button-container {:margin-top 20 :padding-horizontal 20})
(def blur-options
{:blur-amount 34
:blur-radius 20
:blur-type :transparent
:overlay-color :transparent
:background-color (if platform/android?
colors/neutral-100
colors/neutral-80-opa-1-blur)
:padding-vertical 0
:padding-horizontal 0})
(def page-nav-height 56)
@@ -1,9 +1,7 @@
(ns status-im.contexts.onboarding.create-password.view
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.platform :as platform]
[react-native.safe-area :as safe-area]
[status-im.common.floating-button-page.view :as floating-button]
[status-im.common.password-with-hint.view :as password-with-hint]
@@ -29,22 +27,37 @@
(i18n/label :t/password-creation-subtitle)]])
(defn password-inputs
[{:keys [passwords-match? on-change-password on-change-repeat-password on-input-focus
password-long-enough? password-short-enough? empty-password? show-password-validation?
on-blur-repeat-password]}]
(let [hint-1-status (if password-long-enough? :success :default)
hint-2-status (if passwords-match? :success :error)
hint-2-text (if passwords-match?
(i18n/label :t/password-creation-match)
(i18n/label :t/password-creation-dont-match))
error? (and show-password-validation?
(not passwords-match?)
(not empty-password?))]
[{:keys [set-password set-repeat-password same-password-length? same-passwords?
password-long-enough? password-short-enough? non-empty-password?]}]
(let [[show-validation?
set-show-validation?] (rn/use-state false)
on-change-password (rn/use-callback
(fn [new-value]
(set-password new-value)
(when same-password-length?
(set-show-validation? true)))
[same-password-length?])
on-change-repeat-password (rn/use-callback
(fn [new-value]
(set-repeat-password new-value)
(when same-password-length?
(set-show-validation? true)))
[same-password-length?])
on-blur-repeat-password (rn/use-callback
#(set-show-validation? non-empty-password?)
[non-empty-password?])
hint-1-status (if password-long-enough? :success :default)
hint-2-status (if same-passwords? :success :error)
hint-2-text (if same-passwords?
(i18n/label :t/password-creation-match)
(i18n/label :t/password-creation-dont-match))
error? (and show-validation?
(not same-passwords?)
non-empty-password?)]
[:<>
[password-with-hint/view
{:hint (if (not password-short-enough?)
{:text (i18n/label
:t/password-creation-max-length-hint)
{:text (i18n/label :t/password-creation-max-length-hint)
:status :error
:shown? true}
{:text (i18n/label :t/password-creation-hint)
@@ -52,55 +65,50 @@
:shown? true})
:placeholder (i18n/label :t/password-creation-placeholder-1)
:on-change-text on-change-password
:on-focus on-input-focus
:auto-focus true}]
[rn/view {:style style/space-between-inputs}]
[password-with-hint/view
{:hint {:text hint-2-text
:status hint-2-status
:shown? (and (not empty-password?)
show-password-validation?)}
:shown? (and non-empty-password? show-validation?)}
:error? error?
:placeholder (i18n/label :t/password-creation-placeholder-2)
:on-change-text on-change-repeat-password
:on-focus on-input-focus
:on-blur on-blur-repeat-password}]]))
(defn help
[{{:keys [lower-case? upper-case? numbers? symbols?]} :validations
password-strength :password-strength}]
[rn/view
[quo/strength-divider {:type (constants/strength-status password-strength :info)}
(i18n/label :t/password-creation-tips-title)]
[rn/view {:style style/password-tips}
[quo/tips {:completed? lower-case?}
(i18n/label :t/password-creation-tips-1)]
[quo/tips {:completed? upper-case?}
(i18n/label :t/password-creation-tips-2)]
[quo/tips {:completed? numbers?}
(i18n/label :t/password-creation-tips-3)]
[quo/tips {:completed? symbols?}
(i18n/label :t/password-creation-tips-4)]]])
[{:keys [lower-case? upper-case? numbers? symbols?] :as validations}]
(let [password-strength (constants/strength-status (password/strength validations) :info)]
[rn/view
[quo/strength-divider {:type password-strength}
(i18n/label :t/password-creation-tips-title)]
[rn/view {:style style/password-tips}
[quo/tips {:completed? lower-case?}
(i18n/label :t/password-creation-tips-1)]
[quo/tips {:completed? upper-case?}
(i18n/label :t/password-creation-tips-2)]
[quo/tips {:completed? numbers?}
(i18n/label :t/password-creation-tips-3)]
[quo/tips {:completed? symbols?}
(i18n/label :t/password-creation-tips-4)]]]))
(defn- use-password-checks
[password]
(rn/use-memo
(fn []
(let [{:keys [long-enough? short-enough?]
:as validations} (password/validate password)]
{:password-long-enough? long-enough?
:password-short-enough? short-enough?
:password-validations validations
:password-strength (password/strength validations)
:empty-password? (empty? password)}))
(-> password
(password/validate)
(assoc :non-empty? (seq password))))
[password]))
(defn- use-repeat-password-checks
[password repeat-password]
(rn/use-memo
(fn []
{:same-password-length? (and (seq password) (= (count password) (count repeat-password)))
:same-passwords? (and (seq password) (= password repeat-password))})
{:same-password-length? (and (seq password)
(= (count password) (count repeat-password)))
:same-passwords? (and (seq password)
(= password repeat-password))})
[password repeat-password]))
(defn create-password-doc
@@ -119,102 +127,70 @@
{:content create-password-doc
:shell? true}]))
(defn- navigate-back
[]
(rf/dispatch [:navigate-back]))
(defn- navigate-back [] (rf/dispatch [:navigate-back]))
(defn- page-nav
[]
(let [{:keys [top]} (safe-area/get-insets)]
[quo/page-nav
{:margin-top top
:background :blur
:icon-name :i/arrow-left
:on-press navigate-back
:right-side [{:icon-name :i/info
:on-press on-press-info}]}]))
[top]
[quo/page-nav
{:margin-top top
:background :blur
:icon-name :i/arrow-left
:on-press navigate-back
:right-side [{:icon-name :i/info
:on-press on-press-info}]}])
(defn- help-and-confirm-button
[{:keys [password-validations same-passwords? on-submit]}]
(let [{customization-color :color} (rf/sub [:onboarding/profile])
all-requirements-met? (and (:non-empty? password-validations)
(:long-enough? password-validations)
(:short-enough? password-validations)
same-passwords?)]
[rn/view {:style style/footer-container}
[help password-validations]
[quo/button
{:container-style style/footer-button-container
:disabled? (not all-requirements-met?)
:customization-color customization-color
:on-press on-submit}
(i18n/label :t/password-creation-confirm)]]))
(defn- on-confirm-password
[password]
(rf/dispatch [:onboarding/password-set (security/mask-data password)]))
(defn create-password
[]
(let [[password set-password] (rn/use-state "")
[repeat-password set-repeat-password] (rn/use-state "")
[accepts-disclaimer? set-accepts-disclaimer?] (rn/use-state false)
[focused-input set-focused-input] (rn/use-state nil)
[show-password-validation?
set-show-password-validation?] (rn/use-state false)
{user-color :color} (rf/sub [:onboarding/profile])
{:keys [password-long-enough?
password-short-enough?
password-validations password-strength
empty-password?]} (use-password-checks password)
{:keys [same-password-length? same-passwords?]} (use-repeat-password-checks password
repeat-password)
meet-requirements? (and (not empty-password?)
password-long-enough?
password-short-enough?
same-passwords?
accepts-disclaimer?)]
(let [[password set-password] (rn/use-state "")
[repeat-password
set-repeat-password] (rn/use-state "")
{:keys [long-enough? short-enough? non-empty?]
:as password-validations} (use-password-checks password)
{:keys [same-password-length?
same-passwords?]} (use-repeat-password-checks password repeat-password)
on-submit (rn/use-callback
#(on-confirm-password password)
[password])
top (safe-area/get-top)]
[floating-button/view
{:header [page-nav]
:keyboard-should-persist-taps :handled
:content-avoid-keyboard? true
{:header [page-nav top]
:initial-header-height (+ style/page-nav-height top)
:keyboard-should-persist-taps :handled
:content-avoid-keyboard? true
:automatically-adjust-keyboard-insets true
:blur-options
{:blur-amount 34
:blur-radius 20
:blur-type :transparent
:overlay-color :transparent
:background-color (if platform/android? colors/neutral-100 colors/neutral-80-opa-1-blur)
:padding-vertical 0
:padding-horizontal 0}
:footer-container-padding 0
:footer
[rn/view
{:style style/footer-container}
(when same-passwords?
[rn/view {:style style/disclaimer-container}
[quo/disclaimer
{:blur? true
:on-change (partial set-accepts-disclaimer? not)
:checked? accepts-disclaimer?
:customization-color user-color}
(i18n/label :t/password-creation-disclaimer)]])
(when (and (= focused-input :password) (not same-passwords?))
[help
{:validations password-validations
:password-strength password-strength}])
[quo/button
{:container-style style/footer-button-container
:disabled? (not meet-requirements?)
:customization-color user-color
:on-press #(rf/dispatch
[:onboarding/password-set
(security/mask-data password)])}
(i18n/label :t/password-creation-confirm)]]}
:blur-options style/blur-options
:footer-container-padding 0
:footer [help-and-confirm-button
{:password-validations password-validations
:same-passwords? same-passwords?
:on-submit on-submit}]}
[rn/view {:style style/form-container}
[header]
[password-inputs
{:password-long-enough? password-long-enough?
:password-short-enough? password-short-enough?
:passwords-match? same-passwords?
:empty-password? empty-password?
:show-password-validation? show-password-validation?
:on-input-focus #(set-focused-input :password)
:on-change-password (fn [new-value]
(set-password new-value)
(when same-password-length?
(set-show-password-validation? true)))
:on-change-repeat-password (fn [new-value]
(set-repeat-password new-value)
(when same-password-length?
(set-show-password-validation? true)))
:on-blur-repeat-password #(if empty-password?
(set-show-password-validation? false)
(set-show-password-validation? true))}]]]))
{:password-long-enough? long-enough?
:password-short-enough? short-enough?
:non-empty-password? non-empty?
:same-passwords? same-passwords?
:same-password-length? same-password-length?
:set-password set-password
:set-repeat-password set-repeat-password}]]]))
@@ -1,60 +0,0 @@
(ns status-im.contexts.onboarding.create-profile.style
(:require
[quo.foundations.colors :as colors]
[react-native.platform :as platform]))
(def continue-button
{:width "100%"
:margin-left :auto
:margin-top (if platform/android? :auto 0)
:margin-right :auto})
(def button-container
{:width "100%"
:padding-left 20
:padding-right 20
:padding-top 12
:align-self :flex-end
:height 64})
(defn view-button-container
[keyboard-shown?]
(merge button-container
(if platform/ios?
{:margin-bottom (if keyboard-shown? 0 34)}
{:margin-bottom (if keyboard-shown? 12 34)})))
(def blur-button-container
(merge button-container
(when platform/android? {:padding-bottom 12})))
(def page-container
{:position :absolute
:top 0
:bottom 0
:left 0
:right 0
:z-index 100})
(def info-message
{:margin-top 8})
(def title
{:color colors/white
:margin-top 12
:margin-bottom 18})
(def color-title
{:color colors/white-70-blur
:margin-top 20
:margin-bottom 16})
(def content-container
{:padding-horizontal 20})
(def input-container
{:align-items :flex-start})
(def profile-input-container
{:flex-direction :row
:justify-content :center})
@@ -1,210 +0,0 @@
(ns status-im.contexts.onboarding.create-profile.view
(:require
[clojure.string :as string]
[oops.core :as oops]
[quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.hooks :as hooks]
[react-native.platform :as platform]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.common.avatar-picture-picker.view :as profile-picture-picker]
[status-im.common.validation.profile :as profile-validator]
[status-im.constants :as c]
[status-im.contexts.onboarding.create-profile.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.responsiveness :as responsiveness]))
(def scroll-view-height (reagent/atom 0))
(def content-container-height (reagent/atom 0))
(defn show-button-background
[keyboard-height keyboard-shown content-scroll-y]
(let [button-container-height 64
keyboard-view-height (+ keyboard-height button-container-height)]
(when keyboard-shown
(cond
platform/android?
(< (- @scroll-view-height button-container-height) @content-container-height)
platform/ios?
(< (- @scroll-view-height keyboard-view-height) (- @content-container-height content-scroll-y))
:else
false))))
(defn button-container
[show-keyboard? keyboard-shown show-background? keyboard-height children]
(let [height (reagent/atom 0)]
(reset! height (if show-keyboard? (if keyboard-shown keyboard-height 0) 0))
[rn/view {:style {:margin-top :auto}}
(cond
(and (> @height 0) show-background?)
[quo/blur
(when keyboard-shown
{:blur-amount 34
:blur-type :transparent
:overlay-color :transparent
:background-color (if platform/android? colors/neutral-100 colors/neutral-80-opa-1-blur)
:style style/blur-button-container})
children]
(and (> @height 0) (not show-background?))
[rn/view {:style (style/view-button-container true)}
children]
(not show-keyboard?)
[rn/view {:style (style/view-button-container false)}
children])]))
(defn- page
[{:keys [onboarding-profile-data navigation-bar-top]}]
(reagent/with-let [show-keyboard? (reagent/atom false)
content-scroll-y (reagent/atom 0)
show-listener (oops/ocall rn/keyboard
"addListener"
(if platform/android?
"keyboardDidShow"
"keyboardWillShow")
#(reset! show-keyboard? true))
hide-listener (oops/ocall rn/keyboard
"addListener"
(if platform/android?
"keyboardDidHide"
"keyboardWillHide")
#(reset! show-keyboard? false))
{:keys [image-path display-name color]} onboarding-profile-data
full-name (reagent/atom display-name)
validation-msg (reagent/atom
(profile-validator/validation-name
@full-name))
on-change-text (fn [s]
(reset! validation-msg
(profile-validator/validation-name
s))
(reset! full-name (string/trim s)))
custom-color (reagent/atom (or color
c/profile-default-color))
profile-pic (reagent/atom image-path)
on-change-profile-pic #(reset! profile-pic %)
on-change #(reset! custom-color %)]
(let [name-too-short? (profile-validator/name-too-short? @full-name)
valid-name? (and (not @validation-msg) (not name-too-short?))
info-message (if @validation-msg
@validation-msg
(i18n/label :t/minimum-characters
{:min-chars
profile-validator/min-length}))
info-type (cond @validation-msg :error
name-too-short? :default
:else :success)
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
show-background? (show-button-background keyboard-height
keyboard-shown
@content-scroll-y)
{window-width :width} (rn/get-window)]
[rn/view {:style style/page-container}
[quo/page-nav
{:margin-top navigation-bar-top
:background :blur
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back])}]
[rn/scroll-view
{:on-layout (fn [event]
(let [height (oops/oget event "nativeEvent.layout.height")]
(reset! scroll-view-height height)
(reset! content-scroll-y 0)))
:on-scroll (fn [event]
(let [y (oops/oget event "nativeEvent.contentOffset.y")]
(reset! content-scroll-y y)))
:scroll-event-throttle 64
:content-container-style {:flexGrow 1}}
[rn/view
{:on-layout (fn [event]
(let [height (oops/oget event "nativeEvent.layout.height")]
(reset! content-container-height height)))}
[rn/view
{:style style/content-container}
[quo/text
{:size :heading-1
:weight :semi-bold
:style style/title} (i18n/label :t/create-profile)]
[rn/view
{:style style/input-container}
[rn/view
{:style style/profile-input-container}
[quo/profile-input
{:customization-color @custom-color
:placeholder (i18n/label :t/your-name)
:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch
[:show-bottom-sheet
{:content (fn []
[profile-picture-picker/view
{:on-result on-change-profile-pic
:has-picture? false}])
:shell? true}]))
:image-picker-props {:profile-picture @profile-pic
:full-name (if (seq @full-name)
@full-name
(i18n/label :t/your-name))
:customization-color @custom-color}
:title-input-props {:default-value display-name
:auto-focus true
:max-length c/profile-name-max-length
:on-change-text on-change-text}}]]
[quo/info-message
{:status info-type
:size :default
:icon (if valid-name? :i/positive-state :i/info)
:color (when (= :default info-type) colors/white-70-blur)
:container-style style/info-message}
info-message]
[quo/text
{:size :paragraph-2
:weight :medium
:style style/color-title}
(i18n/label :t/accent-colour)]]]
[quo/color-picker
{:blur? true
:default-selected :blue
:on-change on-change
:window-width window-width
:container-style {:padding-left (responsiveness/iphone-11-Pro-20-pixel-from-width
window-width)}}]]]
[rn/keyboard-avoiding-view
{:style {:position :absolute
:top 0
:bottom 0
:left 0
:right 0}
:pointer-events :box-none}
[button-container @show-keyboard? keyboard-shown show-background? keyboard-height
[quo/button
{:accessibility-label :submit-create-profile-button
:type :primary
:customization-color @custom-color
:on-press (fn []
(rf/dispatch [:onboarding/profile-data-set
{:image-path @profile-pic
:display-name @full-name
:color @custom-color}]))
:container-style style/continue-button
:disabled? (or (not valid-name?) (not (seq @full-name)))}
(i18n/label :t/continue)]]]])
(finally
(oops/ocall show-listener "remove")
(oops/ocall hide-listener "remove"))))
(defn create-profile
[]
(let [{:keys [top]} (safe-area/get-insets)
onboarding-profile-data (rf/sub [:onboarding/profile])]
[page
{:navigation-bar-top top
:onboarding-profile-data onboarding-profile-data}]))
+83 -71
View File
@@ -1,5 +1,6 @@
(ns status-im.contexts.onboarding.events
(:require
[quo.foundations.colors :as colors]
[re-frame.core :as re-frame]
status-im.common.biometric.events
[status-im.constants :as constants]
@@ -111,63 +112,57 @@
(rf/reg-event-fx
:onboarding/password-set
(fn [{:keys [db]} [masked-password]]
(let [biometric-supported-type (get-in db [:biometrics :supported-type])]
(let [biometric-supported-type (get-in db [:biometrics :supported-type])
from-screen (get db
:onboarding/navigated-to-enter-seed-phrase-from-screen
:screen/onboarding.new-to-status)]
{:db (-> db
(assoc-in [:onboarding/profile :password] masked-password)
(assoc-in [:onboarding/profile :auth-method] constants/auth-method-password))
:fx [[:dispatch
(if biometric-supported-type
[:navigate-to-within-stack
[:screen/onboarding.enable-biometrics
(get db
:onboarding/navigated-to-enter-seed-phrase-from-screen
:screen/onboarding.new-to-status)]]
[:navigate-to-within-stack [:screen/onboarding.enable-biometrics from-screen]]
[:onboarding/create-account-and-login])]]})))
(rf/defn navigate-to-enable-biometrics
{:events [:onboarding/navigate-to-enable-biometrics]}
[{:keys [db]}]
(let [supported-type (get-in db [:biometrics :supported-type])]
{:dispatch (if supported-type
[:open-modal :screen/onboarding.enable-biometrics]
[:open-modal :screen/onboarding.enable-notifications])}))
(rf/reg-event-fx
:onboarding/navigate-to-enable-biometrics
(fn [{:keys [db]}]
(let [supported-type (get-in db [:biometrics :supported-type])]
{:dispatch (if supported-type
[:open-modal :screen/onboarding.enable-biometrics]
[:open-modal :screen/onboarding.enable-notifications])})))
(rf/defn seed-phrase-validated
{:events [:onboarding/seed-phrase-validated]}
[{:keys [db]} seed-phrase key-uid]
(let [syncing-account-recovered? (and (seq (:syncing/key-uid db))
(= (:syncing/key-uid db) key-uid))
next-screen (if syncing-account-recovered?
:screen/onboarding.create-profile-password
:screen/onboarding.create-profile)]
(if (contains? (:profile/profiles-overview db) key-uid)
{:effects.utils/show-confirmation
{:title (i18n/label :t/multiaccount-exists-title)
:content (i18n/label :t/multiaccount-exists-content)
:confirm-button-text (i18n/label :t/unlock)
:on-accept (fn []
(re-frame/dispatch [:pop-to-root :screen/profile.profiles])
(re-frame/dispatch
[:profile/profile-selected key-uid]))
:on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}}
{:db (-> db
(assoc-in [:onboarding/profile :seed-phrase] seed-phrase)
(assoc-in [:onboarding/profile :key-uid] key-uid)
(assoc-in [:onboarding/profile :color] constants/profile-default-color))
:fx [[:dispatch
[:navigate-to-within-stack
[next-screen
(get db
:onboarding/navigated-to-enter-seed-phrase-from-screen
:screen/onboarding.new-to-status)]]]]})))
(rf/reg-event-fx
:onboarding/seed-phrase-validated
(fn [{:keys [db]} [seed-phrase key-uid]]
(let [next-screen :screen/onboarding.create-profile-password
from-screen (get db
:onboarding/navigated-to-enter-seed-phrase-from-screen
:screen/onboarding.new-to-status)]
(if (contains? (:profile/profiles-overview db) key-uid)
{:fx [[:effects.utils/show-confirmation
{:title (i18n/label :t/multiaccount-exists-title)
:content (i18n/label :t/multiaccount-exists-content)
:confirm-button-text (i18n/label :t/unlock)
:on-accept (fn []
(re-frame/dispatch [:pop-to-root :screen/profile.profiles])
(re-frame/dispatch [:profile/profile-selected key-uid]))
:on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}]]}
{:db (-> db
(assoc-in [:onboarding/profile :seed-phrase] seed-phrase)
(assoc-in [:onboarding/profile :key-uid] key-uid)
(assoc-in [:onboarding/profile :color] constants/profile-default-color))
:fx [[:dispatch [:navigate-to-within-stack [next-screen from-screen]]]]}))))
(rf/defn navigate-to-create-profile
{:events [:onboarding/navigate-to-create-profile]}
[{:keys [db]}]
;; Restart the flow
{:db (dissoc db :onboarding/profile)
:dispatch [:navigate-to-within-stack
[:screen/onboarding.create-profile :screen/onboarding.new-to-status]]})
(rf/reg-event-fx
:onboarding/navigate-to-create-profile
(fn [{:keys [db]}]
{:db (-> db
(assoc-in [:onboarding/profile :color] (rand-nth colors/account-colors))
(update :onboarding/profile dissoc :image-path))
:fx [[:dispatch
[:navigate-to-within-stack
[:screen/onboarding.create-profile-password :screen/onboarding.new-to-status]]]]}))
(rf/reg-event-fx :onboarding/navigate-to-sign-in-by-syncing
(fn [{:keys [db]}]
@@ -180,26 +175,43 @@
(fn [{:keys [db]} [auth-method]]
{:db (assoc db :auth-method auth-method)}))
(rf/defn onboarding-new-account-finalize-setup
{:events [:onboarding/finalize-setup]}
[{:keys [db]}]
(let [masked-password (get-in db [:onboarding/profile :password])
key-uid (get-in db [:profile/profile :key-uid])
syncing? (get-in db [:onboarding/profile :syncing?])
auth-method (get-in db [:onboarding/profile :auth-method])
biometric-enabled? (= auth-method constants/auth-method-biometric)]
(cond-> {:db (assoc db :onboarding/generated-keys? true)}
biometric-enabled?
(assoc :keychain/save-password-and-auth-method
{:key-uid key-uid
:masked-password (if syncing?
masked-password
(security/hash-masked-password masked-password))
:on-success (fn []
(rf/dispatch [:onboarding/set-auth-method auth-method])
(when syncing?
(rf/dispatch
[:onboarding/navigate-to-enable-notifications-from-syncing])))
:on-error #(log/error "failed to save biometrics"
{:key-uid key-uid
:error %})}))))
(def ^:const temp-display-name
"While creating a profile, we cannot use an empty string; this value works as a
placeholder that will be updated later once the compressed key exists. See
`status-im.contexts.profile.edit.name.events/get-default-display-name` for more details."
"temporal username")
(rf/reg-event-fx
:onboarding/use-temporary-display-name
(fn [{:keys [db]} [temporary-display-name?]]
{:db (assoc db
:onboarding/profile
{:temporary-display-name? temporary-display-name?
:display-name (if temporary-display-name?
temp-display-name
"")})}))
(rf/reg-event-fx
:onboarding/finalize-setup
(fn [{db :db}]
(let [{:keys [password syncing? auth-method
temporary-display-name?]} (:onboarding/profile db)
{:keys [key-uid] :as profile} (:profile/profile db)
biometric-enabled? (= auth-method constants/auth-method-biometric)]
{:db (assoc db :onboarding/generated-keys? true)
:fx [(when temporary-display-name?
[:dispatch [:profile/set-default-profile-name profile]])
(when biometric-enabled?
[:keychain/save-password-and-auth-method
{:key-uid key-uid
:masked-password (if syncing?
password
(security/hash-masked-password password))
:on-success (fn []
(rf/dispatch [:onboarding/set-auth-method auth-method])
(when syncing?
(rf/dispatch
[:onboarding/navigate-to-enable-notifications-from-syncing])))
:on-error #(log/error "failed to save biometrics"
{:key-uid key-uid
:error %})}])]})))
@@ -52,6 +52,7 @@
[]
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
(blur-show-fn))
(rf/dispatch [:onboarding/use-temporary-display-name false])
(rf/dispatch [:open-modal
:screen/onboarding.share-usage
{:next-screen :screen/onboarding.sync-or-recover-profile}]))
@@ -60,6 +61,7 @@
[]
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
(blur-show-fn))
(rf/dispatch [:onboarding/use-temporary-display-name true])
(rf/dispatch [:open-modal :screen/onboarding.share-usage
{:next-screen :screen/onboarding.new-to-status}]))
@@ -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
@@ -1,5 +1,7 @@
(ns status-im.contexts.profile.edit.name.events
(:require [utils.i18n :as i18n]
(:require [clojure.string :as string]
[status-im.constants :as constants]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(rf/reg-event-fx :profile/edit-profile-name-success
@@ -20,3 +22,16 @@
:on-success [:profile/edit-profile-name-success]}]]]})
(rf/reg-event-fx :profile/edit-name edit-profile-name)
(defn display-name-from-compressed-key
[profile]
(-> profile :compressed-key (string/split #"zQ3") second (subs 0 constants/profile-name-max-length)))
(rf/reg-event-fx
:profile/set-default-profile-name
(fn [{db :db} [profile]]
(let [default-display-name (display-name-from-compressed-key profile)]
{:db (assoc-in db [:profile/profile :display-name] default-display-name)
:fx [[:json-rpc/call
[{:method "wakuext_setDisplayName"
:params [default-display-name]}]]]})))
@@ -37,7 +37,6 @@
{:dataDir (native-module/backup-disabled-data-dir)
:mixpanelAppId config/mixpanel-app-id
:mixpanelToken config/mixpanel-token
:sentryDSN config/sentry-dsn-status-go
:mediaServerEnableTLS (config/enabled? config/STATUS_BACKEND_SERVER_MEDIA_SERVER_ENABLE_TLS)
:logEnabled (not (string/blank? config/log-level))
:logLevel config/log-level
@@ -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]]]
@@ -152,15 +155,12 @@
(rf/reg-event-fx
:profile.login/login-node-signal
(fn [{{:onboarding/keys [recovered-account? new-account?] :as db} :db}
[{:keys [settings account ensUsernames error]}]]
(fn [{db :db} [{:keys [settings account ensUsernames error]}]]
(log/debug "[signals] node.login" "error" error)
(if error
{:db (update db :profile/login #(-> % (dissoc :processing) (assoc :error error)))}
{:db (dissoc db :profile/login)
:fx [(when (and new-account? (not recovered-account?))
[:dispatch-later [{:ms 1000 :dispatch [:wallet-legacy/set-initial-blocks-range]}]])
[:dispatch-later [{:ms 2000 :dispatch [:ens/update-usernames ensUsernames]}]]
:fx [[:dispatch-later [{:ms 2000 :dispatch [:ens/update-usernames ensUsernames]}]]
[:dispatch [:profile.login/login-existing-profile settings account]]]})))
(rf/reg-event-fx
@@ -47,6 +47,7 @@
[]
(when @push-animation-fn-atom
(@push-animation-fn-atom))
(rf/dispatch [:onboarding/use-temporary-display-name true])
(debounce/throttle-and-dispatch
[:open-modal :screen/onboarding.new-to-status]
1000))
@@ -55,6 +56,7 @@
[]
(when @push-animation-fn-atom
(@push-animation-fn-atom))
(rf/dispatch [:onboarding/use-temporary-display-name false])
(debounce/throttle-and-dispatch
[:open-modal :screen/onboarding.sync-or-recover-profile]
1000))
@@ -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 -1
View File
@@ -2,7 +2,6 @@
(:require
status-im.common.alert-banner.events
status-im.common.alert.effects
status-im.common.app-monitoring.events
status-im.common.async-storage.effects
status-im.common.emoji-picker.events
status-im.common.font.events
@@ -28,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 -3
View File
@@ -11,14 +11,13 @@
(def ^:private initial-flags
{::community.edit-account-selection (enabled-in-env? :FLAG_EDIT_ACCOUNT_SELECTION_ENABLED)
::app-monitoring.intentional-crash true ; (enabled-in-env? :FLAG_INTENTIONAL_CRASH_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 -80
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]
@@ -43,7 +45,6 @@
[status-im.contexts.keycard.pin.enter.view :as keycard.pin.enter]
[status-im.contexts.onboarding.create-or-sync-profile.view :as create-or-sync-profile]
[status-im.contexts.onboarding.create-password.view :as create-password]
[status-im.contexts.onboarding.create-profile.view :as create-profile]
[status-im.contexts.onboarding.enable-biometrics.view :as enable-biometrics]
[status-im.contexts.onboarding.enable-notifications.view :as enable-notifications]
[status-im.contexts.onboarding.identifiers.view :as identifiers]
@@ -74,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]
@@ -154,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}
@@ -194,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}
@@ -208,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}])
@@ -312,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
@@ -372,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}
@@ -406,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}])
@@ -728,16 +745,6 @@
:modalPresentationStyle :overCurrentContext}
:component create-or-sync-profile/sync-or-recover-profile})
(def onboarding-create-profile
{:name :screen/onboarding.create-profile
:metrics {:track? true
:alias-id :onboarding.create-profile-info}
:options {:theme :dark
:layout options/onboarding-transparent-layout
:animations transitions/push-animations-for-transparent-background
:popGesture false}
:component create-profile/create-profile})
(def onboarding-create-profile-password
{:name :screen/onboarding.create-profile-password
:metrics {:track? true
@@ -768,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})
@@ -872,7 +877,6 @@
[onboarding-intro
onboarding-new-to-status
onboarding-sync-or-recover-profile
onboarding-create-profile
onboarding-create-profile-password
onboarding-enable-biometrics
onboarding-preparing-status
@@ -888,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
@@ -938,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
@@ -947,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
@@ -956,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))
+14 -8
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)})))
@@ -711,13 +719,11 @@
(rf/reg-sub
:wallet/zero-balance-in-all-non-watched-accounts?
:<- [:wallet/aggregated-tokens]
:<- [:profile/currency]
:<- [:wallet/prices-per-token]
(fn [[aggregated-tokens currency prices-per-token]]
(let [balance (utils/calculate-balance-from-tokens {:currency currency
:tokens aggregated-tokens
:prices-per-token prices-per-token})]
(and (not-empty aggregated-tokens) (money/equal-to balance 0)))))
(fn [aggregated-tokens]
(let [zero-balance? (->> aggregated-tokens
(mapcat (comp vals :balances-per-chain))
(every? #(money/equal-to (:raw-balance %) 0)))]
(and (not-empty aggregated-tokens) zero-balance?))))
(rf/reg-sub
:wallet/network-preference-details
+147
View File
@@ -1008,3 +1008,150 @@
(update accounts "0x2" assoc :operable :partially)))
(is (true? (rf/sub [sub-name])))))
(h/deftest-sub :wallet/zero-balance-in-all-non-watched-accounts?
[sub-name]
(testing "returns true if the balance is zero in all non-watched accounts"
(swap! rf-db/app-db
#(assoc-in %
[:wallet :accounts]
{"0x1" {:address "0x1"
:watch-only? false
:tokens
[{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}}}
{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}}}]}
"0x2" {:address "0x2"
:watch-only? false
:tokens
[{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}}}
{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}}}]}
"0x3"
{:address "0x3"
:watch-only? true
:tokens [{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance
(money/bignumber
"2")
:has-error false}
constants/optimism-mainnet-chain-id {:raw-balance
(money/bignumber
"1")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance
(money/bignumber
"0")
:has-error false}}}
{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance
(money/bignumber
"0")
:has-error false}
constants/optimism-mainnet-chain-id {:raw-balance
(money/bignumber
"2")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance
(money/bignumber
"0")
:has-error
false}}}]}}))
(is (true? (rf/sub [sub-name]))))
(testing "returns false if the balance is not zero in all non-watched accounts"
(swap! rf-db/app-db
#(assoc-in %
[:wallet :accounts]
{"0x1" {:address "0x1"
:watch-only? false
:tokens
[{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
"2")
:has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
"1")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}}}
{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
"2")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}}}]}
"0x2" {:address "0x2"
:watch-only? true
:tokens
[{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
"2")
:has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
"1")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}}}
{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
"0")
:has-error false}
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
"2")
:has-error false}
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
"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])))))
+9 -6
View File
@@ -126,9 +126,12 @@
(def status
(clj->js
{:intendedPanic identity
:getNodeConfig (fn [] (types/clj->json {:WakuV2Config ""}))
:addCentralizedMetric (fn [_ callback]
(callback))
:fleets (fn [] (.fleets native-status))
:startLocalNotifications identity}))
{:getNodeConfig
(fn [] (types/clj->json {:WakuV2Config ""}))
:addCentralizedMetric
(fn [_ callback]
(callback))
:fleets
(fn [] (.fleets native-status))
:startLocalNotifications
identity}))
+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

Some files were not shown because too many files have changed in this diff Show More