Compare commits

..
Author SHA1 Message Date
pavloburykh d730a25d06 update go version 2024-10-02 17:13:24 +03:00
Lungu Cristian 97aff27980 Dapps Typed Data request improvements (#21333)
* feat: added type data flattening + tests

* feat: added typed data flattened ui

* ref: moved typed data utils into their own ns

* ref: small changes & formatting

* feat: show typed data view only for typed data requests

* ref: moved typed-data? into sub

* fix: tests and styling
2024-10-02 13:50:38 +03:00
Brian Sztamfater 0c3e836272 feat: disable swap and bridge options on testnet mode (#21343)
Signed-off-by: Brian Sztamfater <brian@status.im>
2024-09-30 13:13:15 -03:00
Mohsen 60fc4f1b9a [#21132] refactor: improve send transaction content in wc flow (#21266) 2024-09-30 15:11:56 +03:00
Siddarth Kumar b97e2df2fb chore: nuke personal INFURA token 2024-09-30 17:09:35 +05:30
Alexander f539bb5ca2 Swap flows (launch from home / launch from account) (#21269)
* Swap flows (launch from home / launch from account)

* Fixes

* Lint fix
2024-09-30 10:44:25 +02:00
29 changed files with 613 additions and 231 deletions
@@ -1,4 +1,5 @@
(ns quo.components.buttons.wallet-ctas.style)
(ns quo.components.buttons.wallet-ctas.style
(:require [quo.foundations.colors :as colors]))
(def inner-container
{:flex-direction :row
@@ -10,3 +11,9 @@
:width 77.75
:justify-content :center
:align-items :center})
(defn action-button-text
[theme disabled?]
(cond-> {:margin-top 4
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}
disabled? (assoc :opacity 0.5)))
@@ -3,28 +3,28 @@
[quo.components.buttons.wallet-button.view :as wallet-button]
[quo.components.buttons.wallet-ctas.style :as style]
[quo.components.markdown.text :as text]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[utils.i18n :as i18n]))
(defn action-button
[{:keys [icon text on-press theme accessibility-label]}]
[{:keys [icon text on-press theme accessibility-label disabled?]}]
[rn/view
{:style style/button-container
:accessibility-label accessibility-label}
[wallet-button/view
{:icon icon
:on-press on-press}]
{:icon icon
:disabled? disabled?
:on-press on-press}]
[text/text
{:weight :medium
:size :paragraph-2
:style {:margin-top 4
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}} text]])
:style (style/action-button-text theme disabled?)} text]])
(defn view
[{:keys [buy-action send-action receive-action bridge-action swap-action container-style]}]
[{:keys [buy-action send-action receive-action bridge-action swap-action bridge-disabled?
swap-disabled? container-style]}]
(let [theme (quo.theme/use-theme)]
[rn/view {:style container-style}
[rn/view {:style style/inner-container}
@@ -52,10 +52,12 @@
:text (i18n/label :t/swap)
:on-press swap-action
:theme theme
:disabled? swap-disabled?
:accessibility-label :swap}])
[action-button
{:icon :i/bridge
:text (i18n/label :t/bridge)
:on-press bridge-action
:theme theme
:disabled? bridge-disabled?
:accessibility-label :bridge}]]]))
+1 -1
View File
@@ -10,7 +10,7 @@
(defn enabled? [v] (= "1" v))
(goog-define INFURA_TOKEN "62f3cee52dbb484198e7339837e263f3")
(goog-define INFURA_TOKEN "")
(goog-define POKT_TOKEN "3ef2018191814b7e1009b8d9")
(goog-define STATUS_BUILD_PROXY_USER "")
(goog-define STATUS_BUILD_PROXY_PASSWORD "")
+9
View File
@@ -619,3 +619,12 @@
(def router-error-code-not-enough-liquidity "WPP-038")
(def router-error-code-price-impact-too-high "WPP-039")
(def router-error-code-not-enough-native-balance "WR-002")
(def ^:const wallet-transaction-estimation
{:unknown 0
:less-than-one-minute 1
:less-than-three-minutes 2
:less-than-five-minutes 3
:more-than-five-minutes 4})
(def ^:const wallet-connect-transaction-refresh-interval-ms 10000)
+21 -18
View File
@@ -26,7 +26,8 @@
(let [selected-tab (or (rf/sub [:wallet/account-tab]) first-tab-id)
{:keys [name color formatted-balance
watch-only?]} (rf/sub [:wallet/current-viewing-account])
customization-color (rf/sub [:profile/customization-color])]
customization-color (rf/sub [:profile/customization-color])
testnet-mode? (rf/sub [:profile/test-networks-enabled?])]
(hot-reload/use-safe-unmount (fn []
(rf/dispatch [:wallet/close-account-page])
(rf/dispatch [:wallet/clean-current-viewing-account])))
@@ -46,23 +47,25 @@
[quo/wallet-graph {:time-frame :empty}])
(when (not watch-only?)
[quo/wallet-ctas
{:container-style style/cta-buttons
:send-action (fn []
(rf/dispatch [:wallet/clean-send-data])
(rf/dispatch [:wallet/wizard-navigate-forward
{:start-flow? true
:flow-id :wallet-send-flow}]))
:receive-action #(rf/dispatch [:open-modal :screen/wallet.share-address
{:status :receive}])
:buy-action #(rf/dispatch [:show-bottom-sheet
{:content buy-token/view}])
:bridge-action (fn []
(rf/dispatch [:wallet/clean-send-data])
(rf/dispatch [:wallet/start-bridge]))
:swap-action (when (ff/enabled? ::ff/wallet.swap)
(fn []
(rf/dispatch [:wallet.tokens/get-token-list])
(rf/dispatch [:open-modal :screen/wallet.swap-select-asset-to-pay])))}])
{:container-style style/cta-buttons
:send-action (fn []
(rf/dispatch [:wallet/clean-send-data])
(rf/dispatch [:wallet/wizard-navigate-forward
{:start-flow? true
:flow-id :wallet-send-flow}]))
:receive-action #(rf/dispatch [:open-modal :screen/wallet.share-address
{:status :receive}])
:buy-action #(rf/dispatch [:show-bottom-sheet
{:content buy-token/view}])
:bridge-action (fn []
(rf/dispatch [:wallet/clean-send-data])
(rf/dispatch [:wallet/start-bridge]))
:swap-action (when (ff/enabled? ::ff/wallet.swap)
(fn []
(rf/dispatch [:wallet.tokens/get-token-list])
(rf/dispatch [:open-modal :screen/wallet.swap-select-asset-to-pay])))
:bridge-disabled? testnet-mode?
:swap-disabled? testnet-mode?}])
[quo/tabs
{:style style/tabs
:size 32
@@ -1,6 +1,5 @@
(ns status-im.contexts.wallet.common.token-value.view
(:require [quo.core :as quo]
[status-im.common.not-implemented :as not-implemented]
[status-im.contexts.wallet.send.utils :as send-utils]
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
[status-im.feature-flags :as ff]
@@ -18,15 +17,15 @@
:right-icon :i/external})
(defn- action-send
[send-params entry-point]
[{:keys [disabled?] :as params} entry-point]
{:icon :i/send
:accessibility-label :send
:label (i18n/label :t/send)
:disabled? (:disabled? send-params)
:disabled? disabled?
:on-press (fn []
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:wallet/clean-send-data])
(rf/dispatch [:wallet/set-token-to-send send-params entry-point]))})
(rf/dispatch [:wallet/set-token-to-send params entry-point]))})
(defn- action-receive
[selected-account?]
@@ -38,21 +37,26 @@
#(rf/dispatch [:open-modal :screen/share-shell {:initial-tab :wallet}]))})
(defn- action-bridge
[bridge-params]
[{:keys [bridge-disabled? testnet-mode?] :as params}]
{:icon :i/bridge
:accessibility-label :bridge
:label (i18n/label :t/bridge)
:disabled? (:bridge-disabled? bridge-params)
:disabled? (or testnet-mode? bridge-disabled?)
:on-press (fn []
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:wallet/bridge-select-token bridge-params]))})
(rf/dispatch [:wallet/bridge-select-token params]))})
(defn- action-swap
[]
[{:keys [token token-symbol testnet-mode?]}]
{:icon :i/swap
:accessibility-label :swap
:label (i18n/label :t/swap)
:on-press #(not-implemented/alert)})
:disabled? testnet-mode?
:on-press (fn []
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:wallet.swap/start
{:asset-to-pay (or token {:symbol token-symbol})
:open-new-screen? true}]))})
(defn- action-manage-tokens
[watch-only?]
@@ -71,47 +75,39 @@
(defn token-value-drawer
[token watch-only? entry-point]
(let [token-symbol (:token token)
token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered
{:query token-symbol}]))
fiat-unformatted-value (get-in token [:values :fiat-unformatted-value])
has-balance? (money/greater-than fiat-unformatted-value (money/bignumber "0"))
selected-account? (rf/sub [:wallet/current-viewing-account-address])
token-owners (rf/sub [:wallet/operable-addresses-with-token-symbol token-symbol])
send-params (if selected-account?
{:token token-data
:stack-id :screen/wallet.accounts
:disabled? (not has-balance?)
:start-flow? true
:owners token-owners}
{:token-symbol token-symbol
:stack-id :wallet-stack
:start-flow? true
:owners token-owners})
bridge-params (if selected-account?
{:token token-data
:bridge-disabled? (or (not has-balance?)
(send-utils/bridge-disabled? token-symbol))
:stack-id :screen/wallet.accounts
:start-flow? true
:owners token-owners}
{:token-symbol token-symbol
:bridge-disabled? (send-utils/bridge-disabled? token-symbol)
:stack-id :wallet-stack
:start-flow? true
:owners token-owners})]
(let [token-symbol (:token token)
token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered
{:query token-symbol}]))
selected-account (rf/sub [:wallet/current-viewing-account-address])
token-owners (rf/sub [:wallet/operable-addresses-with-token-symbol token-symbol])
testnet-mode? (rf/sub [:profile/test-networks-enabled?])
params (cond-> {:start-flow? true
:owners token-owners
:testnet-mode? testnet-mode?}
selected-account
(assoc :token token-data
:stack-id :screen/wallet.accounts
:has-balance? (-> (get-in token [:values :fiat-unformatted-value])
(money/greater-than (money/bignumber "0"))))
(not selected-account)
(assoc :token-symbol token-symbol
:stack-id :wallet-stack))]
[quo/action-drawer
[(cond->> [(when (ff/enabled? ::ff/wallet.assets-modal-manage-tokens)
(action-manage-tokens watch-only?))
(when (ff/enabled? ::ff/wallet.assets-modal-hide)
(action-hide))]
(not watch-only?) (concat [(action-buy)
(when (seq token-owners)
(action-send send-params entry-point))
(action-receive selected-account?)
(when (ff/enabled? ::ff/wallet.swap) (action-swap))
(when (seq (seq token-owners))
(action-bridge bridge-params))]))]]))
(not watch-only?)
(concat [(action-buy)
(when (seq token-owners)
(action-send params entry-point))
(action-receive selected-account)
(when (ff/enabled? ::ff/wallet.swap)
(action-swap params))
(when (seq token-owners)
(action-bridge (assoc params
:bridge-disabled?
(send-utils/bridge-disabled? token-symbol))))]))]]))
(defn view
[item _ _ {:keys [watch-only? entry-point]}]
@@ -493,3 +493,13 @@
:available-balance (calculate-total-token-balance token)
:total-balance (calculate-total-token-balance token chain-ids)))
tokens))
(defn estimated-time-format
"Formats the estimated time for a transaction"
[estimated-time]
(condp = estimated-time
(:unknown constants/wallet-transaction-estimation) ">5"
(:less-than-one-minute constants/wallet-transaction-estimation) "<1"
(:less-than-three-minutes constants/wallet-transaction-estimation) "1-3"
(:less-than-five-minutes constants/wallet-transaction-estimation) "3-5"
">5"))
+29 -14
View File
@@ -14,22 +14,36 @@
[utils.number :as number]))
(rf/reg-event-fx :wallet.swap/start
(fn [{:keys [db]} [{:keys [asset-to-pay asset-to-receive network]}]]
(let [asset-to-receive' (or asset-to-receive
(swap-utils/select-asset-to-receive
(:wallet db)
(:profile/profile db)
asset-to-pay))
network' (or network
(swap-utils/select-network asset-to-pay))]
(fn [{:keys [db]} [{:keys [network open-new-screen?] :as data}]]
(let [{:keys [wallet]} db
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
account (swap-utils/wallet-account wallet)
asset-to-pay (if (get-in data [:asset-to-pay :networks])
(:asset-to-pay data)
(swap-utils/select-asset-to-pay-by-symbol
{:wallet wallet
:account account
:test-networks-enabled? test-networks-enabled?
:token-symbol (get-in data [:asset-to-pay :symbol])}))
asset-to-receive (or (:asset-to-receive data)
(swap-utils/select-default-asset-to-receive
{:wallet wallet
:account account
:test-networks-enabled? test-networks-enabled?
:asset-to-pay asset-to-pay}))
network' (or network
(swap-utils/select-network asset-to-pay))]
{:db (-> db
(assoc-in [:wallet :ui :swap :asset-to-pay] asset-to-pay)
(assoc-in [:wallet :ui :swap :asset-to-receive] asset-to-receive')
(assoc-in [:wallet :ui :swap :asset-to-receive] asset-to-receive)
(assoc-in [:wallet :ui :swap :network] network'))
:fx (if network'
[[:dispatch
[:navigate-to-within-stack
[:screen/wallet.setup-swap :screen/wallet.swap-select-asset-to-pay]]]
[[:dispatch [:wallet/switch-current-viewing-account (:address account)]]
[:dispatch
(if open-new-screen?
[:navigate-to :screen/wallet.setup-swap]
[:navigate-to-within-stack
[:screen/wallet.setup-swap :screen/wallet.swap-select-asset-to-pay]])]
[:dispatch [:wallet.swap/set-default-slippage]]]
[[:dispatch
[:show-bottom-sheet
@@ -41,8 +55,9 @@
(rf/dispatch
[:wallet.swap/start
{:asset-to-pay asset-to-pay
:asset-to-receive asset-to-receive'
:network network}]))}])}]]])})))
:asset-to-receive asset-to-receive
:network network
:open-new-screen? open-new-screen?}]))}])}]]])})))
(rf/reg-event-fx :wallet.swap/select-asset-to-pay
(fn [{:keys [db]} [{:keys [token]}]]
@@ -21,7 +21,9 @@
(defn- assets-view
[search-text on-change-text]
(let [on-token-press (fn [token]
(rf/dispatch [:wallet.swap/start {:asset-to-pay token}]))]
(rf/dispatch [:wallet.swap/start
{:asset-to-pay token
:open-new-screen? false}]))]
[:<>
[search-input search-text on-change-text]
[asset-list/view
+50 -11
View File
@@ -30,22 +30,61 @@
:else
(i18n/label :t/something-went-wrong-please-try-again-later)))
(defn select-asset-to-receive
[wallet profile asset-to-pay]
(let [wallet-address (get-in wallet [:current-viewing-account-address])
account (-> wallet
:accounts
vals
(utils/get-account-by-address wallet-address))
test-networks-enabled? (get profile :test-networks-enabled?)
networks (-> (get-in wallet
[:wallet :networks (if test-networks-enabled? :test :prod)])
(network-utils/sorted-networks-with-details))]
(defn- first-operable-account
[accounts]
(->> accounts
vals
(remove :watch-only?)
(filter :operable?)
(sort-by :position)
first))
(defn wallet-account
"Picks the account that's gonna be used for the swap operation.
It's gonna be either the preselected account defined by
`[:wallet :current-viewing-account-address]` in `db`
or the first operable account."
[wallet]
(if-let [wallet-address (get wallet :current-viewing-account-address)]
(-> wallet
:accounts
vals
(utils/get-account-by-address wallet-address))
(-> wallet :accounts first-operable-account)))
(defn select-asset-to-pay-by-symbol
"Selects an asset to pay by token symbol.
It's used for cases when only token symbol is available and the information
about token needs to be extracted from the database.
That happens when token is being selected on the home screen and
it basically indicates that no account pre-selection was made."
[{:keys [wallet account test-networks-enabled? token-symbol]}]
(let [networks (-> (get-in wallet [:networks (if test-networks-enabled? :test :prod)])
(network-utils/sorted-networks-with-details))
token (->> account
:tokens
(filter #(= token-symbol (:symbol %)))
first)]
(assoc token :networks (network-utils/network-list token networks))))
(defn select-default-asset-to-receive
"Selects an asset to receive if it was not provided explicitly.
The principle of how the asset is being selected is simple: we get the
whole list, remove the currently selected `asset-to-pay` from it, and choose
the first one of what's left."
[{:keys [wallet account test-networks-enabled? asset-to-pay]}]
(let [networks (-> (get-in wallet [:networks (if test-networks-enabled? :test :prod)])
(network-utils/sorted-networks-with-details))]
(->> (utils/tokens-with-balance (:tokens account) networks nil)
(remove #(= (:symbol %) (:symbol asset-to-pay)))
first)))
(defn select-network
"Chooses the network.
Usually user needs to do the selection first and if the selection was done
then the list of networks for the defined token will always contain
one entry. Otherwise `nil` will be returned from here which will serve
as an indicator that the network selector needs to be displayed."
[{:keys [networks]}]
(when (= (count networks) 1)
(first networks)))
@@ -7,6 +7,7 @@
[status-im.constants :as constants]
[status-im.contexts.wallet.wallet-connect.utils.signing :as signing]
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transactions]
[status-im.contexts.wallet.wallet-connect.utils.typed-data :as typed-data]
[utils.i18n :as i18n]
[utils.security.core :as security]))
@@ -123,11 +124,11 @@
(rf/reg-fx
:effects.wallet-connect/sign-typed-data
(fn [{:keys [password address data version chain-id on-success on-error]}]
(-> (signing/eth-sign-typed-data (security/safe-unmask-data password)
address
data
chain-id
version)
(-> (typed-data/sign (security/safe-unmask-data password)
address
data
chain-id
version)
(promesa/then on-success)
(promesa/catch on-error))))
@@ -2,15 +2,15 @@
(: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.utils.data-store :as
data-store]
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
[status-im.contexts.wallet.wallet-connect.utils.signing :as signing]
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transactions]
[status-im.contexts.wallet.wallet-connect.utils.typed-data :as typed-data]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
(rf/reg-event-fx
@@ -37,7 +37,9 @@
(assoc-in [:wallet-connect/current-request :response-sent?] false))
:fx [(condp = method
constants/wallet-connect-eth-send-transaction-method
[:dispatch [:wallet-connect/process-eth-send-transaction]]
[:dispatch
[:wallet-connect/process-eth-send-transaction
{:on-success (fn [] (rf/dispatch [:wallet-connect/show-request-modal]))}]]
constants/wallet-connect-eth-sign-method
[:dispatch [:wallet-connect/process-eth-sign]]
@@ -94,22 +96,25 @@
:raw-data prepared-tx
:transaction tx
:chain-id chain-id
:display-data display-data)
:fx [[:dispatch [:wallet-connect/show-request-modal]]]})))
:display-data display-data)})))
(rf/reg-event-fx
:wallet-connect/process-eth-send-transaction
(fn [{:keys [db]}]
(fn [{:keys [db]} [{:keys [on-success]}]]
(let [event (data-store/get-db-current-request-event db)
tx (-> event data-store/get-request-params first)
chain-id (-> event
(get-in [:params :chainId])
networks/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 %])}]]})))
(when tx
{:fx [[:effects.wallet-connect/prepare-transaction
{:tx tx
:chain-id chain-id
:on-success (fn [data]
(rf/dispatch [:wallet-connect/prepare-transaction-success data chain-id])
(when on-success
(rf/call-continuation on-success)))
:on-error #(rf/dispatch [:wallet-connect/on-processing-error %])}]]}))))
(rf/reg-event-fx
:wallet-connect/process-eth-sign-transaction
@@ -130,16 +135,13 @@
(fn [{:keys [db]}]
(try
(let [[address raw-data] (data-store/get-db-current-request-params db)
parsed-raw-data (transforms/js-parse raw-data)
session-chain-id (-> (data-store/get-db-current-request-event db)
(get-in [:params :chainId])
networks/eip155->chain-id)
data-chain-id (-> parsed-raw-data
transforms/js->clj
signing/typed-data-chain-id)
parsed-data (-> parsed-raw-data
(transforms/js-dissoc :types :primaryType)
(transforms/js-stringify 2))]
typed-data (-> raw-data
transforms/js-parse
transforms/js->clj)
data-chain-id (typed-data/get-chain-id typed-data)]
(if (and data-chain-id
(not= session-chain-id data-chain-id))
{:fx [[:dispatch
@@ -150,7 +152,7 @@
[:wallet-connect/current-request]
assoc
:address (string/lower-case address)
:display-data (or parsed-data raw-data)
:display-data (typed-data/flatten-typed-data typed-data)
:raw-data raw-data)
:fx [[:dispatch [:wallet-connect/show-request-modal]]]}))
(catch js/Error err
@@ -4,6 +4,7 @@
[quo.theme]
[react-native.core :as rn]
[status-im.common.standard-authentication.core :as standard-authentication]
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
[status-im.contexts.wallet.wallet-connect.modals.common.footer.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -14,17 +15,25 @@
(rf/dispatch [:wallet-connect/respond-current-session password]))
(defn view
[{:keys [warning-label slide-button-text error-text]} & children]
[{:keys [warning-label slide-button-text error-state]} & children]
(let [{:keys [customization-color]} (rf/sub [:wallet-connect/current-request-account-details])
offline? (rf/sub [:network/offline?])
theme (quo.theme/use-theme)]
[:<>
(when (or offline? error-text)
(when (or offline? error-state)
[quo/alert-banner
{:action? false
:text (if offline?
(i18n/label :t/wallet-connect-no-internet-warning)
error-text)}])
{:action? (when error-state true)
:text (if offline?
(i18n/label :t/wallet-connect-no-internet-warning)
(i18n/label (condp = error-state
:not-enough-assets-to-pay-gas-fees
:t/not-enough-assets-to-pay-gas-fees
:not-enough-assets
:t/not-enough-assets-for-transaction)))
:button-text (i18n/label :t/buy-eth)
:on-button-press #(rf/dispatch [:show-bottom-sheet
{:content buy-token/view}])}])
[rn/view {:style style/content-container}
(into [rn/view
{:style style/data-items-container}]
@@ -33,7 +42,7 @@
[standard-authentication/slide-button
{:size :size-48
:track-text slide-button-text
:disabled? (or offline? (seq error-text))
:disabled? (or offline? error-state)
:customization-color customization-color
:on-auth-success on-auth-success
:auth-button-label (i18n/label :t/confirm)}]]
@@ -1,5 +1,6 @@
(ns status-im.contexts.wallet.wallet-connect.modals.common.style
(:require [status-im.constants :as constants]))
(:require [quo.foundations.colors :as colors]
[status-im.constants :as constants]))
(defn container
[bottom]
@@ -21,3 +22,23 @@
(def data-item
{:flex 1
:background-color :transparent})
(def typed-data-item
(assoc data-item :margin-bottom 4))
(def data-border-container
{:padding-horizontal 12
:padding-top 8
:margin-top 10.5
:margin-bottom 0
:border-width 1
:border-color colors/neutral-10
:border-radius 16})
(def data-item-container
{:padding 10
:margin-top 10.5
:margin-bottom 0
:border-width 1
:border-color colors/neutral-10
:border-radius 16})
@@ -2,7 +2,9 @@
(:require [quo.core :as quo]
[quo.theme]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[react-native.safe-area :as safe-area]
[status-im.constants :as constants]
[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]
@@ -10,19 +12,71 @@
[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]
[status-im.contexts.wallet.wallet-connect.modals.common.style :as style]
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transaction-utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- refetch-transaction
[]
(rf/dispatch [:wallet-connect/process-eth-send-transaction]))
(def tabs-data
[{:id :tab/data :label (i18n/label :t/data)}
{:id :tab/hex :label (i18n/label :t/hex)}])
(defn- render-item
[props]
(let [[label value] props]
[quo/data-item
{:card? false
:container-style style/data-item
:title (str (name label) ":")
:subtitle value}]))
(defn- tab-view
[selected-tab]
(let [{:keys [transaction]} (rf/sub [:wallet-connect/current-request])
transaction-items (rn/use-memo #(-> transaction
(transaction-utils/transaction-hex-values->number)
(transaction-utils/transactions->display-array))
[transaction])]
[:<>
(case selected-tab
:tab/data [gesture/flat-list
{:data transaction-items
:content-container-style style/data-item-container
:render-fn render-item
:shows-vertical-scroll-indicator false}]
:tab/hex [data-block/view])]))
(defn view
[]
(let [bottom (safe-area/get-bottom)
(let [bottom (safe-area/get-bottom)
{:keys [customization-color]
:as account} (rf/sub [:wallet-connect/current-request-account-details])
dapp (rf/sub [:wallet-connect/current-request-dapp])
network (rf/sub [:wallet-connect/current-request-network])
:as account} (rf/sub [:wallet-connect/current-request-account-details])
dapp (rf/sub [:wallet-connect/current-request-dapp])
network (rf/sub [:wallet-connect/current-request-network])
{:keys [max-fees-fiat-formatted
error-state]} (rf/sub [:wallet-connect/current-request-transaction-information])]
(rn/use-unmount #(rf/dispatch [:wallet-connect/on-request-modal-dismissed]))
error-state estimated-time]} (rf/sub
[:wallet-connect/current-request-transaction-information])
[selected-tab set-selected-tab] (rn/use-state (:id (first tabs-data)))
on-change-tab #(set-selected-tab %)
refetch-interval-ref (rn/use-ref nil)
clear-interval (rn/use-callback (fn []
(when (.-current refetch-interval-ref)
(js/clearInterval
(.-current refetch-interval-ref))))
[refetch-interval-ref])]
(rn/use-mount
(fn []
(clear-interval)
(set! (.-current refetch-interval-ref)
(js/setInterval refetch-transaction constants/wallet-connect-transaction-refresh-interval-ms))))
(rn/use-unmount (fn []
(clear-interval)
(rf/dispatch [:wallet-connect/on-request-modal-dismissed])))
[rn/view {:style (style/container bottom)}
[quo/gradient-cover {:customization-color customization-color}]
[page-nav/view
@@ -33,17 +87,17 @@
{:label (i18n/label :t/wallet-connect-send-transaction-header)
:dapp dapp
:account account}]
[data-block/view]]
[quo/segmented-control
{:size 32
:blur? false
:default-active :tab/data
:data tabs-data
:on-change on-change-tab}]
[tab-view selected-tab]]
[footer/view
{:warning-label (i18n/label :t/wallet-connect-sign-warning)
:slide-button-text (i18n/label :t/slide-to-send)
:error-text (when error-state
(i18n/label (condp = error-state
:not-enough-assets-to-pay-gas-fees
:t/not-enough-assets-to-pay-gas-fees
:not-enough-assets
:t/not-enough-assets)))}
:error-state error-state}
[quo/data-item
{:status :default
:card? false
@@ -54,5 +108,12 @@
:subtitle (:full-name network)}]
[fees-data-item/view
{:fees max-fees-fiat-formatted
:fees-error error-state}]]]]))
:fees-error error-state}]
[quo/data-item
{:card? false
:container-style style/data-item
:title (i18n/label :t/est-time)
:subtitle (if estimated-time
(i18n/label :t/time-in-mins {:minutes estimated-time})
(i18n/label :t/unknown))}]]]]))
@@ -1,8 +1,9 @@
(ns status-im.contexts.wallet.wallet-connect.modals.sign-message.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[react-native.safe-area :as safe-area]
[status-im.contexts.wallet.wallet-connect.modals.common.data-block.view :as data-block]
[status-im.common.raw-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]
@@ -12,6 +13,37 @@
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn typed-data-field
[{:keys [label value]}]
[quo/data-item
{:card? false
:container-style style/typed-data-item
:title label
:subtitle value}])
(defn typed-data-view
[]
(let [display-data (rf/sub [:wallet-connect/current-request-display-data])]
[gesture/flat-list
{:data display-data
:style style/data-border-container
:over-scroll-mode :never
:content-container-style {:padding-bottom 12}
:render-fn typed-data-field
:shows-vertical-scroll-indicator false}]))
(defn message-data-view
[]
(let [display-data (rf/sub [:wallet-connect/current-request-display-data])]
[data-block/view display-data]))
(defn display-data-view
[]
(let [typed-data? (rf/sub [:wallet-connect/typed-data-request?])]
(if typed-data?
[typed-data-view]
[message-data-view])))
(defn view
[]
(let [bottom (safe-area/get-bottom)
@@ -29,7 +61,7 @@
{:label (i18n/label :t/wallet-connect-sign-message-header)
:dapp dapp
:account account}]
[data-block/view]]
[display-data-view]]
[footer/view
{:warning-label (i18n/label :t/wallet-connect-sign-warning)
:slide-button-text (i18n/label :t/slide-to-sign)}
@@ -57,3 +57,8 @@
[chain-id]
(-> (rpc-events/call-async "wallet_getSuggestedFees" true chain-id)
(promesa/then transforms/js->clj)))
(defn wallet-get-transaction-estimated-time
[chain-id max-fee-per-gas]
(-> (rpc-events/call-async "wallet_getTransactionEstimatedTime" true chain-id max-fee-per-gas)
(promesa/then transforms/js->clj)))
@@ -1,28 +1,12 @@
(ns status-im.contexts.wallet.wallet-connect.utils.signing
(:require [native-module.core :as native-module]
[promesa.core :as promesa]
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
data-store]
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
[utils.hex :as hex]
[utils.number :as number]
[utils.transforms :as transforms]))
(defn typed-data-chain-id
"Returns the `:chain-id` from typed data if it's present and if the EIP712 domain defines it. Without
the `:chain-id` in the domain type, it will not be signed as part of the typed-data."
[typed-data]
(let [chain-id-type? (->> typed-data
:types
:EIP712Domain
(some #(= "chainId" (:name %))))
data-chain-id (-> typed-data
:domain
:chainId
number/parse-int)]
(when chain-id-type?
data-chain-id)))
(:require
[native-module.core :as native-module]
[promesa.core :as promesa]
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
data-store]
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
[utils.hex :as hex]
[utils.transforms :as transforms]))
(defn eth-sign
[password address data]
@@ -38,13 +22,3 @@
(-> (rpc/wallet-hash-message-eip-191 data)
(promesa/then #(rpc/wallet-sign-message % address password))
(promesa/then hex/prefix-hex)))
(defn eth-sign-typed-data
[password address data chain-id-eip155 version]
(let [legacy? (= version :v1)
chain-id (networks/eip155->chain-id chain-id-eip155)]
(rpc/wallet-safe-sign-typed-data data
address
password
chain-id
legacy?)))
@@ -51,12 +51,16 @@
(transforms/js-stringify 0)))
(defn beautify-transaction
[tx]
(-> tx
clj->js
(js/JSON.stringify nil 2)))
(defn transaction-hex-values->number
[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))))
(format-tx-hex-values hex->number))))
(defn- gwei->hex
[gwei]
@@ -121,10 +125,14 @@
tx-priority
suggested-fees)
prepare-transaction-for-rpc
(rpc/wallet-build-transaction chain-id))]
(rpc/wallet-build-transaction chain-id))
estimated-time (rpc/wallet-get-transaction-estimated-time
chain-id
(:maxPriorityFeePerGas suggested-fees))]
{:tx-args tx-args
:tx-hash message-to-sign
:suggested-fees suggested-fees}))
:suggested-fees suggested-fees
:estimated-time estimated-time}))
(defn sign-transaction
[password address tx-hash tx-args chain-id]
@@ -141,3 +149,11 @@
tx-args
signature)]
tx))
(defn transactions->display-array
[data]
(remove (fn [[k v]]
(or (= v "0x")
(= k :MultiTransactionID)
(= k :Symbol)))
data))
@@ -0,0 +1,102 @@
(ns status-im.contexts.wallet.wallet-connect.utils.typed-data
(:require [clojure.string :as string]
[status-im.constants :as constants]
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
[utils.number :as number]))
(declare flatten-data)
(defn- format-flattened-key
[k]
(cond
(keyword? k) (name k)
(number? k) (str k)
(string? k) k
:else "unsupported-key"))
(defn- flatten-map
[data path]
(reduce-kv (fn [acc k v]
(->> (format-flattened-key k)
(conj path)
(flatten-data v acc)))
[]
data))
(defn- flatten-vec
[data path]
(->> data
(map-indexed vector)
(reduce (fn [acc [idx v]]
(->> (str idx)
(conj path)
(flatten-data v acc)))
[])))
(defn flatten-data
"Recursively flatten a map or vector into a flat vector.
e.g. `[[[\"person\" \"first-name\"] \"Rich\"]
[[[\"person\" \"last-name\"] \"Hickey\"]]]`"
([value]
(flatten-data value [] []))
([value acc path]
(cond
(map? value) (into acc (flatten-map value path))
(vector? value) (into acc (flatten-vec value path))
:else (conj acc [path value]))))
(defn format-fields
"Format the fields into maps with `:label` & `:value`, where the label
is the flattened keys joined with a separator
e.g. `{:label \"person: first-name:\" :value \"Rich\"}`"
[data separator]
(mapv (fn [[kv v]]
{:label (-> separator
(string/join kv)
(str separator)
string/trim)
:value v})
data))
(defn flatten-typed-data
"Flatten typed data and prepare it for UI"
[typed-data]
(-> typed-data
(select-keys [:domain :message])
flatten-data
(format-fields ": ")))
(defn get-chain-id
"Returns the `:chain-id` from typed data if it's present and if the EIP712 domain defines it. Without
the `:chain-id` in the domain type, it will not be signed as part of the typed-data."
[typed-data]
(let [chain-id-type? (->> typed-data
:types
:EIP712Domain
(some #(= "chainId" (:name %))))
data-chain-id (-> typed-data
:domain
:chainId
number/parse-int)]
(when chain-id-type?
data-chain-id)))
(defn sign
[password address data chain-id-eip155 version]
(let [legacy? (= version :v1)
chain-id (networks/eip155->chain-id chain-id-eip155)]
(rpc/wallet-safe-sign-typed-data data
address
password
chain-id
legacy?)))
(defn typed-data-request?
[method]
(contains?
#{constants/wallet-connect-eth-sign-typed-v4-method
constants/wallet-connect-eth-sign-typed-method}
method))
@@ -0,0 +1,52 @@
(ns status-im.contexts.wallet.wallet-connect.utils.typed-data-test
(:require
[cljs.test :refer-macros [deftest is testing]]
[status-im.contexts.wallet.wallet-connect.utils.typed-data :as sut]))
(deftest flatten-data-test
(testing "correctly returns the fallback when key is not string/keyword/number"
(is (match? [[["unsupported-key"] "value"]]
(sut/flatten-data {[1 2] "value"}))))
(testing "correctly flattens a simple map"
(is (match? [[["zero"] 0]
[["one"] 1]
[["2"] 2]]
(sut/flatten-data {:zero 0
"one" 1
2 2}))))
(testing "correctly flattens a simple vec"
(is (match? [[["0"] "zero"] [["1"] "one"]]
(sut/flatten-data ["zero" "one"]))))
(testing "correctly flattens a nested map"
(is (match? [[["nested" "child"] "child value"]
[["nested" "nested" "0"] "child one"]
[["nested" "nested" "1"] "child two"]
[["flat"] "child value"]]
(sut/flatten-data {:nested {:child "child value"
:nested ["child one" "child two"]}
:flat "child value"}))))
(testing "correctly flattens a nested vector"
(is (match? [[["0" "flat"] 1]
[["0" "nested-vector" "0"] 1]
[["0" "nested-vector" "1"] 2]
[["0" "nested-map" "one"] 1]]
(sut/flatten-data [{:flat 1
:nested-vector [1 2]
:nested-map {:one 1}}])))))
(deftest flatten-typed-data-test
(testing "successfully extracts, flattens and formats the typed data"
(is (match? [{:label "domain: chain-id:" :value 1}
{:label "message: to: address:" :value "0x"}
{:label "message: from: address:" :value "0x"}
{:label "message: amount:" :value "0x"}]
(sut/flatten-typed-data {:domain {:chain-id 1}
:types {:Tx [{:name "to"
:type "address"}]}
:message {:to {:address "0x"}
:from {:address "0x"}
:amount "0x"}})))))
@@ -4,6 +4,7 @@
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
data-store]
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
[status-im.contexts.wallet.wallet-connect.utils.typed-data :as typed-data]
[utils.string]))
(rf/reg-sub
@@ -16,6 +17,14 @@
:<- [:wallet-connect/current-request]
:-> :display-data)
(rf/reg-sub
:wallet-connect/current-request-method
:<- [:wallet-connect/current-request]
(fn [request]
(-> request
:event
data-store/get-request-method)))
(rf/reg-sub
:wallet-connect/current-request-account-details
:<- [:wallet-connect/current-request-address]
@@ -45,3 +54,8 @@
:wallet-connect/current-request-network
:<- [:wallet-connect/chain-id]
networks/chain-id->network-details)
(rf/reg-sub
:wallet-connect/typed-data-request?
:<- [:wallet-connect/current-request-method]
typed-data/typed-data-request?)
@@ -54,20 +54,23 @@
:<- [:profile/currency-symbol]
(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 (-> (wallet-utils/get-standard-crypto-format eth-token max-fees-ether)
(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)]
(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 (-> (wallet-utils/get-standard-crypto-format eth-token
max-fees-ether)
(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)
estimated-time-formatted (wallet-utils/estimated-time-format (:estimated-time transaction))]
{:total-transaction-value total-transaction-value
:balance balance
:estimated-time estimated-time-formatted
:max-fees max-fees-wei
:max-fees-fiat-value max-fees-fiat
:max-fees-fiat-formatted max-fees-fiat-formatted
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v2.3.0",
"commit-sha1": "effde33d493ff52b66c8013067c9aa6444d84473",
"src-sha256": "1rd0mczdkvjm9pbmza234v1jy1bvqh3ni2xck1l42ha4sld2aqjl"
"version": "fix/suggested-path-after-kp-deletion",
"commit-sha1": "6f386908f61807353482aad8ed3abc56a21dd2ef",
"src-sha256": "1gd9kb3b86g9g98sqxxc7kp22kbr6z75f11p6q2sf3vwrx37yb3j"
}
+21 -16
View File
@@ -111,11 +111,13 @@ def get_app_path():
return app_path
log_file_names = ['geth', 'requests', 'Status']
def pull_geth(driver):
result = driver.pull_file(get_app_path() + 'geth.log')
return base64.b64decode(result)
def pull_log_file(driver, log_file_name):
result = driver.pull_file(get_app_path() + '%s.log' % log_file_name)
def pull_requests_log(driver):
result = driver.pull_file(get_app_path() + 'requests.log')
return base64.b64decode(result)
@@ -214,7 +216,7 @@ class SingleDeviceTestCase(AbstractTestCase):
self.print_sauce_lab_info(self.driver)
try:
self.add_alert_text_to_report(self.driver)
geth_content = pull_log_file(self.driver, 'geth')
geth_content = pull_geth(self.driver)
self.driver.quit()
if pytest_config_global['docker']:
appium_container.stop_container()
@@ -277,7 +279,7 @@ class SauceMultipleDeviceTestCase(AbstractTestCase):
self.add_alert_text_to_report(self.drivers[driver])
geth_names.append(
'%s_geth%s.log' % (test_suite_data.current_test.name, str(self.drivers[driver].number)))
geth_contents.append(pull_log_file(self.drivers[driver], log_file_name='geth'))
geth_contents.append(pull_geth(self.drivers[driver]))
self.drivers[driver].quit()
except (WebDriverException, AttributeError):
pass
@@ -381,12 +383,14 @@ class SauceSharedMultipleDeviceTestCase(AbstractTestCase):
try:
self.print_sauce_lab_info(self.drivers[driver])
self.add_alert_text_to_report(self.drivers[driver])
for log in log_file_names:
log_names.append(
'%s_%s%s.log' % (test_suite_data.current_test.name, log, str(self.drivers[driver].number)))
log_contents.append(pull_log_file(self.drivers[driver], log_file_name=log))
except (WebDriverException, AttributeError, RemoteDisconnected, ProtocolError) as e:
raise e
log_names.append(
'%s_geth%s.log' % (test_suite_data.current_test.name, str(self.drivers[driver].number)))
log_contents.append(pull_geth(self.drivers[driver]))
log_names.append(
'%s_requests%s.log' % (test_suite_data.current_test.name, str(self.drivers[driver].number)))
log_contents.append(pull_requests_log(self.drivers[driver]))
except (WebDriverException, AttributeError, RemoteDisconnected, ProtocolError):
pass
finally:
try:
logs = {log_names[i]: log_contents[i] for i in range(len(log_names))}
@@ -416,14 +420,15 @@ class SauceSharedMultipleDeviceTestCase(AbstractTestCase):
try:
for i, driver in cls.drivers.items():
if group_setup_failed:
for log in log_file_names:
log_contents.append(pull_log_file(driver=driver, log_file_name=log))
log_names.append('%s_%s%s.log' % (cls.__name__, log, i))
log_contents.append(pull_geth(driver=driver))
log_names.append('%s_geth%s.log' % (cls.__name__, i))
log_contents.append(pull_requests_log(driver=driver))
log_names.append('%s_requests%s.log' % (cls.__name__, i))
session_id = driver.session_id
try:
sauce.jobs.update_job(username=sauce_username, job_id=session_id, name=cls.__name__)
except (RemoteDisconnected, SauceException, requests.exceptions.ConnectionError) as e:
raise e
except (RemoteDisconnected, SauceException, requests.exceptions.ConnectionError):
pass
try:
driver.quit()
except WebDriverException:
+2 -2
View File
@@ -747,8 +747,8 @@ class BaseView(object):
return items_in_logcat
def find_values_in_geth(self, *args):
from tests.base_test_case import pull_log_file
b64_log = pull_log_file(self.driver, log_file_name='geth')
from tests.base_test_case import pull_geth
b64_log = pull_geth(self.driver)
file = base64.b64decode(b64_log)
result = False
for value in args:
+12 -12
View File
@@ -263,20 +263,20 @@ class SignInView(BaseView):
# self.identifiers_button.wait_and_click(30)
if enable_notifications:
self.enable_notifications_button.wait_and_click()
# self.cancel_button.click_if_shown() # TODO: remove when issue 20806 is fixed
# for _ in range(3):
self.allow_button.click_if_shown(sec=10)
# self.cancel_button.click_if_shown() # TODO: remove when issue 20806 is fixed
# self.enable_notifications_button.click_if_shown()
# if self.chats_tab.is_element_displayed():
# break
self.cancel_button.click_if_shown() # TODO: remove when issue 20806 is fixed
for _ in range(3):
self.allow_button.click_if_shown(sec=10)
self.cancel_button.click_if_shown() # TODO: remove when issue 20806 is fixed
self.enable_notifications_button.click_if_shown()
if self.chats_tab.is_element_displayed():
break
else:
self.maybe_later_button.wait_and_click()
# for _ in range(3):
# self.cancel_button.click_if_shown() # TODO: remove when issue 20806 is fixed
# self.maybe_later_button.click_if_shown()
# if self.chats_tab.is_element_displayed():
# break
for _ in range(3):
self.cancel_button.click_if_shown() # TODO: remove when issue 20806 is fixed
self.maybe_later_button.click_if_shown()
if self.chats_tab.is_element_displayed():
break
self.chats_tab.wait_for_visibility_of_element(30)
self.driver.info("## New multiaccount is created successfully!", device=False)
return self.get_home_view()
+2
View File
@@ -1124,6 +1124,7 @@
"help-improve-status": "Help improve Status",
"help-us-improve-status": "Help us improve Status",
"here-is-a-cat-in-a-box-instead": "Heres a cat in a box instead",
"hex": "Hex",
"hide": "Hide",
"hide-content-when-switching-apps": "Block screenshots",
"hide-content-when-switching-apps-ios": "Hide preview",
@@ -1737,6 +1738,7 @@
"not-connected-nodes": "Not connected to a status node",
"not-connected-to-peers": "Not connected to any peers",
"not-enough-assets": "Not enough assets to complete transaction",
"not-enough-assets-for-transaction": "Not enough assets for transaction",
"not-enough-assets-to-pay-gas-fees": "Not enough assets to pay gas fees",
"not-enough-liquidity": "Not enough liquidity. Lower token amount or try again later.",
"not-enough-snt": "Not enough SNT",