Compare commits

...
Author SHA1 Message Date
Lungu Cristian 6215acdd23 feat: dismiss handler for modals 2024-07-22 13:10:51 +03:00
Icaro Motta cec46f985a chore(style): Sort JSON keys in translations/en.json (#20785)
Sorts keys (non-recursively) in translations/en.json. The solution uses
the prettier plugin https://github.com/Gudahtt/prettier-plugin-sort-json.

We only format translations/en.json because it’s the only file we need to
manually change.

- Dependency added: prettier-plugin-sort-json version 4.0.0
- Dependency upgraded: prettier, from version 2.8.8 to 3.3.3.
2024-07-21 22:39:50 -03:00
Volodymyr Kozieiev 06b2996167 Do not update disabled networks when receiver network updated (#20756) 2024-07-19 15:10:13 +01:00
Lungu Cristian 02e24208db Wallet Connect transactions (#20755)
* feat: updated signing endpoints and refactor

https://github.com/status-im/status-go/compare/6e056348...e8aec741

* fix: using the generic warning at the bottom

* fix: show parsed transaction parameters

* feat: adding fees to transactions

https://github.com/status-im/status-go/compare/6e056348...b2e5e7a8

* feat: added fees

* feat: added eip-1559 fee estimation & tx priority

* feat: added fees and failed processing handling

* fix: show testnet name in the request

* fix: address review comments

* feat: added max-fee color when not enough balance

* ref: broke down tx fees subscription

* fix: handle gas estimation on status-go

https://github.com/status-im/status-go/compare/1ef2434b...5389f281

* fix: don't overwrite dynamic fees if already there

* fix: malli schema and review comments

* fix: addressed review comments 1

* fix: addressed comments 2

* fix: removed unused require

* fix: addressed QA review

https://github.com/status-im/status-go/compare/484b8aca...d07f9b5b

* fix: requests being shown simultaneously

* fix: removed support for eth_signTransaction
2024-07-19 14:16:51 +03:00
frank 84b8943fd4 fix_:still return the image when image server is unable to get public key (#20538)
https://github.com/status-im/status-go/compare/cba3ac57...4a43b2b2
2024-07-19 17:17:53 +08:00
Ajay Sivan c52b3e457e Wallet/Swap Input Component (#20318) 2024-07-19 01:00:38 -07:00
Omar Basem 21cc8a199a fix: button width (#20792)
* fix: button width (#20792)
2024-07-19 08:13:50 +04:00
Yevheniia Berdnyk 59374543ef e2e: disabled activity verification in wallet tests 2024-07-18 19:45:20 +03:00
Alexander 9f84a7b912 A pack of bugfixes for the user story "Connect to dApps" (#20711) 2024-07-18 14:57:53 +02:00
Vit∀ly Vlasov 2b0847ef76 fix_: ui part for share-all-future-addresses storage (PR #20549) (#20549)
Related status-go PR: https://github.com/status-im/status-go/pull/5354

https://github.com/status-im/status-go/compare/6e056348...8458cafe

Signed-off-by: Vitaly Vlasov <mail@vitv.ly>
2024-07-18 15:36:38 +03:00
Yevheniia Berdnyk 97b19c5440 e2e: fixes for wallet and deep/universal links tests 2024-07-18 00:52:06 +03:00
Icaro Motta b3e88508ac chore(activity-center): Various small refactors (#20690)
Potentially a solution to https://github.com/status-im/status-mobile/issues/15706

- [x] Fixes swipe button on Android and iOS.
- [x] Performance: we now subscribe only to the minimum from each community.
      This could be the reason the AC would lag as described in the parent
      issue.
- [x] Performance: was able to use flex and removed swipe button height
      calculation that was using `onLayout` and was causing a re-render.
- [x] Performance: reduced the initial number of items to render in the flatlist
      from 10 to 7.
- [x] Performance: delay rendering the heavy list of notification components.
      See in the video below how slow it is to open the AC with just 6
      notifications and that the opening animation is never displayed. And then
      check the improved version with the artificial delay provided by
      `rn/delay-render`. By opening the AC first and animating, this gives the
      user something to look for, and hopefully a few milliseconds more to think
      the app is not stuck, which will be preciously used to render
      notifications.

We refactor all views in the AC to:

- [x] Follow our newest standards with React hooks.
- [x] Removed prop-drilling by creating a separate React context to store the
      current swipeable item (because we need to call `.close` on a `Gesture
      Swipeable` instance whenever a new swipeable opens.
2024-07-17 12:16:06 -03:00
Mohsen 7b09402fcb [#20742] fix: blue background behind the "Save address" button (#20754) 2024-07-17 16:04:40 +03:30
mmilad75 a912125ba9 Token value shows fiat value on the transaction confirmation page #20734 (#20770) 2024-07-17 10:47:27 +02:00
Ulises Manuel 2d0437dd5e fix(wallet): Improvements on activity tab (#20703)
* Fix schema for networks in context-tags

* Fix wallet-activity component overflowing the activity tab

* Improve robustness of the activity tab fetching mechanism

* Handle `wallet-activity-filtering-entries-updated` signal

* Improve processing of data received for the activity tab
2024-07-16 15:07:33 -06:00
Parvesh Monu 43651ef0d0 Adjust on-boarding illustrations position and scale (#20692) 2024-07-16 20:43:19 +05:30
Yevheniia Berdnyk 13232dc7b7 e2e: updated create profile flow 2024-07-16 15:46:23 +01:00
Andrea Maria Piana 93b5f7a918 Add confirmation to centralized metrics
This commit add a confirmation for centralized metrics.
It is added in 3 places:

1) Onboarding -> Create new account
2) Onboarding -> Sync profile
3) On the accounts view if the user is upgrading

To test 1 & 2, you should just be able to do that on a newly installed
device.

To test 3, you will have to upgrade from a PR without this feature that
has at least an account. It should show the confirmation modal until you
either click on Not now or Share usage data.

The modal should also be added in settings, but I will do that as a
separate PR.
2024-07-16 15:46:23 +01:00
Mohsen 4898d32243 [#20664] feat: add share usage data confirmation modal 2024-07-16 15:46:23 +01:00
107 changed files with 4936 additions and 3906 deletions
+14 -9
View File
@@ -1,10 +1,15 @@
*
/*
# Format top-level js files.
!*.js
!*/
*.clj-kondo
*.shadow-cljs
modules
result
target
component-spec
/app
# Ignore all except src/js/**/*.js
!/src/
/src/*
!/src/js
!/src/js/**/*.js
# Ignore all except translations/en.json
!/translations/
/translations/*
!/translations/en.json
+4
View File
@@ -6,4 +6,8 @@ module.exports = {
tabWidth: 2,
trailingComma: 'all',
useTabs: false,
// JSON sorting
jsonSortOrder: '{ "/.*/": "caseInsensitiveLexical" } ',
plugins: ['prettier-plugin-sort-json'],
};
+1 -1
View File
@@ -317,7 +317,7 @@ lint: ##@test Run code style checks
scripts/lint/translations.clj && \
zprint '{:search-config? true}' -sfc $$ALL_CLOJURE_FILES && \
sh scripts/lint/trailing-newline.sh && \
node_modules/.bin/prettier --write .
node_modules/.bin/prettier --check .
# NOTE: We run the linter twice because of https://github.com/kkinnear/zprint/issues/271
lint-fix: export TARGET := clojure
+2 -1
View File
@@ -97,7 +97,8 @@
"jest-silent-reporter": "^0.5.0",
"nodemon": "^2.0.16",
"nyc": "^14.1.1",
"prettier": "^2.8.8",
"prettier": "^3.3.3",
"prettier-plugin-sort-json": "^4.0.0",
"process": "0.11.10",
"react-test-renderer": "18.1.0",
"shadow-cljs": "2.26.2",
@@ -1,5 +1,6 @@
(ns quo.components.avatars.token-avatar.view
(:require [quo.components.avatars.token-avatar.style :as style]
[quo.components.utilities.token.view :as token]
[react-native.core :as rn]
[react-native.hole-view :as hole-view]
[react-native.platform :as platform]
@@ -12,13 +13,14 @@
[:map {:closed true}
[:type {:optional true} [:enum :asset :collectible]]
[:context? {:optional true} [:maybe :boolean]]
[:image :schema.common/image-source]
[:image {:optional true} [:maybe :schema.common/image-source]]
[:token {:optional true} [:maybe [:or :keyword :string]]]
[:network-image {:optional true} [:maybe :schema.common/image-source]]
[:container-style {:optional true} [:maybe :map]]]]]
:any])
(defn- view-internal
[{:keys [type context? image network-image container-style]}]
[{:keys [type context? image token network-image container-style]}]
[rn/view
{:style (merge style/container container-style)
:accessibility-label :token-avatar}
@@ -32,9 +34,11 @@
[])
:style style/hole-view}
platform/android? (assoc :key context?))
[rn/image
{:source image
:style (style/image type)}]]
[token/view
{:size :size-32
:token token
:style (style/image type)
:image-source image}]]
(when context?
[rn/image
{:source network-image
@@ -21,15 +21,17 @@
(colors/theme-colors colors/white colors/neutral-95 theme))})
(defn buttons-container
[actions]
{:flex-direction (if (= actions :two-vertical-actions) :column :row)
:justify-content :space-around
:padding-vertical 12
:gap 12
:padding-horizontal 20})
[actions container-style]
(merge
{:flex-direction (if (= actions :two-vertical-actions) :column :row)
:justify-content :space-around
:padding-vertical 12
:gap 12
:padding-horizontal 20}
container-style))
(def button-container
{:flex 1})
{:flex-grow 1})
(def description-top
{:flex-direction :row
@@ -30,7 +30,8 @@
[:button-two-props {:optional true} [:maybe :map]]
[:scroll? {:optional true} [:maybe :boolean]]
[:blur? {:optional true} [:maybe :boolean]]
[:container-style {:optional true} [:maybe :map]]]]]
[:container-style {:optional true} [:maybe :map]]
[:buttons-container-style {:optional true} [:maybe :map]]]]]
:any])
(def ^:private role-icon
@@ -42,7 +43,7 @@
(defn- view-internal
[{:keys [actions description description-text description-top-text error-message role button-one-label
button-two-label blur? button-one-props button-two-props scroll? container-style
context-tag-props]}]
buttons-container-style context-tag-props]}]
(let [theme (quo.theme/use-theme)]
[rn/view
{:style (merge (style/container scroll? blur? theme) container-style)}
@@ -72,14 +73,14 @@
:context (i18n/label (keyword "t" role))}
context-tag-props)]])
[rn/view {:style (style/buttons-container actions)}
[rn/view {:style (style/buttons-container actions buttons-container-style)}
(when (or (= actions :two-actions)
(= actions :two-vertical-actions))
[button/button
(merge
{:size 40
:background (when (or blur? scroll?) :blur)
:container-style style/button-container
:background (when (or blur? scroll?) :blur)
:theme theme
:accessibility-label :button-two}
button-two-props)
@@ -121,6 +121,7 @@
[:card? {:optional true} [:maybe :boolean]]
[:right-icon {:optional true} [:maybe :keyword]]
[:right-content {:optional true} [:maybe :map]]
[:icon-color {:optional true} [:maybe :schema.common/customization-color]]
[:status {:optional true} [:maybe [:enum :default :loading]]]
[:subtitle-type {:optional true} [:maybe [:enum :default :icon :network :account :editable]]]
[:size {:optional true} [:maybe [:enum :default :small :large]]]
@@ -53,7 +53,7 @@
(def ^:private ?network
[:map
[:network-logo {:optional true} [:maybe :schema.common/image-source]]
[:network-name {:optional true} [:maybe :string]]])
[:network-name {:optional true} [:maybe [:or :string :keyword]]]])
(def ^:private ?multinetwork
[:map
@@ -41,7 +41,8 @@
:align-items :center
:height size
:background-color background-color
:border-radius border-radius}
:border-radius border-radius
:flex-shrink 1}
(= state :selected) (assoc :height (+ size 2)
:border-color border-color
:border-width 1))))
@@ -50,11 +51,13 @@
[size]
{:margin-right (if (= size 24) 6 10)
:flex-direction :row
:flex-shrink 1
:align-items :center})
(defn tag-spacing
[size]
{:margin-left (if (= size 24) 4 8)})
[size shrinkable?]
(cond-> {:margin-left (if (= size 24) 4 8)}
shrinkable? (assoc :flex-shrink 1)))
(defn text
[theme]
+12 -9
View File
@@ -17,17 +17,19 @@
[schema.core :as schema]))
(defn- tag-skeleton
[{:keys [size text theme]
[{:keys [size text theme shrinkable?]
:or {size 24
theme (quo.theme/use-theme)}}
logo-component]
[rn/view {:style (style/tag-container size)}
logo-component
[rn/view {:style (style/tag-spacing size)}
[rn/view {:style (style/tag-spacing size shrinkable?)}
[text/text
{:style (style/text theme)
:weight :medium
:size (if (= size 24) :paragraph-2 :paragraph-1)}
{:style (style/text theme)
:weight :medium
:size (if (= size 24) :paragraph-2 :paragraph-1)
:number-of-lines 1
:ellipsize-mode :middle}
text]]])
(defn- communities-tag
@@ -37,7 +39,7 @@
icon-size (if (= size 24) 16 20)]
[rn/view {:style (style/tag-container size)}
[fast-image/fast-image {:style (style/circle-logo size) :source community-logo}]
[rn/view {:style (style/tag-spacing size)}
[rn/view {:style (style/tag-spacing size false)}
[text/text
{:style (style/text theme)
:weight :medium
@@ -148,9 +150,10 @@
:collectible
[tag-skeleton
{:theme theme
:size size
:text (str collectible-name " #" collectible-number)}
{:theme theme
:size size
:text (str collectible-name " #" collectible-number)
:shrinkable? true}
[rn/image {:style (style/rounded-logo size) :source collectible}]]
:account
@@ -0,0 +1,31 @@
(ns quo.components.wallet.swap-input.component-spec
(:require [quo.components.wallet.swap-input.view :as swap-input]
[test-helpers.component :as h]))
(h/describe "Wallet: Swap Input"
(h/test "should render correctly with props"
(h/render-with-theme-provider
[swap-input/view
{:type :pay
:error? false
:token "SNT"
:status :default
:currency-symbol "€"
:value "5"
:fiat-value "1.50"
:network-tag-props {:title "Max: 200 SNT"}}])
(h/is-truthy (h/get-by-label-text :swap-input))
(h/is-truthy (h/get-by-text "SNT"))
(h/is-truthy (h/get-by-text "€1.50"))
(h/is-truthy (h/get-by-text "Max: 200 SNT")))
(h/test "should render correctly with approval label"
(h/render-with-theme-provider
[swap-input/view
{:type :pay
:show-approval-label? true
:approval-label-props
{:status :approve
:token-value "10"
:token-symbol "SNT"}}])
(h/is-truthy (h/get-by-text "Approve 10 SNT"))))
@@ -0,0 +1,74 @@
(ns quo.components.wallet.swap-input.style
(:require [quo.foundations.colors :as colors]
[quo.foundations.typography :as typography]))
(defn- border-color
[theme]
(colors/theme-colors colors/neutral-10 colors/neutral-80 theme))
(defn- loader-color
[theme]
(colors/theme-colors colors/neutral-5 colors/neutral-90 theme))
(defn content
[theme]
{:border-width 1
:border-radius 16
:border-color (border-color theme)
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)})
(defn row-1
[loading?]
{:padding 12
:gap 8
:align-items (if loading? :center :flex-end)
:flex-direction :row})
(defn row-1-loader
[theme]
{:width 74
:height 14
:border-radius 6
:background-color (loader-color theme)})
(def input-container
{:flex 1
:flex-direction :row
:gap 5
:height 32
:align-items :flex-end})
(defn input
[disabled? error? theme]
(assoc typography/font-semi-bold
:font-size 27
:flex-shrink 1
:padding 0
:color (cond
error? (colors/resolve-color :danger theme)
disabled? (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:else (colors/theme-colors colors/neutral-100 colors/white theme))
:line-height 32))
(defn token-symbol
[theme]
{:padding-bottom 3
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)})
(defn row-2
[align-right?]
{:flex-direction :row
:justify-content (if align-right? :flex-end :space-between)
:align-items :center
:padding 12})
(defn row-2-loader
[theme]
{:width 80
:height 10
:margin-vertical 7
:border-radius 6
:background-color (loader-color theme)})
(def fiat-amount
{:color colors/neutral-50})
@@ -0,0 +1,121 @@
(ns quo.components.wallet.swap-input.view
(:require [oops.core :as oops]
[quo.components.avatars.token-avatar.view :as token-avatar]
[quo.components.buttons.button.view :as buttons]
[quo.components.dividers.divider-line.view :as divider-line]
[quo.components.markdown.text :as text]
[quo.components.tags.network-tags.view :as network-tag]
[quo.components.wallet.approval-label.schema :as approval-label.schema]
[quo.components.wallet.approval-label.view :as approval-label]
[quo.components.wallet.swap-input.style :as style]
[quo.foundations.colors :as colors]
quo.theme
[react-native.core :as rn]
[schema.core :as schema]))
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:type {:optional true} [:maybe [:enum :pay :receive]]]
[:status {:optional true} [:maybe [:enum :default :disabled :loading]]]
[:token {:optional true} [:maybe :string]]
[:value {:optional true} [:maybe :string]]
[:default-value {:optional true} [:maybe :string]]
[:currency-symbol {:optional true} [:maybe :string]]
[:fiat-value {:optional true} [:maybe :string]]
[:show-approval-label? {:optional true} [:maybe :boolean]]
[:error? {:optional true} [:maybe :boolean]]
[:show-keyboard? {:optional true} [:maybe :boolean]]
[:approval-label-props {:optional true} [:maybe approval-label.schema/?schema]]
[:network-tag-props {:optional true} [:maybe :map]]
[:on-change-text {:optional true} [:maybe fn?]]
[:enable-swap? {:optional true} [:maybe :boolean]]
[:on-swap-press {:optional true} [:maybe fn?]]
[:on-token-press {:optional true} [:maybe fn?]]
[:on-max-press {:optional true} [:maybe fn?]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:container-style {:optional true} [:maybe :map]]]]]
:any])
(defn view-internal
[{:keys [type status token value fiat-value show-approval-label? error? network-tag-props
approval-label-props default-value enable-swap?
currency-symbol on-change-text show-keyboard?
container-style on-swap-press on-token-press on-max-press]}]
(let [theme (quo.theme/use-theme)
pay? (= type :pay)
disabled? (= status :disabled)
loading? (= status :loading)
controlled-input? (some? value)
input-ref (rn/use-ref-atom nil)
set-input-ref (rn/use-callback (fn [ref] (reset! input-ref ref)) [])
focus-input (rn/use-callback (fn []
(some-> @input-ref
(oops/ocall "focus")))
[input-ref])]
[rn/view
{:style container-style
:accessibility-label :swap-input}
[rn/view {:style (style/content theme)}
[rn/view
{:style (style/row-1 loading?)}
[rn/pressable {:on-press on-token-press}
[token-avatar/view
{:type :asset
:token token}]]
(if loading?
[rn/view {:style (style/row-1-loader theme)}]
[:<>
[rn/pressable
{:style style/input-container
:on-press focus-input}
[rn/text-input
(cond-> {:ref set-input-ref
:style (style/input disabled? error? theme)
:placeholder-text-color (colors/theme-colors colors/neutral-40
colors/neutral-50
theme)
:keyboard-type :numeric
:auto-focus true
:on-change-text on-change-text
:show-soft-input-on-focus show-keyboard?
:default-value default-value
:placeholder "0"}
controlled-input? (assoc :value value))]
[text/text
{:size :paragraph-2
:weight :semi-bold
:style (style/token-symbol theme)}
token]]
(when (and pay? enable-swap?)
[buttons/button
{:type :outline
:size 32
:on-press on-swap-press
:icon-only? true}
:i/reorder])])]
[divider-line/view]
[rn/view
{:style (style/row-2 (or (not pay?) loading?))}
(when-not loading?
[:<>
(when pay?
[rn/pressable {:on-press on-max-press}
[network-tag/view
(assoc network-tag-props
:status
(if error? :error :default))]])
[text/text
{:size :paragraph-2
:style style/fiat-amount
:weight :medium}
(str currency-symbol fiat-value)]])
(when loading?
[rn/view {:style (style/row-2-loader theme)}])]]
(when (and (not= status :loading) (= type :pay) show-approval-label?)
[approval-label/view
approval-label-props])]))
(def view (schema/instrument #'view-internal ?schema))
@@ -51,8 +51,7 @@
(defn prop-text
[theme]
{:margin-right 4
:color (colors/theme-colors colors/neutral-100 colors/white theme)})
{:color (colors/theme-colors colors/neutral-100 colors/white theme)})
(def icon-container
{:width 32
@@ -61,12 +60,15 @@
(def container
{:flex-direction :row
:flex 1
:column-gap 8})
(def content-line
{:flex-direction :row
:margin-top 2
:align-items :center})
{:flex-direction :row
:margin-top 2
:align-items :center
:column-gap 4
:justify-content :flex-start})
(def icon-hole-view
{:width 32
@@ -98,8 +98,11 @@
(defn prop-tag
[props blur?]
[rn/view {:style {:margin-right 4}}
[context-tag/view (merge props {:size 24 :blur? blur?})]])
[context-tag/view
(assoc props
:size 24
:blur? blur?
:container-style {:flex-shrink 1})])
(defn- view-internal
[{:keys [state blur? first-tag second-tag third-tag fourth-tag on-press
@@ -121,7 +124,7 @@
:on-press-out on-press-out}
[rn/view {:style style/container}
[transaction-icon-view props theme]
[rn/view
[rn/view {:style {:flex 1}}
[transaction-header props theme]
[rn/view {:style style/content-line}
(when first-tag [prop-tag first-tag blur?])
+2
View File
@@ -186,6 +186,7 @@
quo.components.wallet.progress-bar.view
quo.components.wallet.required-tokens.view
quo.components.wallet.summary-info.view
quo.components.wallet.swap-input.view
quo.components.wallet.token-input.view
quo.components.wallet.transaction-progress.view
quo.components.wallet.transaction-summary.view
@@ -472,6 +473,7 @@
(def progress-bar quo.components.wallet.progress-bar.view/view)
(def required-tokens quo.components.wallet.required-tokens.view/view)
(def summary-info quo.components.wallet.summary-info.view/view)
(def swap-input quo.components.wallet.swap-input.view/view)
(def network-link quo.components.wallet.network-link.view/view)
(def token-input quo.components.wallet.token-input.view/view)
(def wallet-overview quo.components.wallet.wallet-overview.view/view)
+1
View File
@@ -112,6 +112,7 @@
quo.components.wallet.progress-bar.component-spec
quo.components.wallet.required-tokens.component-spec
quo.components.wallet.summary-info.component-spec
quo.components.wallet.swap-input.component-spec
quo.components.wallet.token-input.component-spec
quo.components.wallet.transaction-progress.component-spec
quo.components.wallet.transaction-summary.component-spec
@@ -48,7 +48,7 @@
set-animating-true #(reset! animating? true)
set-animating-false (fn [ms]
(js/setTimeout #(reset! animating? false) ms))]
(fn [{:keys [content skip-background?]}]
(fn [{:keys [content skip-background? on-dismiss]}]
(let [theme (quo.theme/use-theme)
{:keys [top] :as insets} (safe-area/get-insets)
alert-banners-top-margin (rf/sub [:alert-banners/top-margin])
@@ -63,6 +63,10 @@
(reanimated/animate opacity 0 300)
(rf/dispatch [:navigate-back])
true)
dismiss (fn []
(when on-dismiss
(on-dismiss))
(close))
reset-open-sheet (fn []
(reanimated/animate translate-y 0 300)
(reanimated/animate opacity 1 300)
@@ -83,7 +87,7 @@
:opacity opacity
:scroll-enabled? scroll-enabled?
:curr-scroll curr-scroll
:close close
:close dismiss
:reset-open-sheet reset-open-sheet
:set-animating-true set-animating-true})}
[reanimated/view {:style (style/main-view translate-y theme)}
@@ -1,5 +1,6 @@
(ns status-im.common.floating-button-page.floating-container.style
(:require [react-native.safe-area :as safe-area]))
(:require [quo.foundations.colors :as colors]
[react-native.safe-area :as safe-area]))
(defn content-container
[blur? keyboard-shown?]
@@ -11,7 +12,12 @@
:padding-horizontal 20}
blur? (dissoc :padding-vertical :padding-horizontal))))
(def blur-inner-container
{:background-color :transparent ; required, otherwise blur-view will shrink
(defn blur-inner-container
[theme shell-overlay?]
{:background-color (colors/theme-colors colors/white-70-blur
(if shell-overlay?
colors/neutral-80-opa-80-blur
colors/neutral-95-opa-70-blur)
theme)
:padding-vertical 12
:padding-horizontal 20})
@@ -1,27 +1,25 @@
(ns status-im.common.floating-button-page.floating-container.view
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[status-im.common.floating-button-page.floating-container.style :as style]))
(defn- blur-container
[child]
[child shell-overlay?]
(let [theme (quo.theme/use-theme)]
[quo/blur
{:blur-amount 52
:blur-radius 20
:blur-type :transparent
:blur-overlay-color (colors/theme-colors colors/white-70-blur colors/neutral-95-opa-70-blur theme)}
[rn/view {:style style/blur-inner-container}
{:blur-amount 20
:blur-type :transparent
:overlay-color :transparent}
[rn/view {:style (style/blur-inner-container theme shell-overlay?)}
child]]))
(defn view
[{:keys [on-layout keyboard-shown? blur?]} child]
[{:keys [on-layout keyboard-shown? blur? shell-overlay?]} child]
[rn/view
{:style (style/content-container blur? keyboard-shown?)
:on-layout on-layout}
(if blur?
[blur-container child]
[blur-container child shell-overlay?]
child)])
@@ -58,7 +58,7 @@
(defn view
[{:keys [header footer customization-color footer-container-padding header-container-style
content-container-style gradient-cover? keyboard-should-persist-taps]
content-container-style gradient-cover? keyboard-should-persist-taps shell-overlay?]
:or {footer-container-padding (safe-area/get-top)}}
& children]
(reagent/with-let [scroll-view-ref (atom nil)
@@ -121,7 +121,8 @@
[floating-container/view
{:on-layout set-footer-container-height
:keyboard-shown? keyboard-shown?
:blur? show-background?}
:blur? show-background?
:shell-overlay? shell-overlay?}
footer]]]])
(finally
(remove-listeners))))
@@ -0,0 +1,14 @@
(ns status-im.common.metrics-confirmation-modal.style)
(def points-wrapper
{:margin-top 11
:margin-horizontal 20
:gap 21
:margin-bottom 15})
(def item-text
{:margin-top 10
:margin-left -4})
(def info-text
{:margin-top -5})
@@ -0,0 +1,79 @@
(ns status-im.common.metrics-confirmation-modal.view
(:require
[quo.core :as quo]
[react-native.core :as rn]
[status-im.common.metrics-confirmation-modal.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- dismiss-keyboard
[]
(rf/dispatch [:dismiss-keyboard]))
(defn- hide-bottom-sheet
[]
(rf/dispatch [:hide-bottom-sheet]))
(defn- toggle-metrics
[enabled?]
(rf/dispatch [:centralized-metrics/toggle-centralized-metrics enabled?]))
(def ^:private will-receive-points
[:t/ip-address
:t/universally-unique-identifiers-of-device
:t/logs-of-actions-withing-the-app])
(def ^:private not-receive-points
[:t/your-profile-information
:t/your-addresses
:t/information-you-input-and-send])
(defn- bullet-points
[{:keys [title points]}]
[rn/view
[quo/text {:weight :semi-bold}
title]
(for [label points]
^{:key label}
[quo/markdown-list
{:description (i18n/label label)
:blur? true
:container-style style/item-text}])])
(defn- on-share-usage
[]
(toggle-metrics true)
(hide-bottom-sheet))
(defn- on-do-not-share
[]
(toggle-metrics false)
(hide-bottom-sheet))
(defn view
[{:keys [settings?]}]
(rn/use-mount #(dismiss-keyboard))
[:<>
[quo/drawer-top
{:title (i18n/label :t/help-us-improve-status)
:description (i18n/label :t/collecting-usage-data)}]
[rn/view {:style style/points-wrapper}
[bullet-points
{:title (i18n/label :t/what-we-will-receive)
:points will-receive-points}]
[bullet-points
{:title (i18n/label :t/what-we-wont-receive)
:points not-receive-points}]
(when-not settings?
[quo/text
{:size :paragraph-2
:style style/info-text}
(i18n/label :t/sharing-usage-data-can-be-turned-off)])]
[quo/bottom-actions
{:actions :two-actions
:blur? true
:button-one-label (i18n/label :t/share-usage-data)
:button-one-props {:on-press on-share-usage}
:button-two-label (i18n/label (if settings? :t/do-not-share :t/not-now))
:button-two-props {:type :grey
:on-press on-do-not-share}}]])
+11 -1
View File
@@ -45,6 +45,11 @@
(def ^:const activity-center-membership-status-accepted 2)
(def ^:const activity-center-membership-status-declined 3)
;; Choose the maximum number of notifications that *usually/safely* fit on
;; most screens, so that the UI doesn't have to needlessly render
;; notifications.
(def ^:const notifications-per-page 7)
(def ^:const mute-for-15-mins-type 1)
(def ^:const mute-for-1-hour-type 2)
(def ^:const mute-for-8-hours-type 3)
@@ -276,12 +281,14 @@
#{wallet-connect-personal-sign-method
wallet-connect-eth-sign-method
wallet-connect-eth-send-transaction-method
wallet-connect-eth-sign-transaction-method
;; NOTE: disabled, as we have no clear use cases for it and other wallets don't support it
;; wallet-connect-eth-sign-transaction-method
wallet-connect-eth-sign-typed-method
wallet-connect-eth-sign-typed-v4-method})
(def ^:const wallet-connect-supported-events #{"accountsChanged" "chainChanged"})
(def ^:const wallet-connect-session-proposal-event "session_proposal")
(def ^:const wallet-connect-session-request-event "session_request")
(def ^:const wallet-connect-session-delete-event "session_delete")
(def ^:const wallet-connect-user-rejected-error-key "USER_REJECTED")
(def ^:const transaction-pending-type-wallet-connect-transfer "WalletConnectTransfer")
@@ -506,6 +513,9 @@
(def ^:const optimism-full-name "Optimism")
(def ^:const arbitrum-full-name "Arbitrum")
(def ^:const sepolia-full-name "Sepolia")
(def ^:const goerli-full-name "Goerli")
(def ^:const mainnet-network-name :mainnet)
(def ^:const ethereum-network-name :ethereum)
(def ^:const optimism-network-name :optimism)
@@ -7,10 +7,17 @@
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(def ^:const user-confirmed-key :centralized-metrics/user-confirmed?)
(def ^:const enabled-key :centralized-metrics/enabled?)
(defn show-confirmation-modal?
[db]
(not (user-confirmed-key db)))
(defn push-event?
[db]
(or (not (:centralized-metrics/user-confirmed? db))
(:centralized-metrics/enabled? db)))
(or (not (user-confirmed-key db))
(enabled-key db)))
(defn centralized-metrics-interceptor
[context]
@@ -29,5 +36,16 @@
(fn [{:keys [db]} [enabled?]]
{:fx [[:effects.centralized-metrics/toggle-metrics enabled?]]
:db (assoc db
:centralized-metrics/user-confirmed? true
:centralized-metrics/enabled? enabled?)}))
user-confirmed-key
true
enabled-key
enabled?)}))
(rf/reg-event-fx :centralized-metrics/check-modal
(fn [{:keys [db]} [modal-view]]
(when (show-confirmation-modal? db)
{:fx [[:dispatch
[:show-bottom-sheet
{:content (fn [] [modal-view])
:shell? true}]]]})))
@@ -6,6 +6,11 @@
[status-im.contexts.centralized-metrics.tracking :as tracking]
[test-helpers.unit :as h]))
(deftest show-confirmation-modal-test
(testing "returns true if the user confirmed"
(is (false? (events/show-confirmation-modal? {events/user-confirmed-key true})))
(is (true? (events/show-confirmation-modal? {})))))
(deftest push-event-test
(testing "returns correct boolean value"
(is (true? (events/push-event? {:centralized-metrics/user-confirmed? false})))
@@ -27,7 +27,7 @@
:on-error #(p-reject (str "failed to sign data\n" %))}))))
(defn- edit-shared-addresses-for-community
[community-id signatures addresses-to-reveal airdrop-address]
[community-id signatures addresses-to-reveal airdrop-address _share-future-addresses?]
(promesa/create
(fn [p-resolve p-reject]
(rpc/call
@@ -41,15 +41,16 @@
:on-error p-reject}))))
(defn- request-to-join
[community-id signatures addresses-to-reveal airdrop-address]
[community-id signatures addresses-to-reveal airdrop-address share-future-addresses?]
(promesa/create
(fn [p-resolve p-reject]
(rpc/call
{:method :wakuext_requestToJoinCommunity
:params [{:communityId community-id
:signatures signatures
:addressesToReveal addresses-to-reveal
:airdropAddress airdrop-address}]
:params [{:communityId community-id
:signatures signatures
:addressesToReveal addresses-to-reveal
:airdropAddress airdrop-address
:shareFutureAddresses share-future-addresses?}]
:js-response true
:on-success p-resolve
:on-error p-reject}))))
@@ -64,15 +65,18 @@
(defn- sign-and-call-endpoint
[{:keys [community-id password pub-key
addresses-to-reveal airdrop-address
addresses-to-reveal airdrop-address share-future-addresses?
on-success on-error
callback]}]
(-> (promesa/let [sign-params (generate-requests-for-signing pub-key community-id addresses-to-reveal)
(-> (promesa/let [sign-params (generate-requests-for-signing pub-key
community-id
addresses-to-reveal)
signatures (sign-data sign-params password)
result (callback community-id
signatures
addresses-to-reveal
airdrop-address)]
airdrop-address
share-future-addresses?)]
(run-callback-or-event on-success result))
(promesa/catch #(run-callback-or-event on-error %))))
@@ -87,6 +91,7 @@
[:or [:set string?]
[:sequential string?]]]
[:airdrop-address string?]
[:share-future-addresses? boolean?]
[:on-success [:or fn? :schema.re-frame/event]]
[:on-error [:or fn? :schema.re-frame/event]]
[:callback fn?]]]
@@ -17,13 +17,12 @@
(rf/reg-event-fx :communities/initialize-permission-addresses initialize-permission-addresses)
(defn do-init-permission-addresses
[{:keys [db]} [community-id revealed-accounts]]
[{:keys [db]} [community-id revealed-accounts share-future-addresses?]]
(let [wallet-accounts (utils/sorted-operable-non-watch-only-accounts db)
addresses-to-reveal (if (seq revealed-accounts)
(set (keys revealed-accounts))
;; Reveal all addresses as fallback.
(set (map :address wallet-accounts)))
;; When there are no revealed addresses, such as when joining a
;; community, use first address for airdrops.
airdrop-address (or (->> revealed-accounts
@@ -35,10 +34,7 @@
first
:address))]
{:db (-> db
;; Set to false by default while we don't persist the user's choice
;; in status-go, otherwise whenever the view is mounted, the choice
;; of selected addresses won't be respected.
(assoc-in [:communities/selected-share-all-addresses community-id] false)
(assoc-in [:communities/selected-share-all-addresses community-id] share-future-addresses?)
(assoc-in [:communities/all-addresses-to-reveal community-id] addresses-to-reveal)
(assoc-in [:communities/all-airdrop-addresses community-id] airdrop-address))
:fx [[:dispatch
@@ -60,36 +56,44 @@
is selecting an airdrop address, we must submit to status-go the current
choice of addresses to share, and vice-versa. If we omit addresses to share,
status-go will default to all available."
[{:keys [db]} [{:keys [community-id password on-success addresses airdrop-address]}]]
(let [pub-key (get-in db [:profile/profile :public-key])
wallet-accounts (utils/sorted-operable-non-watch-only-accounts db)
addresses-to-reveal (if (seq addresses)
(set addresses)
(get-in db [:communities/all-addresses-to-reveal community-id]))
new-airdrop-address (if (contains? addresses-to-reveal airdrop-address)
airdrop-address
(->> wallet-accounts
(filter #(contains? addresses-to-reveal (:address %)))
first
:address))]
[{:keys [db]}
[{:keys [community-id password on-success addresses airdrop-address share-future-addresses?]}]]
(let [pub-key (get-in db [:profile/profile :public-key])
wallet-accounts (utils/sorted-operable-non-watch-only-accounts db)
addresses-to-reveal (if (seq addresses)
(set addresses)
(get-in db [:communities/all-addresses-to-reveal community-id]))
new-airdrop-address (if (contains? addresses-to-reveal airdrop-address)
airdrop-address
(->> wallet-accounts
(filter #(contains? addresses-to-reveal (:address %)))
first
:address))
share-future-addresses? (if (nil? share-future-addresses?)
(get-in db [:communities/selected-share-all-addresses community-id])
share-future-addresses?)]
{:fx [[:effects.community/edit-shared-addresses
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal addresses-to-reveal
:airdrop-address new-airdrop-address
:on-success (fn []
(when (fn? on-success)
(on-success addresses-to-reveal new-airdrop-address))
(rf/dispatch [:communities/edit-shared-addresses-success
community-id addresses-to-reveal airdrop-address]))
:on-error [:communities/edit-shared-addresses-failure community-id]}]]}))
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal addresses-to-reveal
:share-future-addresses? share-future-addresses?
:airdrop-address new-airdrop-address
:on-success (fn []
(when (fn? on-success)
(on-success addresses-to-reveal
new-airdrop-address
share-future-addresses?))
(rf/dispatch [:communities/edit-shared-addresses-success
community-id addresses-to-reveal airdrop-address]))
:on-error [:communities/edit-shared-addresses-failure community-id]}]]}))
(rf/reg-event-fx :communities/edit-shared-addresses edit-shared-addresses)
(rf/reg-event-fx :communities/edit-shared-addresses-success
(fn [_ [community-id addresses-to-reveal airdrop-address]]
(fn [_ [community-id addresses-to-reveal airdrop-address share-future-addresses?]]
{:fx [[:dispatch [:communities/set-airdrop-address community-id airdrop-address]]
[:dispatch [:communities/set-share-all-addresses community-id share-future-addresses?]]
[:dispatch [:communities/set-addresses-to-reveal community-id addresses-to-reveal]]]}))
(rf/reg-event-fx :communities/edit-shared-addresses-failure
@@ -70,7 +70,7 @@
(is
(match?
{:db (-> (:db cofx)
(assoc-in [:communities/selected-share-all-addresses community-id] false)
(assoc-in [:communities/selected-share-all-addresses community-id] true)
(assoc-in [:communities/all-addresses-to-reveal community-id] addresses-to-reveal)
(assoc-in [:communities/all-airdrop-addresses community-id] airdrop-address))
:fx [[:dispatch
@@ -82,7 +82,7 @@
[:dispatch
[:communities/check-permissions-to-join-during-selection community-id
addresses-to-reveal]]]}
(sut/do-init-permission-addresses cofx [community-id revealed-accounts])))))
(sut/do-init-permission-addresses cofx [community-id revealed-accounts true])))))
;; Expect to mark all addresses to be revealed and first one to receive
;; airdrops when no addresses were previously revealed.
@@ -93,7 +93,7 @@
(is
(match?
{:db (-> (:db cofx)
(assoc-in [:communities/selected-share-all-addresses community-id] false)
(assoc-in [:communities/selected-share-all-addresses community-id] true)
(assoc-in [:communities/all-addresses-to-reveal community-id] addresses-to-reveal))
:fx [[:dispatch
[:communities/check-permissions-to-join-community
@@ -101,7 +101,7 @@
[:dispatch
[:communities/check-permissions-to-join-during-selection community-id
addresses-to-reveal]]]}
(sut/do-init-permission-addresses cofx [community-id revealed-accounts]))))))
(sut/do-init-permission-addresses cofx [community-id revealed-accounts true]))))))
(deftest edit-shared-addresses-test
(testing
@@ -109,6 +109,7 @@
fallback to all wallet addresses"
(let [pub-key "abcdef"
revealed-addresses #{"0xB" "0xC"}
share-future-addresses? true
cofx {:db {:profile/profile {:public-key pub-key}
:communities/all-addresses-to-reveal {community-id revealed-addresses}}}
airdrop-address "0xB"
@@ -116,22 +117,24 @@
actual
(sut/edit-shared-addresses
cofx
[{:community-id community-id
:password password
:airdrop-address airdrop-address
:on-success (fn [new-addresses-to-reveal]
(is (match? revealed-addresses new-addresses-to-reveal)))}])
[{:community-id community-id
:password password
:airdrop-address airdrop-address
:share-future-addresses? share-future-addresses?
:on-success (fn [new-addresses-to-reveal]
(is (match? revealed-addresses new-addresses-to-reveal)))}])
on-success-wrapper (-> actual :fx first second :on-success)]
(is (match?
{:fx [[:effects.community/edit-shared-addresses
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal revealed-addresses
:airdrop-address airdrop-address
:on-success fn?
:on-error [:communities/edit-shared-addresses-failure community-id]}]]}
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal revealed-addresses
:share-future-addresses? share-future-addresses?
:airdrop-address airdrop-address
:on-success fn?
:on-error [:communities/edit-shared-addresses-failure community-id]}]]}
actual))
(on-success-wrapper)))
@@ -203,7 +203,9 @@
:addresses-for-permissions])
(rf/dispatch [:hide-bottom-sheet]))}]))}])
(rf/dispatch [:communities/set-share-all-addresses id flag-share-all-addresses]))
(rf/dispatch [:communities/set-addresses-to-reveal id addresses-to-reveal])))
(do
(rf/dispatch [:communities/set-share-all-addresses id flag-share-all-addresses])
(rf/dispatch [:communities/set-addresses-to-reveal id addresses-to-reveal]))))
highest-role (rf/sub [:communities/highest-role-for-selection id])
[unmodified-role _] (rn/use-state highest-role)]
@@ -261,6 +263,7 @@
can-edit-addresses? (rf/sub [:communities/can-edit-shared-addresses? id])
wallet-accounts (rf/sub [:wallet/operable-accounts-without-watched-accounts])
joined (rf/sub [:communities/community-joined id])
unmodified-addresses-to-reveal (rf/sub [:communities/addresses-to-reveal id])
[addresses-to-reveal set-addresses-to-reveal] (rn/use-state unmodified-addresses-to-reveal)
@@ -285,7 +288,6 @@
(set-flag-share-all-addresses new-value)
(when new-value
(set-addresses-to-reveal (set (map :address wallet-accounts))))))]
(rn/use-mount
(fn []
(when-not flag-share-all-addresses
@@ -310,6 +312,7 @@
flag-share-all-addresses]
:header [quo/page-setting
{:checked? flag-share-all-addresses
:disabled? joined
:customization-color color
:on-change toggle-flag-share-all-addresses
:setting-text (i18n/label
+14 -18
View File
@@ -16,6 +16,7 @@
[status-im.navigation.events :as navigation]
[status-im.navigation.transitions :as transitions]
[taoensso.timbre :as log]
[utils.collection :as collection-utils]
[utils.re-frame :as rf]))
(defn handle-community
@@ -372,15 +373,14 @@
(when (and community joined (not fetching-revealed-accounts))
{:db (assoc-in db [:communities community-id :fetching-revealed-accounts] true)
:json-rpc/call
[{:method "wakuext_getRevealedAccounts"
:params [community-id (get-in db [:profile/profile :public-key])]
:js-response true
:on-success [:communities/get-revealed-accounts-success community-id on-success]
:on-error (fn [err]
(log/error {:message "failed to fetch revealed accounts"
:community-id community-id
:err err})
(rf/dispatch [:communities/get-revealed-accounts-failed community-id]))}]})))
[{:method "wakuext_latestRequestToJoinForCommunity"
:params [community-id]
:on-success [:communities/get-revealed-accounts-success community-id on-success]
:on-error (fn [err]
(log/error {:message "failed to fetch revealed accounts"
:community-id community-id
:err err})
(rf/dispatch [:communities/get-revealed-accounts-failed community-id]))}]})))
(rf/reg-event-fx :communities/get-revealed-accounts get-revealed-accounts)
@@ -399,22 +399,18 @@
[:json-rpc/call :schema.common/rpc-call]]]])
(rf/reg-event-fx :communities/get-revealed-accounts-success
(fn [{:keys [db]} [community-id on-success revealed-accounts-js]]
(fn [{:keys [db]} [community-id on-success request-to-join]]
(when-let [community (get-in db [:communities community-id])]
(let [revealed-accounts
(reduce
(fn [acc {:keys [address] :as revealed-account}]
(assoc acc address revealed-account))
{}
(data-store.communities/<-revealed-accounts-rpc revealed-accounts-js))
(let [revealed-accounts (collection-utils/index-by :address (:revealedAccounts request-to-join))
share-future-addresses? (:shareFutureAddresses request-to-join)
community-with-revealed-accounts
(-> community
(assoc :revealed-accounts revealed-accounts)
(assoc :share-future-addresses? share-future-addresses?)
(dissoc :fetching-revealed-accounts))]
{:db (assoc-in db [:communities community-id] community-with-revealed-accounts)
:fx [(when (vector? on-success)
[:dispatch (conj on-success revealed-accounts)])]}))))
[:dispatch (conj on-success revealed-accounts share-future-addresses?)])]}))))
(rf/reg-event-fx :communities/get-revealed-accounts-failed
(fn [{:keys [db]} [community-id]]
@@ -146,8 +146,8 @@
effects (events/get-revealed-accounts {:db db} [community-id])]
(is (match? (assoc-in db [:communities community-id :fetching-revealed-accounts] true)
(:db effects)))
(is (match? {:method "wakuext_getRevealedAccounts"
:params [community-id "profile-public-key"]}
(is (match? {:method "wakuext_latestRequestToJoinForCommunity"
:params [community-id]}
(-> effects :json-rpc/call first (select-keys [:method :params]))))))))
(deftest handle-community-test
@@ -117,13 +117,14 @@
{:community community-name})}]]]})))
(defn request-to-join-with-signatures
[_ [community-id addresses-to-reveal signatures]]
[_ [community-id addresses-to-reveal signatures share-future-addresses?]]
{:fx [[:json-rpc/call
[{:method "wakuext_requestToJoinCommunity"
:params [{:communityId community-id
:signatures signatures
:addressesToReveal addresses-to-reveal
:airdropAddress (first addresses-to-reveal)}]
:params [{:communityId community-id
:signatures signatures
:addressesToReveal addresses-to-reveal
:shareFutureAddresses share-future-addresses?
:airdropAddress (first addresses-to-reveal)}]
:js-response true
:on-success [:communities/requested-to-join]
:on-error [:communities/requested-to-join-error community-id]}]]]})
@@ -153,16 +154,18 @@
(defn request-to-join-with-addresses
[{:keys [db]}
[{:keys [community-id password]}]]
(let [pub-key (get-in db [:profile/profile :public-key])
addresses-to-reveal (get-in db [:communities/all-addresses-to-reveal community-id])
airdrop-address (get-in db [:communities/all-airdrop-addresses community-id])]
(let [pub-key (get-in db [:profile/profile :public-key])
addresses-to-reveal (get-in db [:communities/all-addresses-to-reveal community-id])
share-future-addresses? (get-in db [:communities/selected-share-all-addresses community-id])
airdrop-address (get-in db [:communities/all-airdrop-addresses community-id])]
{:fx [[:effects.community/request-to-join
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal addresses-to-reveal
:airdrop-address airdrop-address
:on-success [:communities/requested-to-join]
:on-error [:communities/requested-to-join-error community-id]}]]}))
{:community-id community-id
:password password
:pub-key pub-key
:addresses-to-reveal addresses-to-reveal
:airdrop-address airdrop-address
:share-future-addresses? share-future-addresses?
:on-success [:communities/requested-to-join]
:on-error [:communities/requested-to-join-error community-id]}]]}))
(rf/reg-event-fx :communities/request-to-join-with-addresses request-to-join-with-addresses)
@@ -37,19 +37,22 @@
(sut/sign-data cofx [community-id password sign-params])))))
(deftest request-to-join-with-signatures-test
(let [cofx {:db {}}
addresses-to-reveal [account-pub-key "0x2"]
signatures ["11111" "222222"]
expected {:fx [[:json-rpc/call
[{:method "wakuext_requestToJoinCommunity"
:params [{:communityId community-id
:signatures signatures
:addressesToReveal addresses-to-reveal
:airdropAddress "0x1"}]
:js-response true
:on-success [:communities/requested-to-join]
:on-error [:communities/requested-to-join-error
community-id]}]]]}]
(let [cofx {:db {}}
addresses-to-reveal [account-pub-key "0x2"]
share-future-addresses? true
signatures ["11111" "222222"]
expected {:fx [[:json-rpc/call
[{:method "wakuext_requestToJoinCommunity"
:params [{:communityId community-id
:signatures signatures
:addressesToReveal addresses-to-reveal
:shareFutureAddresses share-future-addresses?
:airdropAddress "0x1"}]
:js-response true
:on-success [:communities/requested-to-join]
:on-error [:communities/requested-to-join-error
community-id]}]]]}]
(is (match? expected
(sut/request-to-join-with-signatures cofx
[community-id addresses-to-reveal signatures])))))
[community-id addresses-to-reveal signatures
share-future-addresses?])))))
@@ -5,13 +5,8 @@
(def background-container
{:background-color colors/neutral-100
:flex-direction :row
:position :absolute
:overflow :hidden
:top 0
:bottom 0
:left 0
:right 0})
:flex 1
:overflow :hidden})
(def background-blur-overlay
{:position :absolute
@@ -25,13 +25,12 @@
:sub-text (i18n/label :t/explore-the-decentralized-web)}])
(defn background-image
[content-width]
[image-view-width]
[rn/image
{:resize-mode :stretch
:resize-method :scale
:style {:top 138
:width content-width}
:source (resources/get-image :onboarding-illustration)}])
{:resize-mode :stretch
:style {:flex 1
:width image-view-width}
:source (resources/get-image :onboarding-illustration)}])
(defonce progress (atom nil))
(defonce paused? (atom nil))
@@ -5,12 +5,9 @@
(defn header-container
[status-bar-height content-width index header-background]
{:position :absolute
:top 0
:left (* content-width index)
{:margin-left (* content-width index)
:padding-top (+ 30 status-bar-height)
:width content-width
:height (+ 96 status-bar-height)
:flex-direction :row
:background-color (when header-background colors/onboarding-header-black)})
@@ -62,9 +59,9 @@
:top (+ 12 status-bar-height)})
(defn carousel-container
[left animate?]
(cond->> {:position :absolute
:top 0
:flex-direction :row
:left left}
animate? (reanimated/apply-animations-to-style {:left left})))
[left animate? width]
(cond->> {:flex-direction :row
:flex 1
:width width
:margin-left left}
animate? (reanimated/apply-animations-to-style {:margin-left left})))
@@ -18,19 +18,18 @@
:size :heading-2}
(get-in header-text [index :text])]
[quo/text
{:style style/carousel-sub-text
:size :paragraph-1}
{:style style/carousel-sub-text}
(get-in header-text [index :sub-text])]])
(defn content-view
[{:keys [window-width status-bar-height index header-text header-background]} content]
(let [content-width (* 4 window-width)]
[:<>
(when content content)
[rn/view {:style {:flex 1}}
[rn/view {:style (style/header-container status-bar-height content-width index header-background)}
(for [index (range 4)]
^{:key index}
[header-text-view index window-width header-text])]]))
[header-text-view index window-width header-text])]
(when content content)]))
(defn progress-bar
[{:keys [static? progress-bar-width]}]
@@ -64,10 +63,10 @@
:swipeable (animation/composed-gestures progress paused? is-dragging? drag-amount)
:tappable (animation/tap-gesture progress paused?)
nil)]
[:<>
[rn/view {:style {:flex 1}}
[gesture/gesture-detector {:gesture identified-gesture}
[container-view {:style (style/carousel-container carousel-left animate?)}
(for [index (range 2)]
[container-view {:style (style/carousel-container carousel-left animate? (* 4 window-width))}
(for [index (range 1)]
^{:key index}
[content-view
{:window-width window-width
@@ -5,6 +5,7 @@
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.common.check-before-syncing.view :as check-before-syncing]
[status-im.common.metrics-confirmation-modal.view :as metrics-modal]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.resources :as resources]
[status-im.config :as config]
@@ -126,6 +127,7 @@
(defn- internal-view
[sign-in-type]
(rn/use-mount #(rf/dispatch [:centralized-metrics/check-modal metrics-modal/view]))
(let [{:keys [top]} (safe-area/get-insets)]
[rn/view {:style style/content-container}
[quo/page-nav
@@ -4,20 +4,20 @@
(def title-container
{:margin-horizontal 20
:padding-vertical 12})
:padding-bottom 20
:padding-top 12})
(defn page-container
[insets]
{:flex 1
:justify-content :space-between
:padding-top (+ (:top insets) 56)})
{:flex 1
:padding-top (+ (:top insets) 56)})
(defn page-illustration
[width]
{:flex 1
:padding-top 12
:padding-bottom 10
:width width})
{:flex 1
:margin-top 12
:margin-bottom 10
:width width})
(defn buttons
[insets]
@@ -2,11 +2,16 @@
(defn page-container
[insets]
{:flex 1
:justify-content :space-between
:padding-top (:top insets)})
{:flex 1
:padding-top (:top insets)})
(defn page-illustration
[width]
{:flex 1
:width width})
(def title-style
{:position :absolute
:left 0
:right 0
:top 0})
@@ -17,19 +17,22 @@
(defn generate-keys-title
[]
[quo/text-combinations
{:container-style {:margin-horizontal 20}
{:container-style {:margin-horizontal 20
:margin-vertical 12}
:title (i18n/label :t/generating-keys)}])
(defn saving-keys-title
[]
[quo/text-combinations
{:container-style {:margin-horizontal 20}
{:container-style {:margin-horizontal 20
:margin-vertical 12}
:title (i18n/label :t/saving-keys-to-device)}])
(defn keys-saved-title
[]
[quo/text-combinations
{:container-style {:margin-horizontal 20}
{:container-style {:margin-horizontal 20
:margin-vertical 12}
:title (i18n/label :t/keys-saved)}])
(defn sequence-animation
@@ -61,46 +64,42 @@
reanimated/easings))))))
(defn title
[insets]
(let [top-insets (+ (if rn/small-screen? 62 112) (:insets insets))
generate-keys-opacity (reanimated/use-shared-value 1)
[]
(let [generate-keys-opacity (reanimated/use-shared-value 1)
saving-keys-opacity (reanimated/use-shared-value 0)
keys-saved-opacity (reanimated/use-shared-value 0)]
(sequence-animation generate-keys-opacity saving-keys-opacity keys-saved-opacity)
[rn/view
{:position :absolute
:top top-insets}
{:style {:margin-top 56
:height 56}}
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity generate-keys-opacity}
{:position :absolute})}
style/title-style)}
[generate-keys-title]]
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity saving-keys-opacity}
{:position :absolute})}
style/title-style)}
[saving-keys-title]]
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity keys-saved-opacity}
{:position :absolute})}
style/title-style)}
[keys-saved-title]]]))
(defn content
[]
(let [width (:width (rn/get-window))]
[rn/view
{:top 156
:position :absolute}
[rn/image
{:resize-mode :contain
:style (style/page-illustration width)
:source (resources/get-image :generate-keys1)}]]))
[rn/image
{:resize-mode :contain
:style (style/page-illustration width)
:source (resources/get-image :generate-keys1)}]))
(defn view
[]
(let [insets (safe-area/get-insets)]
[rn/view {:style (style/page-container insets)}
[:<>
[title insets]
[title]
[content]]]))
@@ -7,9 +7,8 @@
:justify-content :flex-end})
(def text-container
{:flex 1
:text-align :center
:margin-top 16
{:text-align :center
:margin-top 4
:flex-wrap :wrap})
(def plain-text
@@ -19,9 +18,8 @@
{:flex 1
:color colors/white})
(def bottom-actions-container
{:position :absolute
:background-color colors/onboarding-header-black
:left 0
:right 0
:padding-bottom 40})
(defn bottom-actions-container
[bottom-insets]
{:background-color colors/onboarding-header-black
:flex-shrink 1
:padding-bottom (+ 20 bottom-insets)})
@@ -2,6 +2,7 @@
(:require
[quo.core :as quo]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.contexts.onboarding.common.background.view :as background]
[status-im.contexts.onboarding.common.overlay.view :as overlay]
[status-im.contexts.onboarding.intro.style :as style]
@@ -14,7 +15,7 @@
[rn/view {:style style/page-container}
[background/view false]
[quo/bottom-actions
{:container-style style/bottom-actions-container
{:container-style (style/bottom-actions-container (safe-area/get-bottom))
:actions :two-vertical-actions
:description :bottom
:description-text [quo/text
@@ -212,6 +212,7 @@
[status-im.contexts.preview.quo.wallet.progress-bar :as progress-bar]
[status-im.contexts.preview.quo.wallet.required-tokens :as required-tokens]
[status-im.contexts.preview.quo.wallet.summary-info :as summary-info]
[status-im.contexts.preview.quo.wallet.swap-input :as swap-input]
[status-im.contexts.preview.quo.wallet.token-input :as token-input]
[status-im.contexts.preview.quo.wallet.transaction-progress :as transaction-progress]
[status-im.contexts.preview.quo.wallet.transaction-summary :as
@@ -570,6 +571,7 @@
{:name :required-tokens
:component required-tokens/view}
{:name :summary-info :component summary-info/view}
{:name :swap-input :component swap-input/view}
{:name :token-input :component token-input/view}
{:name :wallet-activity :component wallet-activity/view}
{:name :transaction-progress :component transaction-progress/view}
@@ -0,0 +1,68 @@
(ns status-im.contexts.preview.quo.wallet.swap-input
(:require
[quo.core :as quo]
[quo.foundations.resources :as resources]
[react-native.core :as rn]
[status-im.contexts.preview.quo.preview :as preview]))
(def descriptor
[{:type :select
:key :type
:options [{:key :pay}
{:key :receive}]}
{:type :select
:key :status
:options [{:key :default}
{:key :disabled}
{:key :loading}]}
{:type :select
:key :value
:options [{:key :token}
{:key :fiat}]}
{:type :boolean
:key :error?}
{:type :boolean
:key :enable-swap?}
{:type :boolean
:key :show-approval-label?}
(preview/customization-color-option)])
(defn view
[]
(let [[state set-state] (rn/use-state {:type :pay
:error? false
:token "SNT"
:customization-color :blue
:show-approval-label? false
:enable-swap? true
:status :default
:currency-symbol "€"})
[value set-value] (rn/use-state "")
on-press (fn [v] (set-value (str value v)))
delete (fn [] (set-value #(subs % 0 (dec (count %)))))]
[preview/preview-container
{:state state
:set-state set-state
:descriptor descriptor}
[quo/swap-input
(assoc state
:on-swap-press #(js/alert "Swap Pressed")
:on-token-press #(js/alert "Token Pressed")
:on-max-press #(js/alert "Max Pressed")
:value value
:fiat-value (str (.toFixed (* value 0.3) 2))
:container-style {:margin-bottom 20}
:network-tag-props {:title "Max: 200 SNT"
:networks [{:source (resources/get-network :ethereum)}]}
:approval-label-props
{:status :approve
:token-value "10"
:button-props {:on-press
#(js/alert "Approve Pressed")}
:customization-color (:customization-color state)
:token-symbol "SNT"})]
[quo/numbered-keyboard
{:left-action :dot
:delete-key? true
:on-press on-press
:on-delete delete}]]))
@@ -7,6 +7,7 @@
[react-native.safe-area :as safe-area]
[status-im.common.check-before-syncing.view :as check-before-syncing]
[status-im.common.confirmation-drawer.view :as confirmation-drawer]
[status-im.common.metrics-confirmation-modal.view :as metrics-modal]
[status-im.common.standard-authentication.core :as standard-authentication]
[status-im.config :as config]
[status-im.constants :as constants]
@@ -254,6 +255,7 @@
(defn view
[]
(rn/use-mount #(rf/dispatch [:centralized-metrics/check-modal metrics-modal/view]))
(let [[show-profiles? set-show-profiles] (rn/use-state false)
show-profiles (rn/use-callback #(set-show-profiles true))
hide-profiles (rn/use-callback #(set-show-profiles false))]
@@ -113,7 +113,8 @@
(defn view
[]
(let [profile-color (rf/sub [:profile/customization-color])
(let [view-id (rf/sub [:view-id])
profile-color (rf/sub [:profile/customization-color])
accounts-addresses (rf/sub [:wallet/addresses])
saved-addresses-addresses (rf/sub [:wallet/saved-addresses-addresses])
[address-or-ens set-address-or-ens] (rn/use-state "")
@@ -175,11 +176,12 @@
:on-press navigate-back
:margin-top (safe-area/get-top)
:accessibility-label :add-address-to-save-page-nav}]
:footer [quo/button
{:customization-color profile-color
:disabled? button-disabled?
:on-press on-press-continue}
(i18n/label :t/continue)]}
:footer (when (= view-id :screen/settings.add-address-to-save)
[quo/button
{:customization-color profile-color
:disabled? button-disabled?
:on-press on-press-continue}
(i18n/label :t/continue)])}
[quo/page-top
{:container-style style/header-container
:blur? true
@@ -121,7 +121,8 @@
:on-press on-press-save}
(i18n/label :t/save-address)]
:customization-color address-color
:gradient-cover? true}
:gradient-cover? true
:shell-overlay? true}
[quo/wallet-user-avatar
{:full-name (if (string/blank? address-label)
placeholder
@@ -0,0 +1,18 @@
(ns status-im.contexts.shell.activity-center.context
(:require
["react" :as react]
[oops.core :as oops]
[react-native.core :as rn]))
(defonce ^:private context
(react/createContext {}))
(defn provider
[state & children]
(into [:> (oops/oget context :Provider) {:value state}]
children))
(defn use-context
[]
(let [ctx (rn/use-context context)]
{:active-swipeable (oops/oget ctx :activeSwipeable)}))
@@ -15,10 +15,7 @@
(def defaults
{:filter-status :unread
:filter-type types/no-type
;; Choose the maximum number of notifications that *usually/safely* fit on
;; most screens, so that the UI doesn't have to needlessly render
;; notifications.
:notifications-per-page 8})
:notifications-per-page constants/notifications-per-page})
;;;; Navigation
@@ -1,6 +1,7 @@
(ns status-im.contexts.shell.activity-center.notification.admin.view
(:require
[quo.core :as quo]
[react-native.core :as rn]
[status-im.constants :as constants]
[status-im.contexts.shell.activity-center.notification.common.style :as common-style]
[status-im.contexts.shell.activity-center.notification.common.view :as common]
@@ -23,42 +24,50 @@
:text (i18n/label :t/decline)}])
(defn- swipeable
[{:keys [active-swipeable notification extra-fn]} child]
(let [{:keys [community-id id membership-status]} notification]
[{:keys [notification extra-fn]} child]
(let [{:keys [community-id id
membership-status]} notification
accept (rn/use-callback
(fn []
(rf/dispatch [:communities/accept-request-to-join-pressed
community-id id]))
[community-id id])
decline (rn/use-callback
(fn []
(rf/dispatch [:communities/decline-request-to-join-pressed
community-id id]))
[community-id id])]
(cond
(#{constants/activity-center-membership-status-accepted
constants/activity-center-membership-status-declined}
membership-status)
[common/swipeable
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:active-swipeable active-swipeable
:extra-fn extra-fn}
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:extra-fn extra-fn}
child]
(= membership-status constants/activity-center-membership-status-pending)
[common/swipeable
{:left-button swipe-button-accept
:left-on-press #(rf/dispatch [:communities/accept-request-to-join-pressed community-id id])
:right-button swipe-button-decline
:right-on-press #(rf/dispatch [:communities/decline-request-to-join-pressed community-id
id])
:active-swipeable active-swipeable
:extra-fn extra-fn}
{:left-button swipe-button-accept
:left-on-press accept
:right-button swipe-button-decline
:right-on-press decline
:extra-fn extra-fn}
child]
:else
child)))
(defn view
[{:keys [notification set-swipeable-height customization-color] :as props}]
[{:keys [notification] :as props}]
(let [{:keys [author community-id id membership-status
read timestamp]} notification
community (rf/sub [:communities/community community-id])
community-name (:name community)
community-image (get-in community [:images :thumbnail :uri])]
community-name (rf/sub [:communities/name community-id])
community-logo (rf/sub [:communities/logo community-id])
customization-color (rf/sub [:profile/customization-color])]
[swipeable props
[quo/activity-log
{:title (i18n/label :t/join-request)
@@ -66,14 +75,13 @@
:icon :i/add-user
:timestamp (datetime/timestamp->relative timestamp)
:unread? (not read)
:on-layout set-swipeable-height
:context [[common/user-avatar-tag author]
(i18n/label :t/wants-to-join)
[quo/context-tag
{:type :community
:size 24
:blur? true
:community-logo community-image
:community-logo community-logo
:community-name community-name}]]
:items (condp = membership-status
constants/activity-center-membership-status-accepted
@@ -4,6 +4,7 @@
(def swipe-action-width 80)
(def swipe-button-border-radius 16)
(def swipe-button-margin 8)
(def user-avatar-tag
{:background-color colors/white-opa-10})
@@ -1,10 +1,12 @@
(ns status-im.contexts.shell.activity-center.notification.common.view
(:require
[oops.core :as oops]
[quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[status-im.contexts.profile.utils :as profile.utils]
[status-im.contexts.shell.activity-center.context :as ac.context]
[status-im.contexts.shell.activity-center.notification.common.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -14,7 +16,7 @@
(let [profile (rf/sub [:contacts/contact-by-identity user-id])]
[rn/view
{:on-start-should-set-responder
(fn [_event]
(fn []
(rf/dispatch [:navigate-back])
(rf/dispatch [:chat.ui/show-profile user-id])
true)}
@@ -33,35 +35,27 @@
swipe-button
swipeable-ref
style]}]
(fn [_ ^js drag-x]
(let [{:keys [height] :as extra} (extra-fn)
opacity (.interpolate drag-x interpolation-opacity)
translate-x (.interpolate drag-x interpolation-translate-x)]
(fn [_ drag-x]
(let [extra (extra-fn)
opacity (oops/ocall drag-x :interpolate interpolation-opacity)
translate-x (oops/ocall drag-x :interpolate interpolation-translate-x)]
[gesture/rect-button
{:style (merge {:border-radius style/swipe-button-border-radius} style)
:accessibility-label :notification-swipe-action-button
:on-press (fn []
(when @swipeable-ref
(.close ^js @swipeable-ref)
(oops/ocall @swipeable-ref :close)
(reset! active-swipeable nil))
(on-press extra))}
[swipe-button
{:style {:opacity opacity
:transform [{:translateX translate-x}]
:height height
:flex 1
:width style/swipe-action-width}}
extra]])))
(defn- close-active-swipeable
[active-swipeable swipeable]
(fn [_]
(when (and @active-swipeable
(not= @active-swipeable @swipeable))
(.close ^js @active-swipeable))
(reset! active-swipeable @swipeable)))
(defn swipe-button-container
[{:keys [style icon text]} _]
[{:keys [style icon text]}]
[rn/animated-view
{:accessibility-label :notification-swipe
:style style}
@@ -103,47 +97,54 @@
(rf/dispatch [:activity-center.notifications/delete (:id notification)]))
(defn swipeable
[_]
(let [swipeable-ref (atom nil)]
(fn [{:keys [active-swipeable
extra-fn
left-button
left-on-press
right-button
right-on-press]}
& children]
(into
[gesture/swipeable
(merge
{:ref #(reset! swipeable-ref %)
:accessibility-label :notification-swipeable
:friction 2
:on-swipeable-will-open (close-active-swipeable active-swipeable swipeable-ref)
:children-container-style {:padding-horizontal 20}}
(when left-button
{:overshoot-left false
:left-threshold style/swipe-action-width
:render-left-actions (render-swipe-action
{:active-swipeable active-swipeable
:extra-fn extra-fn
:interpolation-opacity style/left-swipe-opacity-interpolation-js
:interpolation-translate-x
style/left-swipe-translate-x-interpolation-js
:on-press left-on-press
:swipe-button left-button
:swipeable-ref swipeable-ref
:style {:left 8}})})
(when right-button
{:overshoot-right false
:right-threshold style/swipe-action-width
:render-right-actions (render-swipe-action
{:active-swipeable active-swipeable
:extra-fn extra-fn
:interpolation-opacity style/right-swipe-opacity-interpolation-js
:interpolation-translate-x
style/right-swipe-translate-x-interpolation-js
:on-press right-on-press
:swipe-button right-button
:swipeable-ref swipeable-ref
:style {:right -8}})}))]
children))))
[{:keys [extra-fn
left-button
left-on-press
right-button
right-on-press]}
child]
(let [{:keys [active-swipeable]} (ac.context/use-context)
this-swipeable (rn/use-ref-atom nil)
set-this-swipeable (rn/use-callback #(reset! this-swipeable %)
[this-swipeable])
on-swipeable-will-open (rn/use-callback
(fn []
(when (and @active-swipeable
(not= @active-swipeable @this-swipeable))
(oops/ocall @active-swipeable :close))
(reset! active-swipeable @this-swipeable))
[@active-swipeable @this-swipeable])]
[gesture/swipeable
(cond-> {:ref set-this-swipeable
:accessibility-label :notification-swipeable
:friction 2
:on-swipeable-will-open on-swipeable-will-open
:children-container-style {:padding-horizontal 20}}
left-button
(assoc :overshoot-left false
:left-threshold style/swipe-action-width
:render-left-actions (render-swipe-action
{:active-swipeable active-swipeable
:extra-fn extra-fn
:interpolation-opacity style/left-swipe-opacity-interpolation-js
:interpolation-translate-x
style/left-swipe-translate-x-interpolation-js
:on-press left-on-press
:swipe-button left-button
:swipeable-ref this-swipeable
:style {:left style/swipe-button-margin}}))
right-button
(assoc :overshoot-right false
:right-threshold style/swipe-action-width
:render-right-actions (render-swipe-action
{:active-swipeable active-swipeable
:extra-fn extra-fn
:interpolation-opacity style/right-swipe-opacity-interpolation-js
:interpolation-translate-x
style/right-swipe-translate-x-interpolation-js
:on-press right-on-press
:swipe-button right-button
:swipeable-ref this-swipeable
:style {:right (- style/swipe-button-margin)}})))
child]))
@@ -1,6 +1,7 @@
(ns status-im.contexts.shell.activity-center.notification.community-kicked.view
(:require
[quo.core :as quo]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[status-im.contexts.shell.activity-center.notification.common.style :as common-style]
[status-im.contexts.shell.activity-center.notification.common.view :as common]
@@ -9,33 +10,34 @@
[utils.re-frame :as rf]))
(defn- swipeable
[{:keys [active-swipeable extra-fn]} child]
[{:keys [extra-fn]} child]
[common/swipeable
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:active-swipeable active-swipeable
:extra-fn extra-fn}
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:extra-fn extra-fn}
child])
(defn view
[{:keys [notification set-swipeable-height customization-color] :as props}]
(let [{:keys [community-id read
[{:keys [notification extra-fn]}]
(let [{:keys [id community-id read
timestamp]} notification
community (rf/sub [:communities/community community-id])
community-name (:name community)
community-image (get-in community [:images :thumbnail :uri])]
[swipeable props
[gesture/touchable-without-feedback
{:on-press (fn []
(rf/dispatch [:navigate-back])
(rf/dispatch [:activity-center.notifications/mark-as-read (:id notification)]))}
community-image (get-in community [:images :thumbnail :uri])
customization-color (rf/sub [:profile/customization-color])
on-press (rn/use-callback
(fn []
(rf/dispatch [:navigate-back])
(rf/dispatch [:activity-center.notifications/mark-as-read id]))
[id])]
[swipeable {:extra-fn extra-fn}
[gesture/touchable-without-feedback {:on-press on-press}
[quo/activity-log
{:title (i18n/label :t/community-kicked-heading)
:customization-color customization-color
:icon :i/placeholder
:on-layout set-swipeable-height
:timestamp (datetime/timestamp->relative timestamp)
:unread? (not read)
:context [[quo/text {:style common-style/user-avatar-tag-text}
@@ -1,6 +1,7 @@
(ns status-im.contexts.shell.activity-center.notification.community-request.view
(:require
[quo.core :as quo]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[status-im.constants :as constants]
[status-im.contexts.shell.activity-center.notification.common.style :as common-style]
@@ -10,27 +11,23 @@
[utils.re-frame :as rf]))
(defn- swipeable
[{:keys [active-swipeable extra-fn]} child]
[{:keys [extra-fn]} child]
[common/swipeable
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:active-swipeable active-swipeable
:extra-fn extra-fn}
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:extra-fn extra-fn}
child])
(defn- get-header-text-and-context
[community membership-status]
(let [community-name (:name community)
permissions (:permissions community)
open? (not= 3 (:access permissions))
community-image (get-in community [:images :thumbnail :uri])
[community-logo community-name community-permissions membership-status]
(let [open? (not= 3 (:access community-permissions))
community-context-tag [quo/context-tag
{:type :community
:size 24
:blur? true
:community-logo community-image
:community-logo community-logo
:community-name community-name}]]
(cond
(= membership-status constants/activity-center-membership-status-idle)
@@ -56,27 +53,33 @@
:t/joined-community
:t/community-request-accepted-body-text)
(when open? {:community community-name}))]
community-context-tag]}
:else nil)))
community-context-tag]})))
(defn view
[{:keys [notification set-swipeable-height customization-color] :as props}]
[{:keys [notification extra-fn]}]
(let [{:keys [community-id membership-status read
timestamp]} notification
community (rf/sub [:communities/community community-id])
{:keys [header-text context]} (get-header-text-and-context community
membership-status)]
[swipeable props
[gesture/touchable-without-feedback
{:on-press (fn []
(rf/dispatch [:navigate-back])
(rf/dispatch [:communities/navigate-to-community-overview community-id]))}
timestamp]} notification
community-name (rf/sub [:communities/name community-id])
community-logo (rf/sub [:communities/logo community-id])
community-permissions (rf/sub [:communities/permissions community-id])
customization-color (rf/sub [:profile/customization-color])
{:keys [header-text
context]} (get-header-text-and-context community-logo
community-name
community-permissions
membership-status)
on-press (rn/use-callback
(fn []
(rf/dispatch [:navigate-back])
(rf/dispatch [:communities/navigate-to-community-overview
community-id]))
[community-id])]
[swipeable {:extra-fn extra-fn}
[gesture/touchable-without-feedback {:on-press on-press}
[quo/activity-log
{:title header-text
:customization-color customization-color
:icon :i/communities
:on-layout set-swipeable-height
:timestamp (datetime/timestamp->relative timestamp)
:unread? (not read)
:context context}]]]))
@@ -1,6 +1,7 @@
(ns status-im.contexts.shell.activity-center.notification.contact-requests.view
(:require
[quo.core :as quo]
quo.theme
[react-native.core :as rn]
[status-im.constants :as constants]
[status-im.contexts.shell.activity-center.notification.common.style :as common-style]
@@ -24,48 +25,52 @@
:text (i18n/label :t/decline)}])
(defn- swipeable
[{:keys [active-swipeable extra-fn notification]} child]
[{:keys [extra-fn notification]} child]
(let [{:keys [id author message]} notification
{:keys [contact-request-state]} message
{:keys [public-key]} (rf/sub [:multiaccount/contact])
outgoing? (= public-key author)]
outgoing? (= public-key author)
accept (rn/use-callback
#(rf/dispatch [:activity-center.contact-requests/accept id])
[id])
decline (rn/use-callback
#(rf/dispatch [:activity-center.contact-requests/decline id])
[id])]
(cond
(or (#{constants/contact-request-message-state-accepted
constants/contact-request-message-state-declined}
contact-request-state)
(and outgoing? (= contact-request-state constants/contact-request-message-state-pending)))
[common/swipeable
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:active-swipeable active-swipeable
:extra-fn extra-fn}
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:extra-fn extra-fn}
child]
(and (= contact-request-state constants/contact-request-message-state-pending)
(not outgoing?))
[common/swipeable
{:left-button swipe-button-accept
:left-on-press #(rf/dispatch [:activity-center.contact-requests/accept id])
:right-button swipe-button-decline
:right-on-press #(rf/dispatch [:activity-center.contact-requests/decline id])
:active-swipeable active-swipeable
:extra-fn extra-fn}
{:left-button swipe-button-accept
:left-on-press accept
:right-button swipe-button-decline
:right-on-press decline
:extra-fn extra-fn}
child]
:else
child)))
(defn- outgoing-contact-request-view
[{:keys [notification set-swipeable-height customization-color]} theme]
[{:keys [notification]} theme]
(let [{:keys [chat-id message last-message accepted]} notification
{:keys [contact-request-state] :as message} (or message last-message)]
{:keys [contact-request-state] :as message} (or message last-message)
customization-color (rf/sub [:profile/customization-color])]
(if accepted
[quo/activity-log
{:title (i18n/label :t/contact-request-was-accepted)
:customization-color customization-color
:on-layout set-swipeable-height
:icon :i/add-user
:timestamp (datetime/timestamp->relative (:timestamp notification))
:unread? (not (:read notification))
@@ -76,7 +81,6 @@
[quo/activity-log
{:title (i18n/label :t/contact-request)
:customization-color customization-color
:on-layout set-swipeable-height
:icon :i/add-user
:timestamp (datetime/timestamp->relative (:timestamp notification))
:unread? (not (:read notification))
@@ -102,13 +106,22 @@
nil)}])))
(defn- incoming-contact-request-view
[{:keys [notification set-swipeable-height customization-color]} theme]
(let [{:keys [id author message last-message]} notification
message (or message last-message)]
[{:keys [notification]} theme]
(let [{:keys [id author message
last-message]} notification
customization-color (rf/sub [:profile/customization-color])
message (or message last-message)
accept (rn/use-callback
(fn []
(rf/dispatch [:activity-center.contact-requests/accept id]))
[id])
decline (rn/use-callback
(fn []
(rf/dispatch [:activity-center.contact-requests/decline id]))
[id])]
[quo/activity-log
{:title (i18n/label :t/contact-request)
:customization-color customization-color
:on-layout set-swipeable-height
:icon :i/add-user
:timestamp (datetime/timestamp->relative (:timestamp notification))
:unread? (not (:read notification))
@@ -140,13 +153,13 @@
:key :button-decline
:label (i18n/label :t/decline)
:accessibility-label :decline-contact-request
:on-press #(rf/dispatch [:activity-center.contact-requests/decline id])}
:on-press decline}
{:type :button
:subtype :positive
:key :button-accept
:label (i18n/label :t/accept)
:accessibility-label :accept-contact-request
:on-press #(rf/dispatch [:activity-center.contact-requests/accept id])}]
:on-press accept}]
nil)}]))
@@ -155,16 +168,16 @@
(let [{:keys [author message last-message]} notification
{:keys [public-key]} (rf/sub [:multiaccount/contact])
{:keys [contact-request-state]} (or message last-message)
app-theme (rf/sub [:theme])]
theme (quo.theme/use-theme)]
[swipeable props
(cond
(= public-key author)
[outgoing-contact-request-view props app-theme]
[outgoing-contact-request-view props theme]
(= contact-request-state constants/contact-request-message-state-accepted)
[rn/pressable
{:on-press #(rf/dispatch [:chat.ui/start-chat author])}
[incoming-contact-request-view props app-theme]]
[incoming-contact-request-view props theme]]
:else
[incoming-contact-request-view props app-theme])]))
[incoming-contact-request-view props theme])]))
@@ -105,7 +105,7 @@
(rf/dispatch [:activity-center.notifications/mark-as-read id]))
(defn- swipeable
[{:keys [active-swipeable extra-fn notification replying?] :as props} child]
[{:keys [extra-fn notification replying?] :as props} child]
(let [{:keys [id message
contact-verification-status]} notification
challenger? (:outgoing message)]
@@ -116,23 +116,21 @@
(and (not challenger?)
(= contact-verification-status constants/contact-verification-status-pending))
[common/swipeable
{:left-button swipe-button-reply
:left-on-press #(prepare-challenge-reply props)
:right-button swipe-button-decline
:right-on-press #(decline-challenge id)
:active-swipeable active-swipeable
:extra-fn extra-fn}
{:left-button swipe-button-reply
:left-on-press #(prepare-challenge-reply props)
:right-button swipe-button-decline
:right-on-press #(decline-challenge id)
:extra-fn extra-fn}
child]
(and challenger?
(= contact-verification-status constants/contact-verification-status-accepted))
[common/swipeable
{:left-button swipe-button-trust
:left-on-press #(mark-challenge-trusted id)
:right-button swipe-button-untrustworthy
:right-on-press #(mark-challenge-untrustworthy id)
:active-swipeable active-swipeable
:extra-fn extra-fn}
{:left-button swipe-button-trust
:left-on-press #(mark-challenge-trusted id)
:right-button swipe-button-untrustworthy
:right-on-press #(mark-challenge-untrustworthy id)
:extra-fn extra-fn}
child]
(#{constants/contact-verification-status-accepted
@@ -140,12 +138,11 @@
constants/contact-verification-status-trusted}
contact-verification-status)
[common/swipeable
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:active-swipeable active-swipeable
:extra-fn extra-fn}
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:extra-fn extra-fn}
child]
:else
@@ -154,8 +151,9 @@
(defn view
[_]
(let [reply (atom "")]
(fn [{:keys [notification set-swipeable-height replying? customization-color] :as props}]
(let [{:keys [id message
(fn [{:keys [notification replying?] :as props}]
(let [customization-color (rf/sub [:profile/customization-color])
{:keys [id message
contact-verification-status]} notification
challenger? (:outgoing message)]
;; TODO(@ilmotta): Declined challenges should only be displayed for the challengee, not the
@@ -165,86 +163,84 @@
(= contact-verification-status constants/contact-verification-status-declined))
[swipeable props
[quo/activity-log
(merge
(when-not replying?
{:on-layout set-swipeable-height})
{:title (i18n/label :t/identity-verification-request)
:customization-color customization-color
:icon :i/friend
:timestamp (datetime/timestamp->relative (:timestamp notification))
:unread? (not (:read notification))
:on-update-reply #(reset! reply %)
:replying? replying?
:max-reply-length max-reply-length
:valid-reply? valid-reply?
:context (context-tags challenger? notification)
:message (activity-message challenger? notification)
:items
(cond-> []
(and challenger?
(= contact-verification-status constants/contact-verification-status-accepted))
(concat
[{:type :button
:subtype :danger
:key :button-mark-as-untrustworthy
:label (i18n/label :t/untrustworthy)
:accessibility-label :mark-contact-verification-as-untrustworthy
:on-press #(mark-challenge-untrustworthy id)}
{:type :button
:subtype :positive
:key :button-accept
:label (i18n/label :t/accept)
:accessibility-label :mark-contact-verification-as-trusted
:on-press #(mark-challenge-trusted id)}])
{:title (i18n/label :t/identity-verification-request)
:customization-color customization-color
:icon :i/friend
:timestamp (datetime/timestamp->relative (:timestamp notification))
:unread? (not (:read notification))
:on-update-reply #(reset! reply %)
:replying? replying?
:max-reply-length max-reply-length
:valid-reply? valid-reply?
:context (context-tags challenger? notification)
:message (activity-message challenger? notification)
:items
(cond-> []
(and challenger?
(= contact-verification-status constants/contact-verification-status-accepted))
(concat
[{:type :button
:subtype :danger
:key :button-mark-as-untrustworthy
:label (i18n/label :t/untrustworthy)
:accessibility-label :mark-contact-verification-as-untrustworthy
:on-press #(mark-challenge-untrustworthy id)}
{:type :button
:subtype :positive
:key :button-accept
:label (i18n/label :t/accept)
:accessibility-label :mark-contact-verification-as-trusted
:on-press #(mark-challenge-trusted id)}])
(and challenger?
(= contact-verification-status constants/contact-verification-status-trusted))
(concat [{:type :status
:subtype :positive
:key :status-trusted
:label (i18n/label :t/status-confirmed)}])
(and challenger?
(= contact-verification-status constants/contact-verification-status-trusted))
(concat [{:type :status
:subtype :positive
:key :status-trusted
:label (i18n/label :t/status-confirmed)}])
(and challenger?
(= contact-verification-status constants/contact-verification-status-untrustworthy))
(concat [{:type :status
:subtype :negative
:key :status-untrustworthy
:label (i18n/label :t/untrustworthy)}])
(and challenger?
(= contact-verification-status
constants/contact-verification-status-untrustworthy))
(concat [{:type :status
:subtype :negative
:key :status-untrustworthy
:label (i18n/label :t/untrustworthy)}])
(and (not challenger?)
(= contact-verification-status constants/contact-verification-status-accepted))
(concat [{:type :status
:subtype :positive
:key :status-accepted
:label (i18n/label :t/replied)}])
(and (not challenger?)
(= contact-verification-status constants/contact-verification-status-accepted))
(concat [{:type :status
:subtype :positive
:key :status-accepted
:label (i18n/label :t/replied)}])
(and (not challenger?)
(= contact-verification-status constants/contact-verification-status-declined))
(concat [{:type :status
:subtype :negative
:key :status-declined
:label (i18n/label :t/declined)}])
(and (not challenger?)
(= contact-verification-status constants/contact-verification-status-declined))
(concat [{:type :status
:subtype :negative
:key :status-declined
:label (i18n/label :t/declined)}])
(and (not challenger?)
(= contact-verification-status constants/contact-verification-status-pending))
(concat
[{:type :button
:subtype :danger
:key :button-decline
:label (i18n/label :t/decline)
:accessibility-label :decline-contact-verification
:on-press #(decline-challenge id)}
(if replying?
{:type :button
:subtype :primary
:key :button-reply
:label (i18n/label :t/send-reply)
:accessibility-label :reply-to-contact-verification
:disable-when invalid-reply?
:on-press #(send-challenge-reply id @reply)}
{:type :button
:subtype :primary
:key :button-send-reply
:label (i18n/label :t/message-reply)
:accessibility-label :send-reply-to-contact-verification
:on-press #(prepare-challenge-reply props)})]))})]])))))
(and (not challenger?)
(= contact-verification-status constants/contact-verification-status-pending))
(concat
[{:type :button
:subtype :danger
:key :button-decline
:label (i18n/label :t/decline)
:accessibility-label :decline-contact-verification
:on-press #(decline-challenge id)}
(if replying?
{:type :button
:subtype :primary
:key :button-reply
:label (i18n/label :t/send-reply)
:accessibility-label :reply-to-contact-verification
:disable-when invalid-reply?
:on-press #(send-challenge-reply id @reply)}
{:type :button
:subtype :primary
:key :button-send-reply
:label (i18n/label :t/message-reply)
:accessibility-label :send-reply-to-contact-verification
:on-press #(prepare-challenge-reply props)})]))}]])))))
@@ -1,6 +1,7 @@
(ns status-im.contexts.shell.activity-center.notification.membership.view
(:require
[quo.core :as quo]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[status-im.contexts.shell.activity-center.notification.common.style :as common-style]
[status-im.contexts.shell.activity-center.notification.common.view :as common]
@@ -33,35 +34,50 @@
:text (i18n/label :t/decline)}])
(defn- swipeable
[{:keys [active-swipeable notification extra-fn]} child]
(let [{:keys [accepted dismissed id]} notification]
[{:keys [notification extra-fn]} child]
(let [{:keys [accepted dismissed
id]} notification
accept (rn/use-callback
(fn [] (rf/dispatch [:activity-center.notifications/accept id]))
[id])
dismiss (rn/use-callback
(fn [] (rf/dispatch [:activity-center.notifications/dismiss id]))
[id])]
(if (or accepted dismissed)
[common/swipeable
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:active-swipeable active-swipeable
:extra-fn extra-fn}
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:extra-fn extra-fn}
child]
[common/swipeable
{:left-button swipe-button-accept
:left-on-press #(rf/dispatch [:activity-center.notifications/accept id])
:right-button swipe-button-decline
:right-on-press #(rf/dispatch [:activity-center.notifications/dismiss id])
:active-swipeable active-swipeable
:extra-fn extra-fn}
{:left-button swipe-button-accept
:left-on-press accept
:right-button swipe-button-decline
:right-on-press dismiss
:extra-fn extra-fn}
child])))
(defn view
[{:keys [notification set-swipeable-height customization-color] :as props}]
(let [{:keys [id accepted dismissed author read timestamp chat-name chat-id]} notification]
[{:keys [notification] :as props}]
(let [{:keys [id accepted dismissed author read
timestamp chat-name
chat-id]} notification
customization-color (rf/sub [:profile/customization-color])
accept (rn/use-callback
(fn []
(rf/dispatch [:activity-center.notifications/accept id]))
[id])
dismiss (rn/use-callback
(fn []
(rf/dispatch [:activity-center.notifications/dismiss id]))
[id])]
[swipeable props
[pressable {:accepted accepted :chat-id chat-id}
[quo/activity-log
{:title (i18n/label :t/added-to-group-chat)
:customization-color customization-color
:on-layout set-swipeable-height
:icon :i/add-user
:timestamp (datetime/timestamp->relative timestamp)
:unread? (not read)
@@ -78,13 +94,10 @@
:key :button-accept
:label (i18n/label :t/accept)
:accessibility-label :accept-group-chat-invitation
:on-press #(rf/dispatch
[:activity-center.notifications/accept id])}
:on-press accept}
{:type :button
:subtype :danger
:key :button-decline
:label (i18n/label :t/decline)
:accessibility-label :decline-group-chat-invitation
:on-press #(rf/dispatch
[:activity-center.notifications/dismiss
id])}])}]]]))
:on-press dismiss}])}]]]))
@@ -30,25 +30,24 @@
parsed-text-children))))
(defn- swipeable
[{:keys [active-swipeable extra-fn]} child]
[{:keys [extra-fn]} child]
[common/swipeable
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:active-swipeable active-swipeable
:extra-fn extra-fn}
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:extra-fn extra-fn}
child])
(defn view
[{:keys [notification set-swipeable-height customization-color] :as props}]
[{:keys [notification extra-fn]}]
(let [{:keys [author chat-name community-id chat-id
message read timestamp]} notification
community-chat? (not (string/blank? community-id))
community (rf/sub [:communities/community community-id])
community-name (:name community)
community-image (get-in community [:images :thumbnail :uri])]
[swipeable props
community-name (rf/sub [:communities/name community-id])
community-logo (rf/sub [:communities/logo community-id])
customization-color (rf/sub [:profile/customization-color])]
[swipeable {:extra-fn extra-fn}
[gesture/touchable-without-feedback
{:on-press (fn []
(rf/dispatch [:hide-popover])
@@ -56,7 +55,6 @@
[quo/activity-log
{:title (i18n/label :t/mention)
:customization-color customization-color
:on-layout set-swipeable-height
:icon :i/mention
:timestamp (datetime/timestamp->relative timestamp)
:unread? (not read)
@@ -68,7 +66,7 @@
{:type :channel
:blur? true
:size 24
:community-logo community-image
:community-logo community-logo
:community-name community-name
:channel-name chat-name}]
[quo/context-tag
@@ -51,26 +51,26 @@
nil))
(defn- swipeable
[{:keys [active-swipeable extra-fn]} child]
[{:keys [extra-fn]} child]
[common/swipeable
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:active-swipeable active-swipeable
:extra-fn extra-fn}
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
:right-button common/swipe-button-delete
:right-on-press common/swipe-on-press-delete
:extra-fn extra-fn}
child])
(defn view
[{:keys [notification set-swipeable-height customization-color] :as props}]
[{:keys [notification extra-fn]}]
(let [{:keys [author chat-name community-id chat-id
message read timestamp album-messages]} notification
community-chat? (not (string/blank? community-id))
community (rf/sub [:communities/community community-id])
community-name (:name community)
community-image (get-in community [:images :thumbnail :uri])
media-server-port (rf/sub [:mediaserver/port])]
[swipeable props
message read timestamp
album-messages]} notification
community-chat? (not (string/blank? community-id))
community-name (rf/sub [:communities/name community-id])
community-logo (rf/sub [:communities/logo community-id])
customization-color (rf/sub [:profile/customization-color])
media-server-port (rf/sub [:mediaserver/port])]
[swipeable {:extra-fn extra-fn}
[gesture/touchable-without-feedback
{:on-press (fn []
(rf/dispatch [:hide-popover])
@@ -78,7 +78,6 @@
[quo/activity-log
{:title (i18n/label :t/message-reply)
:customization-color customization-color
:on-layout set-swipeable-height
:icon :i/reply
:timestamp (datetime/timestamp->relative timestamp)
:unread? (not read)
@@ -89,7 +88,7 @@
{:type :channel
:blur? true
:size 24
:community-logo community-image
:community-logo community-logo
:community-name community-name
:channel-name chat-name}]
[quo/context-tag
@@ -113,10 +112,7 @@
(= (:content-type message)
constants/content-type-gif)
:gif
:else
nil)
:gif)
:body (get-message-content message
album-messages
media-server-port)}}]]]))
@@ -1,9 +1,10 @@
(ns status-im.contexts.shell.activity-center.view
(:require
[oops.core :as oops]
[quo.core :as quo]
[react-native.core :as rn]
[react-native.navigation :as navigation]
[status-im.constants :as constants]
[status-im.contexts.shell.activity-center.context :as ac.context]
[status-im.contexts.shell.activity-center.header.view :as header]
[status-im.contexts.shell.activity-center.notification-types :as types]
[status-im.contexts.shell.activity-center.notification.admin.view :as admin]
@@ -23,61 +24,68 @@
[utils.re-frame :as rf]))
(defn notification-component
[{:keys [type] :as notification} index]
(let [extra-fn (rn/use-callback
(fn []
{:notification notification})
[notification])
props {:notification notification
:extra-fn extra-fn}]
;; Notifications are expensive to render. Without `delay-render` the opening
;; animation of the Activity Center can be clunky and the time to open the
;; AC after pressing the bell icon can be high.
[rn/view {:style (style/notification-container index)}
(cond
(= type types/contact-verification)
[contact-verification/view props]
(= type types/contact-request)
[contact-requests/view props]
(= type types/mention)
[mentions/view props]
(= type types/reply)
[reply/view props]
(= type types/admin)
[admin/view props]
(some types/membership [type])
(condp = type
types/private-group-chat [membership/view props]
types/community-request [community-request/view props]
types/community-kicked [community-kicked/view props]
nil))]))
(defn- fetch-next-page
[]
(let [height (atom 0)
set-swipeable-height #(reset! height (oops/oget % "nativeEvent.layout.height"))]
(fn [{:keys [type] :as notification} index _ {:keys [active-swipeable customization-color]}]
(let [props {:height height
:customization-color customization-color
:active-swipeable active-swipeable
:set-swipeable-height set-swipeable-height
:notification notification
:extra-fn (fn [] {:height @height :notification notification})}]
[rn/view {:style (style/notification-container index)}
(cond
(= type types/contact-verification)
[contact-verification/view props]
(= type types/contact-request)
[contact-requests/view props]
(= type types/mention)
[mentions/view props]
(= type types/reply)
[reply/view props]
(= type types/admin)
[admin/view props]
(some types/membership [type])
(condp = type
types/private-group-chat [membership/view props]
types/community-request [community-request/view props]
types/community-kicked [community-kicked/view props]
nil)
:else
nil)]))))
(rf/dispatch [:activity-center.notifications/fetch-next-page]))
(defn view
[]
(let [active-swipeable (atom nil)]
(rf/dispatch [:activity-center.notifications/fetch-first-page])
(fn []
(let [notifications (rf/sub [:activity-center/notifications])
customization-color (rf/sub [:profile/customization-color])]
[quo/overlay {:type :shell}
[rn/view {:flex 1 :padding-top (navigation/status-bar-height)}
[header/header]
[rn/flat-list
{:data notifications
:render-data {:active-swipeable active-swipeable
:customization-color customization-color}
:content-container-style {:flex-grow 1}
:empty-component [empty-tab/empty-tab]
:key-fn :id
:on-scroll-to-index-failed identity
:on-end-reached #(rf/dispatch [:activity-center.notifications/fetch-next-page])
:render-fn notification-component}]]
]))))
(let [notifications (rf/sub [:activity-center/notifications])
;; We globally control the active swipeable for all notifications
;; because when a swipe left/right gesture initiates, the previously
;; active swiped notification (if any) must be removed & closed with
;; animation.
active-swipeable (rn/use-ref-atom nil)]
(rn/use-mount
(fn []
(rf/dispatch [:activity-center.notifications/fetch-first-page])))
[ac.context/provider {:active-swipeable active-swipeable}
[quo/overlay {:type :shell}
[rn/view {:style {:flex 1 :padding-top (navigation/status-bar-height)}}
[header/header]
(rn/delay-render
[rn/flat-list
{:data notifications
:initial-num-to-render constants/notifications-per-page
:content-container-style {:flex-grow 1}
:empty-component [empty-tab/empty-tab]
:key-fn :id
:on-scroll-to-index-failed identity
:on-end-reached fetch-next-page
:render-fn notification-component}])]]]))
@@ -117,13 +117,14 @@
(defn- f-internal-view
[]
(let [{:keys [keyboard-shown]} (hooks/use-keyboard)]
[:<>
(when keyboard-shown
(rn/dismiss-keyboard!))
[scan-qr-code/view
{:title (i18n/label :t/scan-qr)
:share-button? true
:on-success-scan on-qr-code-scanned}]]))
(rn/use-mount
(fn []
(when keyboard-shown
(rn/dismiss-keyboard!))))
[scan-qr-code/view
{:title (i18n/label :t/scan-qr)
:share-button? true
:on-success-scan on-qr-code-scanned}]))
(defn view
[]
@@ -4,12 +4,19 @@
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
(defonce ^:private request-id-atom (atom 0))
(defn- get-unique-request-id
[]
(swap! request-id-atom inc)
@request-id-atom)
(rf/reg-event-fx
:wallet/fetch-activities-for-current-account
(fn [{:keys [db]}]
(let [address (-> db :wallet :current-viewing-account-address)
chain-ids (chain/chain-ids db)
request-id 0
request-id (get-unique-request-id)
filters {:period {:startTimestamp 0
:endTimestamp 0}
:types []
@@ -20,9 +27,10 @@
:filterOutAssets false
:filterOutCollectibles false}
offset 0
limit 35
limit 50
request-params [request-id [address] chain-ids filters offset limit]]
{:fx [[:json-rpc/call
{:db (assoc-in db [:wallet :ui :activity-tab :request request-id] address)
:fx [[:json-rpc/call
[{;; This method is deprecated and will be replaced by
;; "wallet_startActivityFilterSession"
;; https://github.com/status-im/status-mobile/issues/19864
@@ -32,13 +40,31 @@
{:event :wallet/fetch-activities-for-current-account
:params request-params}]}]]]})))
(def ^:private activity-transaction-id (comp hash :transaction))
(rf/reg-event-fx
:wallet/activity-filtering-for-current-account-done
(fn [{:keys [db]} [{:keys [message]}]]
(let [address (-> db :wallet :current-viewing-account-address)
activities (->> message
(transforms/json->clj)
(:activities)
(cske/transform-keys transforms/->kebab-case-keyword))
sorted-activities (sort :timestamp activities)]
{:db (assoc-in db [:wallet :activities address] sorted-activities)})))
(fn [{:keys [db]} [{:keys [message requestId]}]]
(let [address (get-in db [:wallet :ui :activity-tab :request requestId])
activities (->> message
(transforms/json->clj)
(:activities)
(cske/transform-keys transforms/->kebab-case-keyword))
activities-indexed (zipmap (map activity-transaction-id activities)
activities)]
{:db (assoc-in db [:wallet :activities address] activities-indexed)})))
(def ^:private nested-merge (partial merge-with merge))
(rf/reg-event-fx
:wallet/activities-filtering-entries-updated
(fn [{:keys [db]} [{:keys [message requestId]}]]
(let [address (get-in db [:wallet :ui :activity-tab :request requestId])
activities (->> message
(transforms/json->clj)
(cske/transform-keys transforms/->kebab-case-keyword))
activities-indexed (zipmap (map activity-transaction-id activities)
activities)]
{:db (-> db
(update-in [:wallet :ui :activity-tab :request] dissoc requestId)
(update-in [:wallet :activities address] nested-merge activities-indexed))})))
@@ -11,31 +11,81 @@
(defn send-and-receive-activity
[{:keys [transaction relative-date status sender recipient token amount network-name
network-logo]}]
[quo/wallet-activity
{:transaction transaction
:timestamp relative-date
:status status
:counter 1
:first-tag {:size 24
:type :token
:token token
:amount amount}
:second-tag-prefix :t/from
:second-tag {:type :address :address sender}
:third-tag-prefix :t/to
:third-tag {:type :address :address recipient}
:fourth-tag-prefix :t/via
:fourth-tag {:size 24
:type :network
:network-name network-name
:network-logo network-logo}
:blur? false}])
network-logo token-id nft-url nft-name]}]
(if token-id
[quo/wallet-activity
{:transaction transaction
:timestamp relative-date
:status status
:counter 1
:first-tag {:size 24
:type :collectible
:collectible nft-url
:collectible-name (if (> amount 1)
(str amount " " nft-name)
nft-name)
:collectible-number token-id}
:second-tag-prefix :t/from
:second-tag {:type :address :address sender}
:third-tag-prefix :t/to
:third-tag {:type :address :address recipient}
:fourth-tag-prefix :t/via
:fourth-tag {:size 24
:type :network
:network-name network-name
:network-logo network-logo}
:blur? false}]
[quo/wallet-activity
{:transaction transaction
:timestamp relative-date
:status status
:counter 1
:first-tag {:size 24
:type :token
:token token
:amount amount}
:second-tag-prefix :t/from
:second-tag {:type :address :address sender}
:third-tag-prefix :t/to
:third-tag {:type :address :address recipient}
:fourth-tag-prefix :t/via
:fourth-tag {:size 24
:type :network
:network-name network-name
:network-logo network-logo}
:blur? false}]))
;; WIP to add the mint activity.
;(defn mint-activity
; [{:keys [transaction relative-date status recipient network-name
; network-logo nft-name nft-url token-id]}]
; [quo/wallet-activity
; {:transaction transaction
; :timestamp relative-date
; :status status
; :counter 1
; :first-tag {:size 24
; :type :collectible
; :collectible nft-url
; :collectible-name nft-name
; :collectible-number token-id}
; :second-tag-prefix :t/at
; :second-tag {:type :address :address recipient}
; :third-tag-prefix :t/to
; :third-tag {:type :address :address recipient}
; :fourth-tag-prefix :t/via
; :fourth-tag {:size 24
; :type :network
; :network-name network-name
; :network-logo network-logo}
; :blur? false}])
(defn activity-item
[{:keys [transaction] :as activity}]
(case transaction
(:send :receive) [send-and-receive-activity activity]
;; WIP to add the mint activity.
;; :mint [mint-activity activity]
nil))
(defn view
@@ -172,17 +172,20 @@
(defn get-network-details
[chain-id]
(condp contains? chain-id
#{constants/ethereum-mainnet-chain-id constants/ethereum-goerli-chain-id
constants/ethereum-sepolia-chain-id}
mainnet-network-details
(as-> chain-id $
(condp contains? $
#{constants/ethereum-mainnet-chain-id constants/ethereum-goerli-chain-id
constants/ethereum-sepolia-chain-id}
mainnet-network-details
#{constants/arbitrum-mainnet-chain-id constants/arbitrum-goerli-chain-id
constants/arbitrum-sepolia-chain-id}
arbitrum-network-details
#{constants/arbitrum-mainnet-chain-id constants/arbitrum-goerli-chain-id
constants/arbitrum-sepolia-chain-id}
arbitrum-network-details
#{constants/optimism-mainnet-chain-id constants/optimism-goerli-chain-id
constants/optimism-sepolia-chain-id}
optimism-network-details
#{constants/optimism-mainnet-chain-id constants/optimism-goerli-chain-id
constants/optimism-sepolia-chain-id}
optimism-network-details
nil))
nil)
(when $
(assoc $ :chain-id chain-id))))
@@ -13,26 +13,26 @@
[utils.re-frame :as rf]))
(defn- on-disconnect
[wallet-account {:keys [name topic]}]
[wallet-account {:keys [name topic pairing-topic]}]
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch
[:wallet-connect/disconnect-dapp
{:topic topic
:on-success (fn []
(rf/dispatch [:wallet-connect/remove-pairing-by-topic topic])
(rf/dispatch [:toasts/upsert
{:id :dapp-disconnect-success
:type :positive
:text (i18n/label :t/disconnect-dapp-success
{:dapp name
:account (:name wallet-account)})}]))
:on-fail (fn []
(rf/dispatch [:toasts/upsert
{:id :dapp-disconnect-failure
:type :negative
:text (i18n/label :t/disconnect-dapp-fail
{:dapp name
:account (:name wallet-account)})}]))}]))
{:topic topic
:pairing-topic pairing-topic
:on-success (fn []
(rf/dispatch [:toasts/upsert
{:id :dapp-disconnect-success
:type :positive
:text (i18n/label :t/disconnect-dapp-success
{:dapp name
:account (:name wallet-account)})}]))
:on-fail (fn []
(rf/dispatch [:toasts/upsert
{:id :dapp-disconnect-failure
:type :negative
:text (i18n/label :t/disconnect-dapp-fail
{:dapp name
:account (:name wallet-account)})}]))}]))
(defn- on-dapp-disconnect-press
[wallet-account dapp]
@@ -83,7 +83,8 @@
[]
(let [{:keys [bottom]} (safe-area/get-insets)
{:keys [color] :as wallet-account} (rf/sub [:wallet/current-viewing-account])
pairings (rf/sub [:wallet-connect/pairings])
sessions (rf/sub
[:wallet-connect/sessions-for-current-account])
theme (quo.theme/use-theme)]
[rn/view {:flex 1}
[header
@@ -91,7 +92,7 @@
:wallet-account wallet-account
:on-close #(rf/dispatch [:navigate-back])
:on-add #(rf/dispatch [:navigate-to :screen/wallet.scan-dapp])}]
(if (empty? pairings)
(if (empty? sessions)
[quo/empty-state
{:title (i18n/label :t/no-dapps)
:description (i18n/label :t/no-dapps-description)
@@ -99,16 +100,16 @@
:container-style style/empty-container-style}]
[rn/view (style/dapps-container bottom)
[rn/flat-list
{:data pairings
{:data sessions
:always-bounce-vertical false
:content-container-style (style/dapps-list theme)
:render-fn (fn [{:keys [topic]
{:keys [icons name url]} :peerMetadata}]
:render-fn (fn [{:keys [topic pairingTopic name url iconUrl]}]
[quo/dapp
{:dapp {:avatar (get icons 0)
:name name
:value url
:topic topic}
{:dapp {:avatar iconUrl
:name name
:value url
:topic topic
:pairing-topic pairingTopic}
:accessibility-label (str "dapp-" topic)
:state :default
:action :icon
@@ -187,15 +187,8 @@
(rf/reg-event-fx
:wallet/update-receiver-networks
(fn [{:keys [db]} [selected-networks]]
(let [amount (get-in db [:wallet :ui :send :amount])
disabled-from-chain-ids (get-in db [:wallet :ui :send :disabled-from-chain-ids])
filtered-disabled-from-chain-ids (filter (fn [chain-id]
(some #(= chain-id %)
selected-networks))
disabled-from-chain-ids)]
{:db (-> db
(assoc-in [:wallet :ui :send :receiver-networks] selected-networks)
(assoc-in [:wallet :ui :send :disabled-from-chain-ids] filtered-disabled-from-chain-ids))
(let [amount (get-in db [:wallet :ui :send :amount])]
{:db (assoc-in db [:wallet :ui :send :receiver-networks] selected-networks)
:fx [[:dispatch [:wallet/get-suggested-routes {:amount amount}]]]})))
(rf/reg-event-fx
@@ -23,19 +23,6 @@
selected-networks-after [:ethereum :optimism]
expected-db {:wallet {:ui {:send {:receiver-networks selected-networks-after}}}}]
(reset! rf-db/app-db {:wallet {:ui {:send {:receiver-networks selected-networks-before}}}})
(is (match? expected-db (:db (dispatch [event-id selected-networks-after]))))))
(testing "if receiver network removed, it is also removed from disabled ones"
(let [selected-networks-before [:ethereum :optimism :arbitrum]
selected-networks-after [:ethereum :optimism]
disabled-from-chain-ids-before [:optimism :arbitrum]
disabled-from-chain-ids-after [:optimism]
expected-db {:wallet {:ui {:send {:receiver-networks selected-networks-after
:disabled-from-chain-ids
disabled-from-chain-ids-after}}}}]
(reset! rf-db/app-db {:wallet {:ui {:send {:receiver-networks selected-networks-before
:disabled-from-chain-ids
disabled-from-chain-ids-before}}}})
(is (match? expected-db (:db (dispatch [event-id selected-networks-after])))))))
(h/deftest-event :wallet/set-token-to-send
@@ -120,7 +120,7 @@
[]
[quo/alert-banner
{:action? true
:text (i18n/label :t/not-enough-assets)
:text (i18n/label :t/not-enough-assets-to-pay-gas-fees)
:button-text (i18n/label :t/buy-eth)
:on-button-press #(rf/dispatch [:show-bottom-sheet
{:content buy-token/view}])}])
@@ -154,11 +154,9 @@
[input-state set-input-state] (rn/use-state controlled-input/init-state)
[just-toggled-mode? set-just-toggled-mode?] (rn/use-state false)
clear-input! #(set-input-state controlled-input/delete-all)
handle-on-confirm (fn []
handle-on-confirm (fn [amount]
(rf/dispatch [:wallet/set-token-amount-to-send
{:amount
(controlled-input/input-value
input-state)
{:amount amount
:stack-id current-screen-id}]))
{fiat-currency :currency} (rf/sub [:profile/profile])
{token-symbol :symbol
@@ -157,7 +157,6 @@
[quo/data-item
{:container-style style/detail-item
:blur? false
:description :default
:card? false
:status :default
:size :small
+35 -18
View File
@@ -23,22 +23,39 @@
:block-number blockNumber
:accounts accounts})
(case event-type
"pending-transaction-status-changed" {:fx
[[:dispatch
[:wallet/pending-transaction-status-changed-received
(transforms/js->clj event-js)]]]}
"wallet-owned-collectibles-filtering-done" {:fx [[:dispatch
[:wallet/owned-collectibles-filtering-done
(transforms/js->clj event-js)]]]}
"wallet-get-collectibles-details-done" {:fx [[:dispatch
[:wallet/get-collectible-details-done
(transforms/js->clj event-js)]]]}
"wallet-tick-reload" {:fx [[:dispatch [:wallet/reload]]]}
"wallet-blockchain-status-changed" {:fx [[:dispatch
[:wallet/blockchain-status-changed
(transforms/js->clj event-js)]]]}
"wallet-activity-filtering-done" {:fx
[[:dispatch
[:wallet/activity-filtering-for-current-account-done
(transforms/js->clj event-js)]]]}
"pending-transaction-status-changed"
{:fx
[[:dispatch
[:wallet/pending-transaction-status-changed-received
(transforms/js->clj event-js)]]]}
"wallet-owned-collectibles-filtering-done"
{:fx [[:dispatch
[:wallet/owned-collectibles-filtering-done
(transforms/js->clj event-js)]]]}
"wallet-get-collectibles-details-done"
{:fx [[:dispatch
[:wallet/get-collectible-details-done
(transforms/js->clj event-js)]]]}
"wallet-tick-reload"
{:fx [[:dispatch [:wallet/reload]]]}
"wallet-blockchain-status-changed"
{:fx [[:dispatch
[:wallet/blockchain-status-changed
(transforms/js->clj event-js)]]]}
"wallet-activity-filtering-done"
{:fx
[[:dispatch
[:wallet/activity-filtering-for-current-account-done
(transforms/js->clj event-js)]]]}
"wallet-activity-filtering-entries-updated"
{:fx [[:dispatch
[:wallet/activities-filtering-entries-updated
(transforms/js->clj event-js)]]]}
(log/debug ::unknown-wallet-event :type event-type)))))
@@ -85,12 +85,45 @@
(defn required-networks-supported?
[proposal supported-networks]
(let [required-networks (get-in proposal [:params :requiredNamespaces :eip155 :chains])
supported-eip155 (set (map chain-id->eip155 supported-networks))]
(every? #(contains? supported-eip155 %) required-networks)))
(let [supported-namespaces #{:eip155}
required-namespaces (get-in proposal [:params :requiredNamespaces])]
(when (every? #(contains? supported-namespaces %)
(keys required-namespaces))
(let [required-networks (get-in required-namespaces [:eip155 :chains])
supported-eip155 (set (map chain-id->eip155 supported-networks))]
(every? #(contains? supported-eip155 %)
required-networks)))))
(defn get-networks-by-mode
[db]
(let [test-mode? (get-in db [:profile/profile :test-networks-enabled?])
networks (get-in db [:wallet :networks (if test-mode? :test :prod)])]
(mapv #(-> % :chain-id) networks)))
(defn add-full-testnet-name
"Updates the `:full-name` key with the full testnet name if using testnet `:chain-id`.\n
e.g. `{:full-name \"Mainnet\"}` -> `{:full-name \"Mainnet Sepolia\"`}`"
[network]
(let [add-testnet-name (fn [testnet-name]
(update network :full-name #(str % " " testnet-name)))]
(condp #(contains? %1 %2) (:chain-id network)
constants/sepolia-chain-ids (add-testnet-name constants/sepolia-full-name)
constants/goerli-chain-ids (add-testnet-name constants/goerli-full-name)
network)))
(defn event-should-be-handled?
[db {:keys [topic]}]
(some #(= topic %)
(map :topic (:wallet-connect/sessions db))))
(defn sdk-session->db-session
[{:keys [topic expiry pairingTopic] :as session}]
{:topic topic
:expiry expiry
:sessionJson (transforms/clj->json session)
:pairingTopic pairingTopic
:name (get-in session [:peer :metadata :name])
:iconUrl (get-in session [:peer :metadata :icons 0])
:url (get-in session [:peer :metadata :url])
:accounts (get-in session [:namespaces :eip155 :accounts])
:disconnected false})
@@ -31,13 +31,6 @@
:event wc-event
:handler handler})))
(rf/reg-fx
:effects.wallet-connect/fetch-pairings
(fn [{:keys [web3-wallet on-success on-fail]}]
(-> (wallet-connect/get-pairings web3-wallet)
(promesa/then on-success)
(promesa/catch on-fail))))
(rf/reg-fx
:effects.wallet-connect/pair
(fn [{:keys [web3-wallet url on-success on-fail]}]
@@ -53,13 +46,6 @@
(promesa/then on-success)
(promesa/catch on-fail))))
(rf/reg-fx
:effects.wallet-connect/fetch-active-sessions
(fn [{:keys [web3-wallet on-success on-fail]}]
(-> (wallet-connect/get-active-sessions web3-wallet)
(promesa/then on-success)
(promesa/catch on-fail))))
(rf/reg-fx
:effects.wallet-connect/approve-session
(fn [{:keys [web3-wallet proposal supported-namespaces on-success on-fail]}]
@@ -74,6 +60,13 @@
(promesa/then on-success)
(promesa/catch on-fail)))))
(rf/reg-fx
:effects.wallet-connect/fetch-active-sessions
(fn [{:keys [web3-wallet on-success on-fail]}]
(-> (wallet-connect/get-active-sessions web3-wallet)
(promesa/then on-success)
(promesa/catch on-fail))))
(rf/reg-fx
:effects.wallet-connect/sign-message
(fn [{:keys [password address data rpc-method on-success on-error]}]
@@ -90,22 +83,33 @@
(promesa/then on-success)
(promesa/catch on-error)))))
(rf/reg-fx
:effects.wallet-connect/prepare-transaction
(fn [{:keys [tx chain-id on-success on-error]}]
(-> (transactions/prepare-transaction tx
chain-id
transactions/default-tx-priority)
(promesa/then on-success)
(promesa/catch on-error))))
(rf/reg-fx
:effects.wallet-connect/sign-transaction
(fn [{:keys [password address chain-id tx on-success on-error]}]
(fn [{:keys [password address chain-id tx-hash tx-args on-success on-error]}]
(-> (transactions/sign-transaction (security/safe-unmask-data password)
address
tx
tx-hash
tx-args
chain-id)
(promesa/then on-success)
(promesa/catch on-error))))
(rf/reg-fx
:effects.wallet-connect/send-transaction
(fn [{:keys [password address chain-id tx on-success on-error]}]
(fn [{:keys [password address chain-id tx-hash tx-args on-success on-error]}]
(-> (transactions/send-transaction (security/safe-unmask-data password)
address
tx
tx-hash
tx-args
chain-id)
(promesa/then on-success)
(promesa/catch on-error))))
@@ -8,7 +8,8 @@
status-im.contexts.wallet.wallet-connect.responding-events
[status-im.contexts.wallet.wallet-connect.utils :as wc-utils]
[taoensso.timbre :as log]
[utils.i18n :as i18n]))
[utils.i18n :as i18n]
[utils.transforms :as types]))
(rf/reg-event-fx
:wallet-connect/init
@@ -22,12 +23,7 @@
(fn [{:keys [db]} [web3-wallet]]
{:db (assoc db :wallet-connect/web3-wallet web3-wallet)
:fx [[:dispatch [:wallet-connect/register-event-listeners]]
[:effects.wallet-connect/fetch-pairings
{:web3-wallet web3-wallet
:on-fail #(log/error "Failed to get dApp pairings" {:error %})
:on-success (fn [data]
(rf/dispatch [:wallet-connect/set-pairings
(js->clj data :keywordize-keys true)]))}]]}))
[:dispatch [:wallet-connect/fetch-persisted-sessions]]]}))
(rf/reg-event-fx
:wallet-connect/register-event-listeners
@@ -40,7 +36,11 @@
[:effects.wallet-connect/register-event-listener
[web3-wallet
constants/wallet-connect-session-request-event
#(rf/dispatch [:wallet-connect/on-session-request %])]]]})))
#(rf/dispatch [:wallet-connect/on-session-request %])]]
[:effects.wallet-connect/register-event-listener
[web3-wallet
constants/wallet-connect-session-delete-event
#(rf/dispatch [:wallet-connect/on-session-delete %])]]]})))
(rf/reg-event-fx
:wallet-connect/on-init-fail
@@ -54,20 +54,24 @@
(fn [{:keys [db]} [proposal]]
(log/info "Received Wallet Connect session proposal: " {:id (:id proposal)})
(let [accounts (get-in db [:wallet :accounts])
without-watched (remove :watch-only? (vals accounts))
current-viewing-address (get-in db [:wallet :current-viewing-account-address])
available-accounts (filter #(and (:operable? %)
(not (:watch-only? %)))
(vals accounts))
networks (wallet-connect-core/get-networks-by-mode db)
session-networks (wallet-connect-core/proposal-networks-intersection proposal
networks)
required-networks-supported? (wallet-connect-core/required-networks-supported? proposal
networks)]
(if required-networks-supported?
(if (and (not-empty session-networks) required-networks-supported?)
{:db (update db
:wallet-connect/current-proposal assoc
:request proposal
:session-networks session-networks
:address (-> without-watched
first
:address))
:address (or current-viewing-address
(-> available-accounts
first
:address)))
:fx [[:dispatch
[:open-modal :screen/wallet.wallet-connect-session-proposal]]]}
{:fx [[:dispatch
@@ -85,9 +89,16 @@
(rf/reg-event-fx
:wallet-connect/on-session-request
(fn [_ [event]]
(log/info "Received Wallet Connect session request: " event)
{:fx [[:dispatch [:wallet-connect/process-session-request event]]]}))
(fn [{:keys [db]} [event]]
(when (wallet-connect-core/event-should-be-handled? db event)
{:fx [[:dispatch [:wallet-connect/process-session-request event]]]})))
(rf/reg-event-fx
:wallet-connect/on-session-delete
(fn [{:keys [db]} [{:keys [topic] :as event}]]
(when (wallet-connect-core/event-should-be-handled? db event)
(log/info "Received Wallet Connect session delete: " event)
{:fx [[:dispatch [:wallet-connect/disconnect-session topic]]]})))
(rf/reg-event-fx
:wallet-connect/reset-current-session-proposal
@@ -104,28 +115,18 @@
(fn [{:keys [db]}]
{:db (dissoc db :wallet-connect/current-request)}))
(rf/reg-event-fx
:wallet-connect/set-pairings
(fn [{:keys [db]} [pairings]]
{:db (assoc db :wallet-connect/pairings pairings)}))
(rf/reg-event-fx
:wallet-connect/remove-pairing-by-topic
(fn [{:keys [db]} [topic]]
{:db (update db
:wallet-connect/pairings
(fn [pairings]
(remove #(= (:topic %) topic) pairings)))}))
(rf/reg-event-fx
:wallet-connect/disconnect-dapp
(fn [{:keys [db]} [{:keys [topic on-success on-fail]}]]
(fn [{:keys [db]} [{:keys [pairing-topic on-success on-fail]}]]
(let [web3-wallet (get db :wallet-connect/web3-wallet)]
{:fx [[:effects.wallet-connect/disconnect
{:web3-wallet web3-wallet
:topic topic
:topic pairing-topic
:on-fail on-fail
:on-success on-success}]]})))
:on-success (fn []
(rf/dispatch [:wallet-connect/disconnect-session pairing-topic])
(when on-success
(on-success)))}]]})))
(rf/reg-event-fx
:wallet-connect/pair
@@ -137,15 +138,6 @@
:on-fail #(log/error "Failed to pair with dApp" {:error %})
:on-success #(log/info "dApp paired successfully")}]]})))
(rf/reg-event-fx
:wallet-connect/fetch-active-sessions
(fn [{:keys [db]}]
(let [web3-wallet (get db :wallet-connect/web3-wallet)]
{:fx [[:effects.wallet-connect/fetch-active-sessions
{:web3-wallet web3-wallet
:on-fail #(log/error "Failed to get active sessions" {:error %})
:on-success #(log/info "Got active sessions successfully" {:sessions %})}]]})))
(rf/reg-event-fx
:wallet-connect/approve-session
(fn [{:keys [db]}]
@@ -204,10 +196,55 @@
{:version version}))}]]]}
{:fx [[:dispatch [:wallet-connect/pair scanned-text]]]}))))
;; We first load sessions from database, then we initiate a call to Wallet Connect SDK and
;; then replace the list we have stored in the database with the one that came from the SDK.
;; In addition to that, we also update the backend state by marking sessions that are not
;; active anymore by calling `:wallet-connect/disconnect-session`.
(rf/reg-event-fx
:wallet-connect/fetch-active-sessions-success
(fn [{:keys [db now]} [sessions]]
(let [persisted-sessions (:wallet-connect/sessions db)
sessions (->> (js->clj sessions :keywordize-keys true)
vals
(map wallet-connect-core/sdk-session->db-session))
expired-sessions (remove
(fn [{:keys [expiry]}]
(> expiry (/ now 1000)))
persisted-sessions)]
{:fx (mapv (fn [{:keys [pairingTopic]}]
[:wallet-connect/disconnect-session pairingTopic])
expired-sessions)
:db (assoc db :wallet-connect/sessions sessions)})))
(rf/reg-event-fx
:wallet-connect/fetch-active-sessions
(fn [{:keys [db]}]
(let [web3-wallet (get db :wallet-connect/web3-wallet)]
{:fx [[:effects.wallet-connect/fetch-active-sessions
{:web3-wallet web3-wallet
:on-fail #(log/error "Failed to get active sessions" {:error %})
:on-success #(rf/dispatch [:wallet-connect/fetch-active-sessions-success %])}]]})))
(rf/reg-event-fx
:wallet-connect/fetch-persisted-sessions-success
(fn [{:keys [db]} [sessions]]
{:db (assoc db :wallet-connect/persisted-sessions sessions)}))
(let [sessions' (mapv (fn [{:keys [sessionJson] :as session}]
(assoc session
:accounts
(-> sessionJson
types/json->clj
:namespaces
:eip155
:accounts)))
sessions)]
{:fx [[:dispatch [:wallet-connect/fetch-active-sessions]]]
:db (assoc db :wallet-connect/sessions sessions')})))
(rf/reg-event-fx
:wallet-connect/fetch-persisted-sessions-fail
(fn [_ [error]]
(log/info "Wallet Connect fetch persisted sessions failed" error)
{:fx [[:dispatch [:wallet-connect/fetch-active-sessions]]]}))
(rf/reg-event-fx
:wallet-connect/fetch-persisted-sessions
@@ -218,7 +255,7 @@
;; 0 means, return everything
:params [0]
:on-success [:wallet-connect/fetch-persisted-sessions-success]
:on-error #(log/info "Wallet Connect fetch persisted sessions failed" %)}]]]}))
:on-error [:wallet-connect/fetch-persisted-sessions-fail]}]]]}))
(rf/reg-event-fx
:wallet-connect/persist-session
@@ -226,5 +263,22 @@
{:fx [[:json-rpc/call
[{:method "wallet_addWalletConnectSession"
:params [(js/JSON.stringify session-info)]
:on-success #(log/info "Wallet Connect session persisted")
:on-success (fn []
(log/info "Wallet Connect session persisted")
(rf/dispatch [:wallet-connect/fetch-persisted-sessions]))
:on-error #(log/info "Wallet Connect session persistence failed" %)}]]]}))
(rf/reg-event-fx
:wallet-connect/disconnect-session
(fn [{:keys [db]} [pairing-topic]]
{:db (update db
:wallet-connect/sessions
(fn [sessions]
(->> sessions
(remove #(= (:pairingTopic %) pairing-topic))
(into []))))
:fx [[:json-rpc/call
[{:method "wallet_disconnectWalletConnectSession"
:params [pairing-topic]
:on-success #(log/info "Wallet Connect session disconnected")
:on-error #(log/info "Wallet Connect session persistence failed" %)}]]]}))
@@ -0,0 +1,31 @@
(ns status-im.contexts.wallet.wallet-connect.modals.common.fees-data-item.view
(:require [quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme]
[status-im.contexts.wallet.wallet-connect.modals.common.style :as style]
[utils.i18n :as i18n]))
(defn- fees-subtitle
[{:keys [text error?]}]
(let [theme (quo.theme/use-theme)]
[quo/text
{:weight :medium
:size :paragraph-2
:style {:color (if error?
(colors/resolve-color :danger theme)
(colors/theme-colors colors/neutral-100
colors/white
theme))}}
text]))
(defn view
[{:keys [fees fees-error]}]
[quo/data-item
{:size :small
:status :default
:card? false
:container-style style/data-item
:title (i18n/label :t/max-fees)
:custom-subtitle (fn [] [fees-subtitle
{:text (or fees (i18n/label :t/no-fees))
:error? (= fees-error :not-enough-assets-to-pay-gas-fees)}])}])
@@ -13,7 +13,7 @@
(rf/dispatch [:wallet-connect/respond-current-session password]))
(defn view
[{:keys [warning-label slide-button-text disabed?]} & children]
[{:keys [warning-label slide-button-text disabled?]} & children]
(let [{:keys [customization-color]} (rf/sub [:wallet-connect/current-request-account-details])]
[rn/view {:style style/content-container}
(into [rn/view
@@ -23,7 +23,7 @@
[standard-authentication/slide-button
{:size :size-48
:track-text slide-button-text
:disabled? disabed?
:disabled? disabled?
:customization-color customization-color
:on-auth-success on-auth-success
:auth-button-label (i18n/label :t/confirm)}]]
@@ -10,12 +10,12 @@
[quo/text
{:size :heading-1
:weight :semi-bold}
(let [{:keys [name icons]} (:peerMetadata dapp)]
(let [{:keys [name iconUrl]} dapp]
[rn/view {:style style/header-dapp-name}
[quo/summary-tag
{:type :dapp
:label name
:image-source (first icons)}]])
:image-source iconUrl}]])
(str " " label " ")
(let [{:keys [emoji customization-color name]} account]
[rn/view {:style style/header-account-name}
@@ -1,8 +1,11 @@
(ns status-im.contexts.wallet.wallet-connect.modals.send-transaction.view
(:require [quo.core :as quo]
[quo.theme]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.contexts.wallet.wallet-connect.modals.common.data-block.view :as data-block]
[status-im.contexts.wallet.wallet-connect.modals.common.fees-data-item.view :as
fees-data-item]
[status-im.contexts.wallet.wallet-connect.modals.common.footer.view :as footer]
[status-im.contexts.wallet.wallet-connect.modals.common.header.view :as header]
[status-im.contexts.wallet.wallet-connect.modals.common.page-nav.view :as page-nav]
@@ -40,7 +43,7 @@
:not-enough-assets
:t/not-enough-assets))}])
[footer/view
{:warning-label (i18n/label :t/wallet-connect-send-transaction-warning)
{:warning-label (i18n/label :t/wallet-connect-sign-warning)
:slide-button-text (i18n/label :t/slide-to-send)
:disabled? error-state}
[quo/data-item
@@ -51,11 +54,7 @@
:subtitle-type :network
:network-image (:source network)
:subtitle (:full-name network)}]
[quo/data-item
{:size :small
:status :default
:card? false
:container-style style/data-item
:title (i18n/label :t/max-fees)
:subtitle (or max-fees-fiat-formatted (i18n/label :t/no-fees))}]]]]))
[fees-data-item/view
{:fees max-fees-fiat-formatted
:fees-error error-state}]]]]))
@@ -3,6 +3,8 @@
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.contexts.wallet.wallet-connect.modals.common.data-block.view :as data-block]
[status-im.contexts.wallet.wallet-connect.modals.common.fees-data-item.view :as
fees-data-item]
[status-im.contexts.wallet.wallet-connect.modals.common.footer.view :as footer]
[status-im.contexts.wallet.wallet-connect.modals.common.header.view :as header]
[status-im.contexts.wallet.wallet-connect.modals.common.page-nav.view :as page-nav]
@@ -28,13 +30,7 @@
:account account}]
[data-block/view]]
[footer/view
{:warning-label (i18n/label :t/wallet-connect-sign-message-warning)
{:warning-label (i18n/label :t/wallet-connect-sign-warning)
:slide-button-text (i18n/label :t/slide-to-sign)}
[quo/data-item
{:size :small
:status :default
:card? false
:container-style style/data-item
:title (i18n/label :t/max-fees)
:subtitle (i18n/label :t/no-fees)}]]]]))
[fees-data-item/view]]]]))
@@ -3,6 +3,8 @@
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.contexts.wallet.wallet-connect.modals.common.data-block.view :as data-block]
[status-im.contexts.wallet.wallet-connect.modals.common.fees-data-item.view :as
fees-data-item]
[status-im.contexts.wallet.wallet-connect.modals.common.footer.view :as footer]
[status-im.contexts.wallet.wallet-connect.modals.common.header.view :as header]
[status-im.contexts.wallet.wallet-connect.modals.common.page-nav.view :as page-nav]
@@ -40,7 +42,7 @@
:not-enough-assets
:t/not-enough-assets))}])
[footer/view
{:warning-label (i18n/label :t/wallet-connect-sign-transaction-warning)
{:warning-label (i18n/label :t/wallet-connect-sign-warning)
:slide-button-text (i18n/label :t/slide-to-sign)
:disabled? error-state}
[quo/data-item
@@ -51,11 +53,7 @@
:subtitle-type :network
:network-image (:source network)
:subtitle (:full-name network)}]
[quo/data-item
{:size :small
:status :default
:card? false
:container-style style/data-item
:title (i18n/label :t/max-fees)
:subtitle (or max-fees-fiat-formatted (i18n/label :t/no-fees))}]]]]))
[fees-data-item/view
{:fees max-fees-fiat-formatted
:fees-error error-state}]]]]))
@@ -1,18 +1,32 @@
(ns status-im.contexts.wallet.wallet-connect.processing-events
(:require [clojure.string :as string]
(:require [cljs-bean.core :as bean]
[clojure.string :as string]
[native-module.core :as native-module]
[re-frame.core :as rf]
[status-im.constants :as constants]
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
[status-im.contexts.wallet.wallet-connect.transactions :as transactions]
[taoensso.timbre :as log]
[utils.transforms :as transforms]))
(rf/reg-event-fx
:wallet-connect/process-session-request
(fn [{:keys [db]} [event]]
(let [method (wallet-connect-core/get-request-method event)
:wallet-connect/show-request-modal
(fn [{:keys [db]}]
(let [event (get-in db [:wallet-connect/current-request :event])
method (wallet-connect-core/get-request-method event)
screen (wallet-connect-core/method-to-screen method)]
(if screen
{:fx [[:dispatch [:open-modal screen]]]}
(log/error "Didn't find screen for Wallet Connect method"
{:method method
:event :wallet-connect/process-session-request})))))
(rf/reg-event-fx
:wallet-connect/process-session-request
(fn [{:keys [db]} [event]]
(let [method (wallet-connect-core/get-request-method event)
existing-event (get-in db [:wallet-connect/current-request :event])]
;; NOTE: make sure we don't show two requests at the same time
(when-not existing-event
{:db (assoc-in db [:wallet-connect/current-request :event] event)
:fx [(condp = method
constants/wallet-connect-eth-send-transaction-method
@@ -31,12 +45,7 @@
[:dispatch [:wallet-connect/process-sign-typed]]
constants/wallet-connect-personal-sign-method
[:dispatch [:wallet-connect/process-personal-sign]])
[:dispatch [:open-modal screen]]]}
(log/error "Didn't find screen for Wallet Connect method"
{:method method
:event :wallet-connect/process-session-request})))))
[:dispatch [:wallet-connect/process-personal-sign]])]}))))
(rf/reg-event-fx
:wallet-connect/process-personal-sign
@@ -48,7 +57,8 @@
assoc
:address (string/lower-case address)
:raw-data raw-data
:display-data (or parsed-data raw-data))})))
:display-data (or parsed-data raw-data))
:fx [[:dispatch [:wallet-connect/show-request-modal]]]})))
(rf/reg-event-fx
:wallet-connect/process-eth-sign
@@ -60,44 +70,53 @@
assoc
:address (string/lower-case address)
:raw-data raw-data
:display-data (or parsed-data raw-data))})))
:display-data (or parsed-data raw-data))
:fx [[:dispatch [:wallet-connect/show-request-modal]]]})))
(rf/reg-event-fx
:wallet-connect/prepare-transaction-success
(fn [{:keys [db]} [prepared-tx chain-id]]
(let [{:keys [tx-args]} prepared-tx
tx (bean/->clj tx-args)
address (-> tx :from string/lower-case)
display-data (transactions/beautify-transaction tx)]
{:db (update-in db
[:wallet-connect/current-request]
assoc
:address address
:raw-data prepared-tx
:transaction tx
:chain-id chain-id
:display-data display-data)
:fx [[:dispatch [:wallet-connect/show-request-modal]]]})))
(rf/reg-event-fx
:wallet-connect/process-eth-send-transaction
(fn [{:keys [db]}]
(let [event (wallet-connect-core/get-db-current-request-event db)
display-data (-> event
clj->js
(js/JSON.stringify nil 2))
{:keys [from] :as tx} (-> event wallet-connect-core/get-request-params first)
chain-id (-> event
(get-in [:params :chainId])
wallet-connect-core/eip155->chain-id)]
{:db (update-in db
[:wallet-connect/current-request]
assoc
:address (string/lower-case from)
:raw-data tx
:chain-id chain-id
:display-data display-data)})))
(let [event (wallet-connect-core/get-db-current-request-event db)
tx (-> event wallet-connect-core/get-request-params first)
chain-id (-> event
(get-in [:params :chainId])
wallet-connect-core/eip155->chain-id)]
{:fx [[:effects.wallet-connect/prepare-transaction
{:tx tx
:chain-id chain-id
:on-success #(rf/dispatch [:wallet-connect/prepare-transaction-success % chain-id])
:on-error #(rf/dispatch [:wallet-connect/on-processing-error %])}]]})))
(rf/reg-event-fx
:wallet-connect/process-eth-sign-transaction
(fn [{:keys [db]}]
(let [event (wallet-connect-core/get-db-current-request-event db)
display-data (.stringify js/JSON (clj->js event) nil 2)
{:keys [from] :as tx} (-> event wallet-connect-core/get-request-params first)
chain-id (-> event
(get-in [:params :chainId])
wallet-connect-core/eip155->chain-id)]
{:db (update-in db
[:wallet-connect/current-request]
assoc
:address (string/lower-case from)
:raw-data tx
:chain-id chain-id
:display-data display-data)})))
(let [event (wallet-connect-core/get-db-current-request-event db)
tx (-> event wallet-connect-core/get-request-params first)
chain-id (-> event
(get-in [:params :chainId])
wallet-connect-core/eip155->chain-id)]
{:fx [[:effects.wallet-connect/prepare-transaction
{:tx tx
:chain-id chain-id
:on-success #(rf/dispatch [:wallet-connect/prepare-transaction-success % chain-id])
:on-error #(rf/dispatch [:wallet-connect/on-processing-error %])}]]})))
(rf/reg-event-fx
:wallet-connect/process-sign-typed
@@ -108,11 +127,31 @@
(transforms/js-dissoc :types :primaryType)
(transforms/js-stringify 2))
(catch js/Error _ nil))]
;; TODO: decide if we should proceed if the typed-data is invalid JSON or fail ahead of time
(when (nil? parsed-data) (log/error "Invalid typed data"))
{:db (update-in db
[:wallet-connect/current-request]
assoc
:address (string/lower-case address)
:display-data (or parsed-data raw-data)
:raw-data raw-data)})))
(if (nil? parsed-data)
{:fx [[:dispatch
[:wallet-connect/on-processing-error
(ex-info "Failed to parse JSON typed data" {:data raw-data})]]]}
{:db (update-in db
[:wallet-connect/current-request]
assoc
:address (string/lower-case address)
:display-data (or parsed-data raw-data)
:raw-data raw-data)
:fx [[:dispatch [:wallet-connect/show-request-modal]]]}))))
;; TODO: we should reject a request if processing fails
(rf/reg-event-fx
:wallet-connect/on-processing-error
(fn [{:keys [db]} [error]]
(let [{:keys [address event]} (get db :wallet-connect/current-request)
method (wallet-connect-core/get-request-method event)
screen (wallet-connect-core/method-to-screen method)]
(log/error "Failed to process Wallet Connect request"
{:error error
:address address
:method method
:wallet-connect-event event
:event :wallet-connect/on-processing-error})
{:fx [[:dispatch [:dismiss-modal screen]]
[:dispatch [:wallet-connect/reset-current-request]]]})))
@@ -58,34 +58,38 @@
(rf/reg-event-fx
:wallet-connect/respond-send-transaction-data
(fn [{:keys [db]} [password]]
(let [{:keys [chain-id raw-data address]} (get db :wallet-connect/current-request)]
(let [{:keys [chain-id raw-data address]} (get db :wallet-connect/current-request)
{:keys [tx-hash tx-args]} raw-data]
{:fx [[:effects.wallet-connect/send-transaction
{:password password
:address address
:chain-id chain-id
:tx raw-data
:tx-hash tx-hash
:tx-args tx-args
:on-error #(rf/dispatch [:wallet-connect/on-sign-error %])
:on-success #(rf/dispatch [:wallet-connect/send-response {:result %}])}]]})))
(rf/reg-event-fx
:wallet-connect/respond-sign-transaction-data
(fn [{:keys [db]} [password]]
(let [{:keys [chain-id raw-data address]} (get db :wallet-connect/current-request)]
(let [{:keys [chain-id raw-data address]} (get db :wallet-connect/current-request)
{:keys [tx-hash tx-args]} raw-data]
{:fx [[:effects.wallet-connect/sign-transaction
{:password password
:address address
:chain-id chain-id
:tx raw-data
:tx-hash tx-hash
:tx-params tx-args
:on-error #(rf/dispatch [:wallet-connect/on-sign-error %])
:on-success #(rf/dispatch [:wallet-connect/send-response {:result %}])}]]})))
;; TODO: should reject if "signing" fails
(rf/reg-event-fx
:wallet-connect/on-sign-error
(fn [{:keys [db]} [error]]
(let [event (get-in db [:wallet-connect/current-request :event])
{:keys [raw-data address]} (get db :wallet-connect/current-request)
method (wallet-connect-core/get-request-method event)
screen (wallet-connect-core/method-to-screen method)]
(let [{:keys [raw-data address event]} (get db :wallet-connect/current-request)
method (wallet-connect-core/get-request-method event)
screen (wallet-connect-core/method-to-screen method)]
(log/error "Failed to sign Wallet Connect request"
{:error error
:address address
@@ -132,7 +136,7 @@
:proposal current-proposal
:on-success #(log/info "Wallet Connect session proposal rejected")
:on-error #(log/error "Wallet Connect unable to reject session proposal")}]
[:dispatch [:wallet-connect/reset-current-session]]]})))
[:dispatch [:wallet-connect/reset-current-session-proposal]]]})))
;; NOTE: Currently we only reject a session if the user rejected it
;; But this needs to be solidified to ensure other cases:
@@ -59,3 +59,8 @@
password
chain-id
legacy?))
(defn wallet-get-suggested-fees
[chain-id]
(-> (call-rpc "wallet_getSuggestedFees" chain-id)
(promesa/then transforms/js->clj)))
@@ -6,12 +6,13 @@
:padding-top 12})
(def approval-note-container
{:margin-horizontal 20
:padding 12
:border-radius 16
:border-width 1
:border-color colors/neutral-10
:background-color colors/neutral-2_5})
{:margin-horizontal 20
:padding-horizontal 16
:padding-vertical 12
:border-radius 16
:border-width 1
:border-color colors/neutral-10
:background-color colors/neutral-2_5})
(def approval-note-title
{:color colors/neutral-50
@@ -20,10 +21,8 @@
(def approval-note-li
{:flex 1
:flex-direction :row
:align-items :center})
(def approval-li-spacer
{:width 8})
:align-items :center
:gap 8})
(def account-switcher-title
{:padding-horizontal 20})
@@ -31,3 +30,6 @@
(def account-switcher-list
{:margin-top 8
:padding-horizontal 8})
(def footer-buttons-container
{:padding-horizontal 0})
@@ -33,16 +33,21 @@
labels [(i18n/label :t/check-your-account-balance-and-activity)
(i18n/label :t/request-txns-and-message-signing)]]
[rn/view {:style style/approval-note-container}
[quo/text {:style style/approval-note-title}
[quo/text
{:style style/approval-note-title
:weight :regular
:size :paragraph-2}
(i18n/label :t/dapp-will-be-able-to {:dapp-name dapp-name})]
(map-indexed
(fn [idx label]
^{:key (str idx label)}
[rn/view {:style style/approval-note-li}
[quo/icon :i/bullet
{:color colors/neutral-50}]
[rn/view {:style style/approval-li-spacer}]
[quo/text label]])
{:color colors/neutral-40}]
[quo/text
{:weight :regular
:size :paragraph-2}
label]])
labels)]))
(defn- format-network-name
@@ -57,16 +62,14 @@
(defn- accounts-list
[]
(let [accounts (rf/sub [:wallet/accounts-without-watched-accounts])
(let [accounts (rf/sub [:wallet/operable-accounts-without-watched-accounts])
selected-address (rf/sub [:wallet-connect/current-proposal-address])]
[rn/view {:style style/account-switcher-list}
(for [account accounts]
^{:key (-> account :address str)}
(for [{:keys [address] :as account} accounts]
^{:key (str address)}
[quo/account-item
{:type :default
:state (if (and selected-address
(= (account :address)
selected-address))
:state (if (= address selected-address)
:selected
:default)
:account-props account
@@ -101,12 +104,10 @@
(map format-network-name)
(string/join ", "))
network-images (mapv :source session-networks)
data-item-common-props {:blur? false
:description :default
:card? false
:label :preview
:status :default
:size :large}
data-item-common-props {:blur? false
:card? false
:status :default
:size :large}
account-data-item-props (assoc data-item-common-props
:right-content {:type :accounts
:size :size-32
@@ -116,9 +117,7 @@
:on-press show-account-switcher-bottom-sheet
:title (i18n/label :t/account-title)
:subtitle name
:icon-right? true
:right-icon :i/chevron-right
:icon-color colors/neutral-10)
:right-icon :i/chevron-right)
networks-data-item-props (assoc data-item-common-props
:right-content {:type :network
:data network-images}
@@ -136,18 +135,21 @@
[]
(let [customization-color (rf/sub [:profile/customization-color])]
[quo/bottom-actions
{:actions :two-actions
:button-two-label (i18n/label :t/decline)
:button-two-props {:type :grey
:accessibility-label :wc-deny-connection
:on-press #(do (rf/dispatch [:navigate-back])
(rf/dispatch
[:wallet-connect/reject-session-proposal]))}
:button-one-label (i18n/label :t/connect)
:button-one-props {:customization-color customization-color
:type :primary
:accessibility-label :wc-connect
:on-press #(rf/dispatch [:wallet-connect/approve-session])}}]))
{:actions :two-actions
:buttons-container-style style/footer-buttons-container
:button-two-label (i18n/label :t/decline)
:button-two-props {:type :grey
:accessibility-label :wc-deny-connection
:on-press (fn []
(rf/dispatch [:navigate-back])
(rf/dispatch
[:wallet-connect/reject-session-proposal]))}
:button-one-label (i18n/label :t/connect)
:button-one-props {:customization-color customization-color
:type :primary
:accessibility-label :wc-connect
:on-press #(rf/dispatch
[:wallet-connect/approve-session])}}]))
(defn- header
[]
@@ -1,10 +1,24 @@
(ns status-im.contexts.wallet.wallet-connect.transactions
(:require [cljs-bean.core :as bean]
[clojure.string :as string]
[native-module.core :as native-module]
[promesa.core :as promesa]
[status-im.constants :as constants]
[status-im.contexts.wallet.wallet-connect.core :as core]
[status-im.contexts.wallet.wallet-connect.rpc :as rpc]
[utils.money :as money]
[utils.transforms :as transforms]))
(defn transaction-request?
[event]
(->> (core/get-request-method event)
(contains? #{constants/wallet-connect-eth-send-transaction-method
constants/wallet-connect-eth-sign-transaction-method})))
;; NOTE: Currently we don't allow the user to configure the tx priority as we don't
;; show the estimated time, but when we implement it, we should allow to change it
(def ^:constant default-tx-priority :medium)
(defn- strip-hex-prefix
"Strips the extra 0 in hex value if present"
[hex-value]
@@ -15,12 +29,12 @@
(defn- format-tx-hex-values
"Due to how status-go expects hex values, we should remove the extra 0s in transaction hex values e.g. 0x0f -> 0xf"
[tx]
[tx f]
(let [tx-keys [:gasLimit :gas :gasPrice :nonce :value :maxFeePerGas :maxPriorityFeePerGas]]
(reduce (fn [acc tx-key]
(if (and (contains? tx tx-key)
(not (nil? (get tx tx-key))))
(update acc tx-key strip-hex-prefix)
(update acc tx-key f)
acc))
tx
tx-keys)))
@@ -29,26 +43,100 @@
"Formats the transaction and transforms it into a stringified JS object, ready to be passed to an RPC call."
[tx]
(-> tx
format-tx-hex-values
;; NOTE: removing `:nonce` to compute it when building the transaction on status-go
(dissoc :nonce)
(format-tx-hex-values strip-hex-prefix)
bean/->js
(transforms/js-stringify 0)))
(defn beautify-transaction
[tx]
(let [hex->number #(-> % (subs 2) native-module/hex-to-number)]
(-> tx
(format-tx-hex-values hex->number)
clj->js
(js/JSON.stringify nil 2))))
(defn- gwei->hex
[gwei]
(->> gwei
money/gwei->wei
native-module/number-to-hex
(str "0x")))
(defn- get-max-fee-per-gas-key
"Mapping transaction priority (which determines how quickly a tx is processed)
to the `suggested-routes` key that should be used for `:maxPriorityFeePerGas`.
Returns `:high` | `:medium` | `:low`"
[tx-priority]
(get {:high :maxFeePerGasHigh
:medium :maxFeePerGasMedium
:low :maxFeePerGasLow}
tx-priority))
(defn- dynamic-fee-tx?
"Checks if a transaction has dynamic fees (EIP1559)"
[tx]
(every? tx [:maxFeePerGas :maxPriorityFeePerGas]))
(defn- tx->eip1559-tx
"Adds `:maxFeePerGas` and `:maxPriorityFeePerGas` for dynamic fee support (EIP1559) and
removes `:gasPrice`, if the chain supports EIP1559 and the transaction doesn't already
have dynamic fees."
[tx suggested-fees tx-priority]
(if (and (:eip1559Enabled suggested-fees)
(not (dynamic-fee-tx? tx)))
(let [max-fee-per-gas-key (get-max-fee-per-gas-key tx-priority)
max-fee-per-gas (-> suggested-fees max-fee-per-gas-key gwei->hex)
max-priority-fee-per-gas (-> suggested-fees :maxPriorityFeePerGas gwei->hex)]
(-> tx
(assoc
:maxFeePerGas max-fee-per-gas
:maxPriorityFeePerGas max-priority-fee-per-gas)
;; NOTE: `:gasPrice` is used only for legacy Tx, so we discard it in favor of dynamic fees
(dissoc :gasPrice)))
tx))
(defn- prepare-transaction-fees
"Makes sure the transaction has the correct gas and fees properties"
[tx tx-priority suggested-fees]
(-> (assoc tx
;; NOTE: `gasLimit` is ignored on status-go when building a transaction
;; (`wallet_buildTransaction`), so we're setting it as the `gas` property
:gas
(or (:gasLimit tx)
(:gas tx)))
(dissoc :gasLimit)
(tx->eip1559-tx suggested-fees tx-priority)))
(defn prepare-transaction
"Formats and builds the incoming transaction, adding the missing properties and returning the final
transaction, along with the transaction hash and the suggested fees"
[tx chain-id tx-priority]
(promesa/let [suggested-fees (rpc/wallet-get-suggested-fees chain-id)
{:keys [tx-args message-to-sign]} (->>
(prepare-transaction-fees tx
tx-priority
suggested-fees)
prepare-transaction-for-rpc
(rpc/wallet-build-transaction chain-id))]
{:tx-args tx-args
:tx-hash message-to-sign
:suggested-fees suggested-fees}))
(defn sign-transaction
[password address tx chain-id]
[password address tx-hash tx-args chain-id]
(promesa/let
[formatted-tx (prepare-transaction-for-rpc tx)
{:keys [message-to-sign tx-args]} (rpc/wallet-build-transaction chain-id formatted-tx)
signature (rpc/wallet-sign-message message-to-sign address password)
raw-tx (rpc/wallet-build-raw-transaction chain-id tx-args signature)]
[signature (rpc/wallet-sign-message tx-hash address password)
raw-tx (rpc/wallet-build-raw-transaction chain-id tx-args signature)]
raw-tx))
(defn send-transaction
[password address tx chain-id]
[password address tx-hash tx-args chain-id]
(promesa/let
[formatted-tx (prepare-transaction-for-rpc tx)
{:keys [message-to-sign tx-args]} (rpc/wallet-build-transaction chain-id formatted-tx)
signature (rpc/wallet-sign-message message-to-sign address password)
tx (rpc/wallet-send-transaction-with-signature chain-id
tx-args
signature)]
[signature (rpc/wallet-sign-message tx-hash address password)
tx (rpc/wallet-send-transaction-with-signature chain-id
tx-args
signature)]
tx))
@@ -11,14 +11,14 @@
(defn timestamp-expired?
[expiry-timestamp]
(> (current-timestamp) expiry-timestamp))
(when expiry-timestamp
(> (current-timestamp) expiry-timestamp)))
(defn valid-wc-uri?
[parsed-uri]
(let [{:keys [topic version expiryTimestamp]} parsed-uri]
(let [{:keys [topic version]} parsed-uri]
(and (seq topic)
(number? version)
(number? expiryTimestamp))))
(number? version))))
(defn valid-uri?
"Check if the uri is in the wallet-connect format.
+7 -3
View File
@@ -2,6 +2,7 @@
(:require
[legacy.status-im.ui.screens.screens :as old-screens]
[quo.foundations.colors :as colors]
[re-frame.core :as rf]
[status-im.common.emoji-picker.view :as emoji-picker]
[status-im.common.enter-seed-phrase.view :as enter-seed-phrase]
[status-im.common.lightbox.view :as lightbox]
@@ -539,15 +540,18 @@
;; Wallet Connect
{:name :screen/wallet-connect.sign-message
:options {:sheet? true}
:options {:sheet? true
:on-dismiss-sheet #(rf/dispatch [:wallet-connect/reject-session-request])}
:component wallet-connect-sign-message/view}
{:name :screen/wallet-connect.sign-transaction
:options {:sheet? true}
:options {:sheet? true
:on-dismiss-sheet #(rf/dispatch [:wallet-connect/reject-session-request])}
:component wallet-connect-sign-transaction/view}
{:name :screen/wallet-connect.send-transaction
:options {:sheet? true}
:options {:sheet? true
:on-dismiss-sheet #(rf/dispatch [:wallet-connect/reject-session-request])}
:component wallet-connect-send-transaction/view}
{:name :screen/wallet.connected-dapps
+17 -16
View File
@@ -57,22 +57,22 @@
[screen-key]
(reagent.core/reactify-component
(fn []
(let [screen-details (get (if js/goog.DEBUG
(get-screens)
screens)
(keyword screen-key))
qualified-screen-details (get (if js/goog.DEBUG
(get-screens)
screens)
(keyword "screen" screen-key))
{:keys [component options]} (or qualified-screen-details screen-details)
(let [screen-details (get (if js/goog.DEBUG
(get-screens)
screens)
(keyword screen-key))
qualified-screen-details (get (if js/goog.DEBUG
(get-screens)
screens)
(keyword "screen" screen-key))
{:keys [component options]} (or qualified-screen-details screen-details)
{:keys [insets sheet? theme
skip-background?]} options
alert-banners-top-margin (rf/sub [:alert-banners/top-margin])
background-color (or (get-in options [:layout :backgroundColor])
(when sheet? :transparent))
app-theme (rf/sub [:theme])
theme (or theme app-theme)]
skip-background? on-dismiss-sheet]} options
alert-banners-top-margin (rf/sub [:alert-banners/top-margin])
background-color (or (get-in options [:layout :backgroundColor])
(when sheet? :transparent))
app-theme (rf/sub [:theme])
theme (or theme app-theme)]
^{:key (str "root" screen-key @reloader/cnt)}
[quo.theme/provider theme
[rn/view
@@ -83,7 +83,8 @@
:alert-banners-top-margin alert-banners-top-margin))}
[inactive]
(if sheet?
[bottom-sheet-screen/view {:content component :skip-background? skip-background?}]
[bottom-sheet-screen/view
{:content component :skip-background? skip-background? :on-dismiss on-dismiss-sheet}]
[component])]
(when js/goog.DEBUG
[:<>
+21
View File
@@ -16,12 +16,33 @@
(fn [info [_ id]]
(get info id)))
;; Do not use this subscription directly in views. There is a significant risk
;; of re-rendering views too frequently because an active community can change
;; for numerous reasons.
(re-frame/reg-sub
:communities/community
:<- [:communities]
(fn [communities [_ id]]
(get communities id)))
(re-frame/reg-sub :communities/logo
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[community]]
(get-in community [:images :thumbnail :uri])))
(re-frame/reg-sub :communities/name
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [name]}]]
name))
(re-frame/reg-sub :communities/permissions
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [permissions]}]]
permissions))
(re-frame/reg-sub
:communities/community-color
(fn [[_ community-id]]
+1 -1
View File
@@ -169,7 +169,7 @@
(reg-root-key-sub :wallet-connect/web3-wallet :wallet-connect/web3-wallet)
(reg-root-key-sub :wallet-connect/current-proposal :wallet-connect/current-proposal)
(reg-root-key-sub :wallet-connect/current-request :wallet-connect/current-request)
(reg-root-key-sub :wallet-connect/pairings :wallet-connect/pairings)
(reg-root-key-sub :wallet-connect/sessions :wallet-connect/sessions)
;;biometrics
(reg-root-key-sub :biometrics :biometrics)
+75 -30
View File
@@ -1,5 +1,6 @@
(ns status-im.subs.wallet.activities
(:require
[clojure.string :as string]
[native-module.core :as native-module]
[quo.foundations.resources :as quo.resources]
[quo.foundations.resources]
@@ -16,49 +17,91 @@
:<- [:wallet]
:-> :activities)
(defn- activity-amount
[amount]
(-> amount
(defn- hex-wei->amount
[hex-str-amount]
(-> hex-str-amount
(utils.hex/normalize-hex)
(native-module/hex-to-number)
(money/wei->ether)
(money/with-precision precision)
(str)))
(defn- hex-string->number
[hex-str-amount]
(-> hex-str-amount
(utils.hex/normalize-hex)
(native-module/hex-to-number)
(str)))
(defn- normalize-nft-name
[token-id nft-name]
(if (and (some? token-id) (string/blank? nft-name))
"Unknown"
nft-name))
(defn- get-token-amount
[token amount]
(let [token-type (:token-type token)]
(if (#{constants/wallet-activity-token-type-erc-721
constants/wallet-activity-token-type-erc-1155}
token-type)
(hex-string->number amount)
(hex-wei->amount amount))))
(defn- process-send-activity
[{:keys [symbol-out chain-id-out amount-out]} activity chain-id->network-name]
(let [network-name (chain-id->network-name chain-id-out)]
(assoc activity
:transaction :send
:token symbol-out
:amount (activity-amount amount-out)
:network-name network-name
:network-logo (quo.resources/get-network network-name))))
[{:keys [symbol-out amount-out token-out]
:as data}]
(assoc data
:transaction :send
:token symbol-out
:amount (get-token-amount token-out amount-out)))
(defn- process-receive-activity
[{:keys [symbol-in amount-in chain-id-in]} activity chain-id->network-name]
(let [network-name (chain-id->network-name chain-id-in)]
(assoc activity
:transaction :receive
:token symbol-in
:amount (activity-amount amount-in)
:network-name network-name
:network-logo (quo.resources/get-network network-name))))
[{:keys [symbol-in amount-in token-in] :as data}]
(assoc data
:transaction :receive
:token symbol-in
:amount (get-token-amount token-in amount-in)))
;; WIP to add the mint activity.
;(defn- process-mint-activity
; [{:keys [token-in symbol-in amount-in chain-id-in nft-name] :as data}
; chain-id->network-name]
; (-> data
; (merge activity)
; (assoc :transaction :mint
; ;:token symbol-in
; ;:amount (activity-amount amount-in)
; :nft-name (normalize-nft-name token-id nft-name))))
(defn- process-activity-by-type
[chain-id->network-name
{:keys [activity-type activity-status timestamp sender recipient] :as data}]
(let [activity {:relative-date (datetime/timestamp->relative (* timestamp 1000))
:timestamp timestamp
:status (constants/wallet-activity-status->name activity-status)
:sender sender
:recipient recipient}]
{:keys [activity-type activity-status timestamp sender recipient token-in token-out
chain-id-in chain-id-out nft-name]
:as data}]
(let [network-name (chain-id->network-name (or chain-id-in chain-id-out))
token-id (some-> (or token-in token-out)
:token-id
hex-string->number)
activity (assoc data
:relative-date (datetime/timestamp->relative (* timestamp 1000))
:sender sender
:recipient recipient
:timestamp timestamp
:network-name network-name
:token-id token-id
:status (constants/wallet-activity-status->name activity-status)
:network-logo (quo.resources/get-network network-name)
:nft-name (normalize-nft-name token-id nft-name))]
(condp = activity-type
constants/wallet-activity-type-send
(process-send-activity data activity chain-id->network-name)
(process-send-activity activity)
constants/wallet-activity-type-receive
(process-receive-activity data activity chain-id->network-name)
(process-receive-activity activity)
;; WIP to add the mint activity. Constants/wallet-activity-type-mint
;; (process-mint-activity activity chain-id->network-name)
nil)))
@@ -69,9 +112,11 @@
:<- [:wallet/network-details]
(fn [[activities current-viewing-account-address network-details]]
(let [chain-id->network-name (update-vals (group-by :chain-id network-details)
(comp :network-name first))]
(->> current-viewing-account-address
(get activities)
(comp :network-name first))
address-activities (->> (get activities current-viewing-account-address)
(vals)
(sort :timestamp))]
(->> address-activities
(keep #(process-activity-by-type chain-id->network-name %))
(group-by (fn [{:keys [timestamp]}]
(datetime/timestamp->relative-short-date (* timestamp 1000))))
+20 -20
View File
@@ -24,26 +24,26 @@
(fn [db]
(-> db
(assoc-in [:wallet :activities]
{"acc1" [{:activity-type constants/wallet-activity-type-send
:amount-out "0x1"
:sender "acc1"
:recipient "acc2"
:timestamp 1588291200}
{:activity-type constants/wallet-activity-type-receive
:amount-in "0x1"
:sender "acc2"
:recipient "acc1"
:timestamp 1588377600}
{:activity-type constants/wallet-activity-type-send
:amount-out "0x1"
:sender "acc1"
:recipient "acc4"
:timestamp 1588464000}]
"acc3" [{:activity-type constants/wallet-activity-type-receive
:amount-in "0x1"
:sender "acc4"
:recipient "acc3"
:timestamp 1588464000}]})
{"acc1" {1 {:activity-type constants/wallet-activity-type-send
:amount-out "0x1"
:sender "acc1"
:recipient "acc2"
:timestamp 1588291200}
2 {:activity-type constants/wallet-activity-type-receive
:amount-in "0x1"
:sender "acc2"
:recipient "acc1"
:timestamp 1588377600}
3 {:activity-type constants/wallet-activity-type-send
:amount-out "0x1"
:sender "acc1"
:recipient "acc4"
:timestamp 1588464000}}
"acc3" {4 {:activity-type constants/wallet-activity-type-receive
:amount-in "0x1"
:sender "acc4"
:recipient "acc3"
:timestamp 1588464000}}})
(assoc-in [:wallet :current-viewing-account-address] "acc1"))))
(is
(match? [{:title "May 3, 2020"
+2 -1
View File
@@ -49,8 +49,9 @@
:<- [:wallet/all-activities]
:<- [:wallet/current-viewing-account-address]
(fn [[all-activities current-viewing-account-address]]
(let [address-activity (get all-activities current-viewing-account-address)]
(let [address-activity (vals (get all-activities current-viewing-account-address))]
(->> address-activity
(sort :timestamp)
(keep (fn [{:keys [activity-type recipient]}]
(when (= constants/wallet-activity-type-send activity-type)
recipient)))
+20 -20
View File
@@ -62,25 +62,25 @@
(fn [db]
(-> db
(assoc-in [:wallet :activities]
{"acc1" [{:activity-type constants/wallet-activity-type-send
:amount-out "0x1"
:sender "acc1"
:recipient "acc2"
:timestamp 1588291200}
{:activity-type constants/wallet-activity-type-receive
:amount-in "0x1"
:sender "acc2"
:recipient "acc1"
:timestamp 1588377600}
{:activity-type constants/wallet-activity-type-send
:amount-out "0x1"
:sender "acc1"
:recipient "acc4"
:timestamp 1588464000}]
"acc3" [{:activity-type constants/wallet-activity-type-receive
:amount-in "0x1"
:sender "acc4"
:recipient "acc3"
:timestamp 1588464000}]})
{"acc1" {1 {:activity-type constants/wallet-activity-type-send
:amount-out "0x1"
:sender "acc1"
:recipient "acc2"
:timestamp 1588291200}
2 {:activity-type constants/wallet-activity-type-receive
:amount-in "0x1"
:sender "acc2"
:recipient "acc1"
:timestamp 1588377600}
3 {:activity-type constants/wallet-activity-type-send
:amount-out "0x1"
:sender "acc1"
:recipient "acc4"
:timestamp 1588464000}}
"acc3" {4 {:activity-type constants/wallet-activity-type-receive
:amount-in "0x1"
:sender "acc4"
:recipient "acc3"
:timestamp 1588464000}}})
(assoc-in [:wallet :current-viewing-account-address] "acc1"))))
(is (match? ["acc2" "acc4"] (rf/sub [sub-name])))))
+97 -56
View File
@@ -1,8 +1,10 @@
(ns status-im.subs.wallet.wallet-connect
(:require [re-frame.core :as rf]
(:require [clojure.string :as string]
[re-frame.core :as rf]
[status-im.contexts.wallet.common.utils :as wallet-utils]
[status-im.contexts.wallet.common.utils.networks :as networks]
[status-im.contexts.wallet.wallet-connect.core :as wallet-connect-core]
[status-im.contexts.wallet.wallet-connect.transactions :as transactions]
[utils.money :as money]))
(rf/reg-sub
@@ -37,75 +39,114 @@
(rf/reg-sub
:wallet-connect/current-request-dapp
:<- [:wallet-connect/current-request]
:<- [:wallet-connect/pairings]
(fn [[request pairings]]
:<- [:wallet-connect/sessions]
(fn [[request sessions]]
(let [dapp-url (get-in request [:event :verifyContext :verified :origin])]
(->> pairings
(filter (fn [pairing]
(= dapp-url (get-in pairing [:peerMetadata :url]))))
(->> sessions
(filter (fn [session]
(= dapp-url (get session :url))))
(first)))))
(rf/reg-sub
:wallet-connect/current-request-network
:wallet-connect/sessions-for-current-account
:<- [:wallet-connect/sessions]
:<- [:wallet/current-viewing-account-address]
(fn [[sessions address]]
(filter
(fn [{:keys [accounts]}]
(some #(string/includes? % address) accounts))
sessions)))
(rf/reg-sub
:wallet-connect/chain-id
:<- [:wallet-connect/current-request]
(fn [request]
(-> request
(get-in [:event :params :chainId])
(wallet-connect-core/eip155->chain-id)
(networks/get-network-details))))
(wallet-connect-core/eip155->chain-id))))
(rf/reg-sub
:wallet-connect/current-request-network
:<- [:wallet-connect/chain-id]
(fn [chain-id]
(-> chain-id
(networks/get-network-details)
(wallet-connect-core/add-full-testnet-name))))
(rf/reg-sub
:wallet-connect/transaction-args
:<- [:wallet-connect/current-request]
(fn [{:keys [event transaction]}]
(when (transactions/transaction-request? event)
transaction)))
(rf/reg-sub
:wallet-connect/transaction-suggested-fees
:<- [:wallet-connect/current-request]
(fn [{:keys [event raw-data]}]
(when (transactions/transaction-request? event)
(:suggested-fees raw-data))))
(rf/reg-sub
:wallet-connect/transaction-max-fees-wei
:<- [:wallet-connect/transaction-args]
:<- [:wallet-connect/transaction-suggested-fees]
(fn [[transaction suggested-fees]]
(when transaction
(let [{:keys [gasPrice gas gasLimit maxFeePerGas]} transaction
eip-1559-chain? (:eip1559Enabled suggested-fees)
gas-limit (or gasLimit gas)
max-gas-fee (if eip-1559-chain? maxFeePerGas gasPrice)]
(money/bignumber (* max-gas-fee gas-limit))))))
(rf/reg-sub
:wallet-connect/account-eth-token
:<- [:wallet-connect/current-request-address]
:<- [:wallet/accounts]
(fn [[address accounts]]
(let [fee-token "ETH"
find-account #(when (= (:address %) address) %)
find-token #(when (= (:symbol %) fee-token) %)]
(->> accounts
(some find-account)
:tokens
(some find-token)))))
(rf/reg-sub
:wallet-connect/current-request-transaction-information
:<- [:wallet-connect/current-request]
:<- [:wallet/accounts]
:<- [:wallet-connect/chain-id]
:<- [:wallet-connect/transaction-max-fees-wei]
:<- [:wallet-connect/transaction-args]
:<- [:wallet-connect/account-eth-token]
:<- [:profile/currency]
:<- [:profile/currency-symbol]
(fn [[request accounts currency currency-symbol]]
(let [chain-id (-> request
(get-in [:raw-data :params :chainId])
(wallet-connect-core/eip155->chain-id))
all-tokens (->> accounts
(filter #(= (:address %)
(:address request)))
(first)
:tokens)
eth-token (->> all-tokens
(filter #(= (:symbol %) "ETH"))
(first))
{:keys [gasPrice gasLimit value]} (-> request
:raw-data
wallet-connect-core/get-request-params
first)
max-fees-wei (money/bignumber (* gasPrice gasLimit))]
(when (and gasPrice gasLimit)
(let [max-fees-ether (money/wei->ether max-fees-wei)
token-fiat-value (wallet-utils/calculate-token-fiat-value {:currency currency
:balance max-fees-ether
:token eth-token})
crypto-formatted (wallet-utils/get-standard-crypto-format eth-token max-fees-ether)
fiat-formatted (wallet-utils/get-standard-fiat-format crypto-formatted
currency-symbol
token-fiat-value)
balance (-> eth-token
(get-in [:balances-per-chain chain-id :raw-balance])
(money/bignumber))
value (money/bignumber value)
total-transaction-value (money/add max-fees-wei value)]
{:total-transaction-value total-transaction-value
:balance balance
:max-fees max-fees-wei
:max-fees-fiat-value token-fiat-value
:max-fees-fiat-formatted fiat-formatted
:error-state (cond
(and
(money/sufficient-funds? value balance)
(not (money/sufficient-funds? total-transaction-value balance)))
:not-enough-assets-to-pay-gas-fees
(fn [[chain-id max-fees-wei transaction eth-token currency currency-symbol]]
(when transaction
(let [max-fees-ether (money/wei->ether max-fees-wei)
max-fees-fiat (wallet-utils/calculate-token-fiat-value {:currency currency
:balance max-fees-ether
:token eth-token})
max-fees-fiat-formatted (-> max-fees-ether
(wallet-utils/get-standard-crypto-format eth-token)
(wallet-utils/get-standard-fiat-format currency-symbol
max-fees-fiat))
balance (-> eth-token
(get-in [:balances-per-chain chain-id :raw-balance])
money/bignumber)
tx-value (money/bignumber (:value transaction))
total-transaction-value (money/add max-fees-wei tx-value)]
{:total-transaction-value total-transaction-value
:balance balance
:max-fees max-fees-wei
:max-fees-fiat-value max-fees-fiat
:max-fees-fiat-formatted max-fees-fiat-formatted
:error-state (cond
(not (money/sufficient-funds? tx-value balance))
:not-enough-assets
(not (money/sufficient-funds? value balance))
:not-enough-assets
:else nil)})))))
(not (money/sufficient-funds? total-transaction-value
balance))
:not-enough-assets-to-pay-gas-fees)}))))
(rf/reg-sub
:wallet-connect/current-proposal-request
+4
View File
@@ -148,6 +148,10 @@
[n]
(wei-> :gwei n))
(defn gwei->wei
[n]
(->wei :gwei n))
(defn ether->wei
[^js bn]
(when bn
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v0.182.35",
"commit-sha1": "484b8aca1a12718c9b3940f8a398e60ee4419600",
"src-sha256": "1xnpx86k54lnsw93xw6la0sggd9y0nm7hn70cm0qgmq2qg8pzb3a"
"version": "v0.182.37",
"commit-sha1": "4a43b2b2bebe45df2100d1a5c5034105d93e50b8",
"src-sha256": "0f5mm7lx6s2qcy9xpa9v7piqb60yazi6p677fy105yz7hg731cw6"
}

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