diff --git a/src/status_im/accounts/core.cljs b/src/status_im/accounts/core.cljs index 4578a15d49f..e62dd91cbd5 100644 --- a/src/status_im/accounts/core.cljs +++ b/src/status_im/accounts/core.cljs @@ -23,21 +23,19 @@ (defn- chat-send? [transaction] (and (seq transaction) - (not (:in-progress? transaction)) (:from-chat? transaction))) -(fx/defn continue-after-wallet-onboarding [{:keys [db] :as cofx} modal?] - (let [transaction (get-in db [:wallet :send-transaction])] - (if modal? - {:dispatch [:navigate-to-clean :wallet-send-transaction-modal]} - (if-not (chat-send? transaction) - (navigation/navigate-to-clean cofx :wallet nil) - (navigation/navigate-to-cofx cofx :wallet-send-transaction-modal nil))))) +(fx/defn continue-after-wallet-onboarding [{:keys [db] :as cofx} modal? {:keys [flow] :as screen-params}] + (if modal? + {:dispatch [:navigate-to :wallet-send-transaction-modal screen-params]} + (if (= :chat flow) + (navigation/navigate-to-cofx cofx :wallet-txn-overview screen-params) + (navigation/navigate-to-clean cofx :wallet nil)))) (fx/defn confirm-wallet-set-up - [{:keys [db] :as cofx} modal?] + [{:keys [db] :as cofx} modal? screen-params] (fx/merge cofx - (continue-after-wallet-onboarding modal?) + (continue-after-wallet-onboarding modal? screen-params) (wallet.settings.models/wallet-autoconfig-tokens) (accounts.update/account-update {:wallet-set-up-passed? true} {}))) diff --git a/src/status_im/chat/commands/impl/transactions.cljs b/src/status_im/chat/commands/impl/transactions.cljs index b512f3dc72e..098a45f83d2 100644 --- a/src/status_im/chat/commands/impl/transactions.cljs +++ b/src/status_im/chat/commands/impl/transactions.cljs @@ -235,14 +235,6 @@ (when network-mismatch? [react/text send-network])]]))) -;; TODO(goranjovic) - update to include tokens in https://github.com/status-im/status-react/issues/3233 -(defn- transaction-details [contact symbol] - (-> contact - (select-keys [:name :address :public-key]) - (assoc :symbol symbol - :gas (ethereum/estimate-gas symbol) - :from-chat? true))) - (defn- inject-network-info [parameters {:keys [db]}] (assoc parameters :network (:chain db))) @@ -303,26 +295,14 @@ {:keys [symbol decimals]} (tokens/asset-for all-tokens chain symbol-param) {:keys [value error]} (wallet.db/parse-amount amount decimals) next-view-id (if (:wallet-set-up-passed? sender-account) - :wallet-send-transaction-modal + :wallet-txn-overview :wallet-onboarding-setup)] - (fx/merge cofx - {:db (-> db - (update-in [:wallet :send-transaction] - assoc - :amount (money/formatted->internal value symbol decimals) - :amount-text amount - :amount-error error) - #_(choose-recipient.events/fill-request-details - (transaction-details recipient-contact symbol)) - (update-in [:wallet :send-transaction] - dissoc :id :password :wrong-password?)) - ;; TODO(janherich) - refactor wallet send events, updating gas price - ;; is generic thing which shouldn't be defined in wallet.send, then - ;; we can include the utility helper without running into circ-dep problem - :update-gas-price {:web3 (:web3 db) - :success-event :wallet/update-gas-price-success - :edit? false}} - (navigation/navigate-to-cofx next-view-id {})))) + (let [transaction {:amount (money/formatted->internal value symbol decimals) + :symbol symbol + :to (:address recipient-contact)}] + (navigation/navigate-to-cofx cofx next-view-id {:transaction transaction + :contact recipient-contact + :flow :chat})))) protocol/EnhancedParameters (enhance-send-parameters [_ parameters cofx] (-> parameters diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 57301539594..0b63b7adcdc 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -169,8 +169,8 @@ (handlers/register-handler-fx :accounts.ui/wallet-set-up-confirmed - (fn [cofx [_ modal?]] - (accounts/confirm-wallet-set-up cofx modal?))) + (fn [cofx [_ modal? screen-params]] + (accounts/confirm-wallet-set-up cofx modal? screen-params))) ;; accounts create module diff --git a/src/status_im/extensions/ethereum.cljs b/src/status_im/extensions/ethereum.cljs index aa029a5818b..7774e3a5bcf 100644 --- a/src/status_im/extensions/ethereum.cljs +++ b/src/status_im/extensions/ethereum.cljs @@ -70,8 +70,8 @@ (defn- execute-send-transaction [db {:keys [method params on-success on-failure] :as arguments}] (let [tx-object (assoc (select-keys arguments [:to :gas :gas-price :value :nonce]) :data (when (and method params) (abi-spec/encode method params))) - transaction (prepare-extension-transaction tx-object (:contacts/contacts db) on-success on-failure)] - (models.wallet/open-modal-wallet-for-transaction db transaction tx-object))) + transaction (prepare-extension-transaction tx-object (:contacts/contacts db) on-success on-failure)] + (models.wallet/open-modal-wallet-for-transaction db transaction))) (handlers/register-handler-fx :extensions/ethereum-send-transaction diff --git a/src/status_im/models/wallet.cljs b/src/status_im/models/wallet.cljs index be30c01c691..331aa4dad04 100644 --- a/src/status_im/models/wallet.cljs +++ b/src/status_im/models/wallet.cljs @@ -91,12 +91,12 @@ (assoc :nonce nonce)))) ;; SEND TRANSACTION -> RPC TRANSACTION -(defn prepare-send-transaction [from {:keys [amount to gas gas-price data nonce]}] +(defn prepare-send-transaction [from {:keys [amount to gas gas-price optimal-gas optimal-gas-price data nonce]}] (cond-> {:from (ethereum/normalized-address from) :to (ethereum/normalized-address to) :value (ethereum/int->hex amount) - :gas (ethereum/int->hex gas) - :gasPrice (ethereum/int->hex gas-price)} + :gas (ethereum/int->hex (or gas optimal-gas)) + :gasPrice (ethereum/int->hex (or gas-price optimal-gas-price))} data (assoc :data data) nonce @@ -145,9 +145,8 @@ (when on-error {:dispatch (conj on-error "transaction was cancelled by user")})))) -(defn prepare-unconfirmed-transaction [db now hash] - (let [transaction (get-in db [:wallet :send-transaction]) - all-tokens (:wallet/all-tokens db)] +(defn prepare-unconfirmed-transaction [db now transaction hash] + (let [all-tokens (:wallet/all-tokens db)] (let [chain (:chain db) token (tokens/symbol->token all-tokens (keyword chain) (:symbol transaction))] (-> transaction @@ -237,18 +236,14 @@ (assoc-in [:wallet :balance-loading?] true) (assoc :prices-loading? true))}))) -(defn open-modal-wallet-for-transaction [db transaction tx-object] - (let [{:keys [gas gas-price]} transaction +(defn open-modal-wallet-for-transaction [db transaction] + (let [{:keys [gas]} transaction {:keys [wallet-set-up-passed?]} (:account/account db)] - {:db (-> db - (assoc-in [:wallet :send-transaction] transaction) - (assoc-in [:wallet :send-transaction :original-gas] gas)) + {:db db :dispatch-n [[:update-wallet] - (when-not gas - [:wallet/update-estimated-gas tx-object]) - (when-not gas-price - [:wallet/update-gas-price]) [:navigate-to (if wallet-set-up-passed? - :wallet-send-modal-stack - :wallet-send-modal-stack-with-onboarding)]]})) + :wallet-send-transaction-modal + :wallet-onboarding-setup-modal) + {:transaction (assoc transaction :original-gas gas) + :flow :dapp}]]})) diff --git a/src/status_im/ui/components/colors.cljs b/src/status_im/ui/components/colors.cljs index 166db3dc75f..68ed054106e 100644 --- a/src/status_im/ui/components/colors.cljs +++ b/src/status_im/ui/components/colors.cljs @@ -31,8 +31,10 @@ ;; ACCENT BLUE (def blue "#4360df") ;; Accent blue, used as main wallet color, and ios home add button + ;; LIGHT BLUE (def blue-light "#ECEFFC") ;; Light Blue +(def blue-shadow "#8FA2EA") (def gray-background blue-light) ;; TODO (andrey) should be refactored later by Dmitry ;; RED diff --git a/src/status_im/ui/components/tooltip/styles.cljs b/src/status_im/ui/components/tooltip/styles.cljs index dd4a0e2b6fa..40d1a1bbd73 100644 --- a/src/status_im/ui/components/tooltip/styles.cljs +++ b/src/status_im/ui/components/tooltip/styles.cljs @@ -41,8 +41,8 @@ :background-color colors/gray :border-radius 8}) -(defn tooltip-text [font-size] - {:color colors/red +(defn tooltip-text [font-size text-color] + {:color (or text-color colors/red) :font-size font-size}) (def bottom-tooltip-text diff --git a/src/status_im/ui/components/tooltip/views.cljs b/src/status_im/ui/components/tooltip/views.cljs index 1cb1df95187..c0a310ef41c 100644 --- a/src/status_im/ui/components/tooltip/views.cljs +++ b/src/status_im/ui/components/tooltip/views.cljs @@ -8,14 +8,14 @@ [status-im.ui.components.colors :as colors] [reagent.core :as reagent])) -(views/defview tooltip [label & [{:keys [bottom-value color font-size] :or {bottom-value -30 color :white font-size 15}}]] +(views/defview tooltip [label & [{:keys [bottom-value color text-color font-size] :or {bottom-value -30 color :white font-size 15}}]] (views/letsubs [bottom-anim-value (animation/create-value bottom-value) opacity-value (animation/create-value 0)] {:component-did-mount (animations/animate-tooltip bottom-value bottom-anim-value opacity-value 10)} [react/view styles/tooltip-container [react/animated-view {:style (styles/tooltip-animated bottom-anim-value opacity-value)} [react/view (styles/tooltip-text-container color) - [react/text {:style (styles/tooltip-text font-size)} label]] + [react/text {:style (styles/tooltip-text font-size text-color)} label]] [vector-icons/icon :icons/tooltip-triangle {:color color :style styles/tooltip-triangle}]]])) (views/defview bottom-tooltip-info [label on-close] diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index 25df33e8a5b..cee028f241c 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -35,7 +35,6 @@ [status-im.ui.screens.wallet.request.views :refer [wallet-request-contacts-list request-transaction send-transaction-request]] [status-im.ui.screens.wallet.components.views :as wallet.components] [status-im.ui.screens.wallet.onboarding.views :as wallet.onboarding] - [status-im.ui.screens.wallet.transaction-fee.views :as wallet.transaction-fee] [status-im.ui.screens.wallet.settings.views :as wallet-settings] [status-im.ui.screens.wallet.transactions.views :as wallet-transactions] [status-im.ui.screens.wallet.transaction-sent.views :refer [transaction-sent transaction-sent-modal]] @@ -187,10 +186,7 @@ [:modal send-transaction-modal] :wallet-transaction-sent - [:modal transaction-sent-modal] - - :wallet-transaction-fee - [:modal wallet.transaction-fee/transaction-fee]} + [:modal transaction-sent-modal]} :config {:headerMode "none" :initialRouteName "wallet-send-transaction-modal"}} @@ -204,10 +200,7 @@ [:modal send-transaction-modal] :wallet-transaction-sent - [:modal transaction-sent-modal] - - :wallet-transaction-fee - [:modal wallet.transaction-fee/transaction-fee]} + [:modal transaction-sent-modal]} :config {:headerMode "none" :initialRouteName "wallet-onboarding-setup-modal"}} @@ -288,11 +281,6 @@ {:screen (nav-reagent/stack-screen (wrap-modal :wallet-settings-assets wallet-settings/manage-assets))} - :wallet-transaction-fee - {:screen (nav-reagent/stack-screen - (wrap-modal :wallet-transaction-fee - wallet.transaction-fee/transaction-fee))} - :wallet-transactions-filter {:screen (nav-reagent/stack-screen (wrap-modal :wallet-transactions-filter diff --git a/src/status_im/ui/screens/wallet/components/styles.cljs b/src/status_im/ui/screens/wallet/components/styles.cljs index f9a8742f481..1a8c78c8e4d 100644 --- a/src/status_im/ui/screens/wallet/components/styles.cljs +++ b/src/status_im/ui/screens/wallet/components/styles.cljs @@ -31,29 +31,15 @@ :justify-content :space-between :align-items :center}) -(def cartouche-text-wrapper - {:flex-direction :row - :justify-content :space-between - :padding-horizontal 15 - :padding-vertical 15}) - -(def cartouche-primary-text - {:color colors/white}) - -(def cartouche-secondary-text - {:color colors/white-transparent}) - (def text-content {:color colors/white}) (def text-secondary-content {:color colors/white-transparent}) -(def text - {:margin-right 10}) - (def text-list-primary-content - (merge text {:color colors/black})) + {:margin-right 10 + :color colors/black}) (def text-input (merge text-content @@ -64,22 +50,6 @@ :height 52 :letter-spacing -0.2})) -(def contact-code-text-input - {:text-align-vertical :top - :padding-top 16 - :padding-left 2 - :padding-right 8 - :height 72}) - -(defstyle label - {:color :white - :ios {:line-height 16} - :android {:font-size 12}}) - -(def label-transparent - (merge label - {:color colors/white-transparent})) - (def network {:color :white :font-size 13 @@ -94,27 +64,6 @@ :align-items :center :justify-content :center}) -(def asset-container - {:margin-top 8 - :height 52 - :background-color colors/white-light-transparent - :justify-content :center - :padding-left 14 - :padding-vertical 14 - :padding-right 8 - :border-radius 8}) - -(def asset-container-read-only - {:margin-top 8 - :height 52 - :border-color colors/white-light-transparent - :border-width 1 - :justify-content :center - :padding-left 14 - :padding-vertical 14 - :padding-right 8 - :border-radius 8}) - (def asset-content-container {:flex-direction :row :align-items :center @@ -139,30 +88,6 @@ (def asset-label {:margin-right 10}) -(def asset-text - {:color colors/white}) - -(defstyle container-disabled - {:border-width 1 - :border-color colors/white-light-transparent - :background-color nil - :border-radius 8}) - -(def wallet-container - {:flex-direction :row - :margin-top 8 - :height 52 - :border-width 1 - :border-color colors/white-light-transparent - :align-items :center - :padding 14 - :border-radius 8}) - -(def wallet-name - {:color :white - :font-size 15 - :letter-spacing -0.2}) - (defn participant [address?] {:color (if address? :white colors/white-transparent) :flex-shrink 1 @@ -187,27 +112,3 @@ (def recipient-no-address {:color colors/white-transparent}) - -(def wallet-value-container - {:flex 1 - :flex-direction :row}) - -(def wallet-value - {:padding-left 6 - :color colors/white-transparent - :font-size 15 - :letter-spacing -0.2}) - -(def wallet-value-amount - {:flex -1}) - -(def separator - {:height 1 - :margin-horizontal 15 - :background-color colors/white-light-transparent}) - -(def button-text - {:color :white - :font-size 15 - :letter-spacing -0.2}) - diff --git a/src/status_im/ui/screens/wallet/components/views.cljs b/src/status_im/ui/screens/wallet/components/views.cljs index f0f57d66e62..4fe3444f116 100644 --- a/src/status_im/ui/screens/wallet/components/views.cljs +++ b/src/status_im/ui/screens/wallet/components/views.cljs @@ -90,30 +90,9 @@ [vector-icons/icon icon (merge {:color :white} icon-opts)]] content)]]])]) -(defn- cartouche-primary-text [s] - [react/text {:style styles/cartouche-primary-text} - s]) - -(defn cartouche-secondary-text [s] - [react/text {:style styles/cartouche-secondary-text} - s]) - -(defn cartouche-text-content [primary secondary] - [react/view styles/cartouche-text-wrapper - [cartouche-primary-text primary] - [cartouche-secondary-text secondary]]) - -(defn view-asset [symbol] - [react/view - [react/i18n-text {:style styles/label :key :wallet-asset}] - [react/view styles/asset-container-read-only - [react/text {:style styles/asset-text} - (name symbol)]]]) - (defn- type->handler [k] - (case k - :send :wallet.send/set-symbol - :request :wallet.request/set-symbol + (if (= k :request) + :wallet.request/set-symbol (throw (str "Unknown type: " k)))) (defn- render-token [{:keys [symbol name icon decimals amount] :as token} type] @@ -262,12 +241,3 @@ [amount-input m token]] (when error [tooltip/tooltip error])]) - -(defn separator [] - [react/view styles/separator]) - -(defn button-text [label] - [react/text {:style styles/button-text - :font (if platform/android? :medium :default) - :uppercase? true} - label]) diff --git a/src/status_im/ui/screens/wallet/navigation.cljs b/src/status_im/ui/screens/wallet/navigation.cljs index dc845d414cc..14506f506df 100644 --- a/src/status_im/ui/screens/wallet/navigation.cljs +++ b/src/status_im/ui/screens/wallet/navigation.cljs @@ -24,12 +24,6 @@ (re-frame/dispatch [:update-transactions]) db) -(def transaction-send-default - (let [symbol :ETH] - {:gas (ethereum/estimate-gas symbol) - :method constants/web3-send-transaction - :symbol symbol})) - (def transaction-request-default {:symbol :ETH}) @@ -38,13 +32,4 @@ (if (= event :navigate-back) db (-> db - (assoc-in [:wallet :request-transaction] transaction-request-default) - (assoc-in [:wallet :send-transaction] transaction-send-default)))) - -(defmethod navigation/preload-data! :wallet-send-transaction - [db [event]] - (if (= event :navigate-back) - db - (do - (re-frame/dispatch [:wallet/update-gas-price]) - (assoc-in db [:wallet :send-transaction] transaction-send-default)))) + (assoc-in [:wallet :request-transaction] transaction-request-default)))) diff --git a/src/status_im/ui/screens/wallet/onboarding/views.cljs b/src/status_im/ui/screens/wallet/onboarding/views.cljs index 22e905ecf09..889e369a45d 100644 --- a/src/status_im/ui/screens/wallet/onboarding/views.cljs +++ b/src/status_im/ui/screens/wallet/onboarding/views.cljs @@ -100,23 +100,25 @@ nil]]])) (views/defview screen [] - (views/letsubs [{:keys [signing-phrase]} [:account/account]] + (views/letsubs [{:keys [signing-phrase]} [:account/account] + screen-params [:get-screen-params :wallet-onboarding-setup]] [wallet.components/simple-screen {:avoid-keyboard? true} (toolbar) (main-panel signing-phrase - (partial display-confirmation #(re-frame/dispatch [:accounts.ui/wallet-set-up-confirmed false])))])) + (partial display-confirmation #(re-frame/dispatch [:accounts.ui/wallet-set-up-confirmed false screen-params])))])) (views/defview modal [] - (views/letsubs [{:keys [signing-phrase]} [:account/account]] + (views/letsubs [{:keys [signing-phrase]} [:account/account] + screen-params [:get-screen-params :wallet-onboarding-setup-modal]] [react/view styles/modal [status-bar/status-bar {:type :modal-wallet}] [react/view components.styles/flex (toolbar) (main-panel signing-phrase - (partial display-confirmation #(re-frame/dispatch [:accounts.ui/wallet-set-up-confirmed true])))]])) + (partial display-confirmation #(re-frame/dispatch [:accounts.ui/wallet-set-up-confirmed true screen-params])))]])) (defn onboarding [] [react/view styles/root diff --git a/src/status_im/ui/screens/wallet/send/events.cljs b/src/status_im/ui/screens/wallet/send/events.cljs index 067d1ca9036..4299efc999f 100644 --- a/src/status_im/ui/screens/wallet/send/events.cljs +++ b/src/status_im/ui/screens/wallet/send/events.cljs @@ -26,21 +26,57 @@ ;;;; FX -(defn- send-ethers [params on-completed masked-password] +(defn- send-ethers [params on-completed password] (status/send-transaction (types/clj->json params) - (security/safe-unmask-data masked-password) + password on-completed)) -(defn- send-tokens [all-tokens symbol chain {:keys [from to value gas gasPrice]} on-completed masked-password] - (let [contract (:address (tokens/symbol->token all-tokens (keyword chain) symbol))] - (erc20/transfer contract from to value gas gasPrice masked-password on-completed))) +(defn- send-tokens [{:keys [from to value gas gasPrice]} token on-completed password] + (let [contract (:address token)] + (erc20/transfer contract from to value gas gasPrice password on-completed))) -(re-frame/reg-fx - ::send-transaction - (fn [[params all-tokens symbol chain on-completed masked-password]] - (case symbol - :ETH (send-ethers params on-completed masked-password) - (send-tokens all-tokens symbol chain params on-completed masked-password)))) +(defn send-transaction! [params symbol coin on-completed password] + (if (= :ETH symbol) + (send-ethers params on-completed password) + (send-tokens params coin on-completed password))) + +(handlers/register-handler-fx + :wallet/add-unconfirmed-transaction + (fn [{:keys [db now]} [_ transaction result]] + {:db (assoc-in db [:wallet :transactions result] + (models.wallet/prepare-unconfirmed-transaction db now transaction result))})) + +;;TODO(goranjovic) - fully refactor +(defn on-transaction-completed [transaction flow {:keys [public-key]} {:keys [decimals] :as coin} {:keys [result error]} in-progress?] + (let [{:keys [id method to symbol amount on-result]} transaction + amount-text (str (money/internal->formatted amount symbol decimals))] + (if error + ;; ERROR + (do (utils/show-popup (i18n/label :t/error) + (if (= (:code error) 5) + (i18n/label :t/wrong-password) + (:message error))) + (reset! in-progress? false)) + ;; RESULT + (do + (re-frame/dispatch [:wallet/add-unconfirmed-transaction transaction result]) + (if on-result + (re-frame/dispatch (conj on-result id result method)) + (when public-key + (re-frame/dispatch [:send-transaction-message public-key flow {:address to + :asset (name symbol) + :amount amount-text + :tx-hash result}]))))))) + +(defn send-transaction-wrapper [{:keys [transaction password flow all-tokens in-progress? chain contact account]}] + (let [symbol (:symbol transaction) + coin (tokens/asset-for all-tokens (keyword chain) symbol)] + (reset! in-progress? true) + (send-transaction! (models.wallet/prepare-send-transaction (:address account) transaction) + symbol + coin + #(on-transaction-completed transaction flow contact coin (types/json->clj %) in-progress?) + password))) (re-frame/reg-fx ::sign-message @@ -141,7 +177,8 @@ ::transaction-completed (fn [{:keys [db now] :as cofx} [_ {:keys [result error]}]] (let [{:keys [id method public-key to symbol amount-text on-result]} (get-in db [:wallet :send-transaction]) - db' (assoc-in db [:wallet :send-transaction :in-progress?] false)] + db' (assoc-in db [:wallet :send-transaction :in-progress?] false) + transaction (get-in db [:wallet :send-transaction])] (if error ;; ERROR (models.wallet/handle-transaction-error (assoc cofx :db db') error) @@ -151,20 +188,14 @@ (not= method constants/web3-personal-sign) (assoc-in [:wallet :transactions result] - (models.wallet/prepare-unconfirmed-transaction db now result)))} + (models.wallet/prepare-unconfirmed-transaction db now transaction result)))} (if on-result {:dispatch (conj on-result id result method)} - {:dispatch [:send-transaction-message public-key {:address to - :asset (name symbol) - :amount amount-text - :tx-hash result}]})))))) - -;; DISCARD TRANSACTION -(handlers/register-handler-fx - :wallet/discard-transaction - (fn [cofx _] - (models.wallet/discard-transaction cofx))) + {:dispatch [:send-transaction-message public-key :dapp {:address to + :asset (name symbol) + :amount amount-text + :tx-hash result}]})))))) (handlers/register-handler-fx :wallet.dapp/transaction-on-result @@ -193,7 +224,7 @@ ;;SEND TRANSACTION (= method constants/web3-send-transaction) (let [transaction (models.wallet/prepare-dapp-transaction queued-transaction (:contacts/contacts db))] - (models.wallet/open-modal-wallet-for-transaction db' transaction (first params))) + (models.wallet/open-modal-wallet-for-transaction db' transaction)) ;;SIGN MESSAGE (= method constants/web3-personal-sign) @@ -213,27 +244,15 @@ :send-transaction-message (concat [(re-frame/inject-cofx :random-id-generator)] navigation/navigation-interceptors) - (fn [{:keys [db] :as cofx} [_ chat-id params]] + (fn [{:keys [db] :as cofx} [_ chat-id flow params]] ;;NOTE(goranjovic): we want to send the payment message only when we have a whisper id ;; for the recipient, we always redirect to `:wallet-transaction-sent` even when we don't (let [send-command? (and chat-id (get-in db [:id->command ["send" #{:personal-chats}]]))] (fx/merge cofx #(when send-command? (commands-sending/send % chat-id send-command? params)) - (navigation/navigate-to-clean :wallet-transaction-sent {}))))) - -(defn set-and-validate-amount-db [db amount symbol decimals] - (let [{:keys [value error]} (wallet.db/parse-amount amount decimals)] - (-> db - (assoc-in [:wallet :send-transaction :amount] (money/formatted->internal value symbol decimals)) - (assoc-in [:wallet :send-transaction :amount-text] amount) - (assoc-in [:wallet :send-transaction :amount-error] error)))) - -(handlers/register-handler-fx - :wallet.send/set-and-validate-amount - (fn [{:keys [db]} [_ amount symbol decimals]] - {:db (set-and-validate-amount-db db amount symbol decimals)})) - + (navigation/navigate-to-clean :wallet-transaction-sent {:flow flow + :chat-id chat-id}))))) (handlers/register-handler-fx :wallet/discard-transaction-navigate-back (fn [cofx _] @@ -241,40 +260,6 @@ (navigation/navigate-back) (models.wallet/discard-transaction)))) -(defn update-gas-price - ([db edit? success-event] - {:update-gas-price {:web3 (:web3 db) - :success-event (or success-event :wallet/update-gas-price-success) - :edit? edit?}}) - ([db edit?] (update-gas-price db edit? :wallet/update-gas-price-success)) - ([db] (update-gas-price db false :wallet/update-gas-price-success))) - -(defn recalculate-gas [{:keys [db] :as fx} symbol] - (-> fx - (assoc-in [:db :wallet :send-transaction :gas] (ethereum/estimate-gas symbol)) - (merge (update-gas-price db)))) - -(handlers/register-handler-fx - :wallet/update-gas-price - (fn [{:keys [db]} [_ edit?]] - (update-gas-price db edit?))) - -(handlers/register-handler-fx - :wallet.send/set-symbol - (fn [{:keys [db]} [_ symbol]] - (let [old-symbol (get-in db [:wallet :send-transaction :symbol])] - (cond-> {:db (-> db - (assoc-in [:wallet :send-transaction :symbol] symbol) - (assoc-in [:wallet :send-transaction :amount] nil) - (assoc-in [:wallet :send-transaction :amount-text] nil) - (assoc-in [:wallet :send-transaction :asset-error] nil))} - (not= old-symbol symbol) (recalculate-gas symbol))))) - -(handlers/register-handler-fx - :wallet.send/toggle-advanced - (fn [{:keys [db]} [_ advanced?]] - {:db (assoc-in db [:wallet :send-transaction :advanced?] advanced?)})) - (handlers/register-handler-fx :wallet/cancel-entering-password (fn [{:keys [db]} _] @@ -288,41 +273,13 @@ (fn [{:keys [db]} [_ masked-password]] {:db (assoc-in db [:wallet :send-transaction :password] masked-password)})) -(handlers/register-handler-fx - :wallet.send/edit-value - (fn [cofx [_ key value]] - (models.wallet/edit-value key value cofx))) - -(handlers/register-handler-fx - :wallet.send/set-gas-details - (fn [{:keys [db]} [_ gas gas-price]] - {:db (-> db - (assoc-in [:wallet :send-transaction :gas] gas) - (assoc-in [:wallet :send-transaction :gas-price] gas-price))})) - -(handlers/register-handler-fx - :wallet.send/clear-gas - (fn [{:keys [db]}] - {:db (update db :wallet dissoc :edit)})) - -(handlers/register-handler-fx - :wallet.send/reset-gas-default - (fn [{:keys [db] :as cofx}] - (let [gas-default (if-some [original-gas (-> db :wallet :send-transaction :original-gas)] - (money/to-fixed original-gas) - (money/to-fixed - (ethereum/estimate-gas - (-> db :wallet :send-transaction :symbol))))] - (assoc (models.wallet/edit-value - :gas - gas-default - cofx) - :dispatch [:wallet/update-gas-price true])))) - (handlers/register-handler-fx :close-transaction-sent-screen - (fn [cofx [_ chat-id]] + (fn [cofx [_ chat-id flow]] (fx/merge cofx {:dispatch-later [{:ms 400 :dispatch [:check-dapps-transactions-queue]}]} - (navigation/navigate-back)))) + #(case flow + :chat (re-frame/dispatch [:chat.ui/navigate-to-chat chat-id {}]) + :dapp (re-frame/dispatch [:navigate-back]) + (re-frame/dispatch [:navigate-to :wallet {}]))))) diff --git a/src/status_im/ui/screens/wallet/send/styles.cljs b/src/status_im/ui/screens/wallet/send/styles.cljs index fb83e6d9d60..760044b08c1 100644 --- a/src/status_im/ui/screens/wallet/send/styles.cljs +++ b/src/status_im/ui/screens/wallet/send/styles.cljs @@ -1,7 +1,6 @@ (ns status-im.ui.screens.wallet.send.styles (:require-macros [status-im.utils.styles :refer [defstyle]]) (:require [status-im.ui.components.colors :as colors] - [status-im.ui.components.styles :as styles] [status-im.ui.screens.wallet.components.styles :as wallet.components.styles])) (def send-transaction-form @@ -76,61 +75,10 @@ :padding 8 :align-items :center}) -(def advanced-button-wrapper - {:align-items :center}) - -(def advanced-wrapper - {:margin-top 24 - :margin-bottom 16}) - -(def gas-container-wrapper - {:flex 1 - :flex-direction :row}) - -(def gas-input-wrapper - {:align-items :center - :justify-content :space-between - :flex-direction :row}) - -(def advanced-options-text-wrapper - {:flex 1 - :flex-direction :row - :justify-content :space-between - :margin-vertical 15}) - -(def advanced-label - {:text-align-vertical :center - :margin-left 4}) - -(def advanced-fees-text - {:color colors/white}) - -(def advanced-fees-details-text - {:color colors/white-transparent}) - -(def transaction-fee-block-wrapper - {:flex-direction :row}) - (def transaction-fee-info {:flex-direction :row :margin 15}) -(def transaction-fee-info-text-wrapper - {:flex-shrink 1}) - -(def transaction-fee-info-icon - {:border-radius 25 - :width 25 - :height 25 - :margin-right 15 - :align-items :center - :justify-content :center - :background-color colors/black-transparent}) - -(def transaction-fee-info-icon-text - {:color colors/white - :font-size 14}) - (def transaction-fee-input {:keyboard-type :numeric :auto-capitalize "none" @@ -143,27 +91,22 @@ {:background-color colors/blue :padding-vertical 8}) -(def fee-buttons - {:background-color colors/blue}) - (def password-error-tooltip {:bottom-value 15 :color colors/red-light}) -(defstyle gas-input-error-tooltip - {:android {:bottom-value -38}}) - ;; ---------------------------------------------------------------------- ;; Choose Address View ;; ---------------------------------------------------------------------- -(def centered {:justify-content :center - :align-items :center}) +(def centered + {:justify-content :center + :align-items :center}) (defstyle choose-recipient-text-input {:color colors/white :font-size 30 :font-weight :bold - :android {:width "100%"} - :ios {:min-width 236} + :android {:width "75%"} + :ios {:min-width 236} :margin-horizontal 24}) diff --git a/src/status_im/ui/screens/wallet/send/subs.cljs b/src/status_im/ui/screens/wallet/send/subs.cljs index 63bc84c4216..ddb935bde4b 100644 --- a/src/status_im/ui/screens/wallet/send/subs.cljs +++ b/src/status_im/ui/screens/wallet/send/subs.cljs @@ -1,7 +1,9 @@ (ns status-im.ui.screens.wallet.send.subs (:require [re-frame.core :as re-frame] [status-im.utils.money :as money] - [status-im.models.wallet :as models.wallet])) + [status-im.models.wallet :as models.wallet] + [status-im.utils.ethereum.core :as ethereum] + [status-im.constants :as constants])) (re-frame/reg-sub ::send-transaction @@ -9,24 +11,6 @@ (fn [wallet] (:send-transaction wallet))) -(re-frame/reg-sub - :wallet.send/symbol - :<- [::send-transaction] - (fn [send-transaction] - (:symbol send-transaction))) - -(re-frame/reg-sub - :wallet.send/advanced? - :<- [::send-transaction] - (fn [send-transaction] - (:advanced? send-transaction))) - -(re-frame/reg-sub - :wallet.send/camera-flashlight - :<- [::send-transaction] - (fn [send-transaction] - (:camera-flashlight send-transaction))) - (re-frame/reg-sub :wallet.send/wrong-password? :<- [::send-transaction] @@ -39,38 +23,15 @@ (fn [{:keys [password]}] (and (not (nil? password)) (not= password "")))) -(defn edit-or-transaction-data - "Set up edit data structure, defaulting to transaction when not available" - [transaction edit] - (cond-> edit - (not (get-in edit [:gas-price :value])) - (models.wallet/build-edit - :gas-price - (money/to-fixed (money/wei-> :gwei (:gas-price transaction)))) - - (not (get-in edit [:gas :value])) - (models.wallet/build-edit - :gas - (money/to-fixed (:gas transaction))))) - -(re-frame/reg-sub - :wallet/edit - :<- [::send-transaction] - :<- [:wallet] - (fn [[send-transaction {:keys [edit]}]] - (edit-or-transaction-data - send-transaction - edit))) - -(defn check-sufficient-funds [transaction balance symbol amount] +(defn- check-sufficient-funds [{:keys [amount symbol] :as transaction} balance] (assoc transaction :sufficient-funds? (or (nil? amount) (money/sufficient-funds? amount (get balance symbol))))) -(defn check-sufficient-gas [transaction balance symbol amount] +(defn- check-sufficient-gas [{:keys [amount symbol] :as transaction} balance] (assoc transaction :sufficient-gas? (or (nil? amount) - (let [available-ether (get balance :ETH (money/bignumber 0)) + (let [available-ether (get balance :ETH (money/bignumber 0)) available-for-gas (if (= :ETH symbol) (.minus available-ether (money/bignumber amount)) available-ether)] @@ -80,13 +41,16 @@ (money/formatted->internal :ETH 18)) (money/bignumber available-for-gas)))))) +(def transaction-send-default + {:method constants/web3-send-transaction + :symbol :ETH}) + (re-frame/reg-sub :wallet.send/transaction - :<- [::send-transaction] :<- [:balance] - (fn [[{:keys [amount symbol] :as transaction} balance]] - (-> transaction + (fn [balance] + (-> transaction-send-default (models.wallet/transform-data-for-message) (models.wallet/add-max-fee) - (check-sufficient-funds balance symbol amount) - (check-sufficient-gas balance symbol amount)))) + (check-sufficient-funds balance) + (check-sufficient-gas balance)))) diff --git a/src/status_im/ui/screens/wallet/send/views.cljs b/src/status_im/ui/screens/wallet/send/views.cljs index a8518232bd0..19676a1b956 100644 --- a/src/status_im/ui/screens/wallet/send/views.cljs +++ b/src/status_im/ui/screens/wallet/send/views.cljs @@ -2,12 +2,8 @@ (:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require [clojure.string :as string] [re-frame.core :as re-frame] - [status-im.contact.db :as contact.db] [status-im.i18n :as i18n] [status-im.ui.components.animation :as animation] - [status-im.ui.components.bottom-buttons.view :as bottom-buttons] - [status-im.ui.components.button.view :as button] - [status-im.ui.components.common.common :as common] [status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.react :as react] [status-im.ui.components.status-bar.view :as status-bar] @@ -18,62 +14,29 @@ [status-im.ui.components.list.views :as list] [status-im.ui.components.list.styles :as list.styles] [status-im.ui.screens.chat.photos :as photos] - [status-im.ui.screens.wallet.components.styles :as wallet.components.styles] - [status-im.ui.screens.wallet.components.views :as components] [status-im.ui.screens.wallet.components.views :as wallet.components] [status-im.ui.screens.wallet.db :as wallet.db] - [status-im.ui.screens.wallet.send.animations :as send.animations] [status-im.ui.screens.wallet.send.styles :as styles] [status-im.ui.screens.wallet.send.events :as events] [status-im.ui.screens.wallet.styles :as wallet.styles] - [status-im.ui.screens.wallet.main.views :as wallet.main.views] [status-im.utils.money :as money] - [status-im.utils.security :as security] [status-im.utils.utils :as utils] [status-im.utils.ethereum.tokens :as tokens] [status-im.utils.ethereum.core :as ethereum] - [status-im.transport.utils :as transport.utils] [status-im.utils.ethereum.ens :as ens] [taoensso.timbre :as log] [reagent.core :as reagent] [status-im.ui.components.colors :as colors] [status-im.ui.screens.wallet.utils :as wallet.utils])) -(defn- toolbar [modal? title] - (let [action (if modal? actions/close-white actions/back-white)] +(defn- toolbar [flow title chat-id] + (let [action (if (#{:chat :dapp} flow) actions/close-white actions/back-white)] [toolbar/toolbar {:style wallet.styles/toolbar} - [toolbar/nav-button (action (if modal? - #(re-frame/dispatch [:wallet/discard-transaction-navigate-back]) + [toolbar/nav-button (action (if (= :chat flow) + #(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id {}]) #(actions/default-handler)))] [toolbar/content-title {:color :white :font-weight :bold :font-size 17} title]])) -(defn- advanced-cartouche [native-currency {:keys [max-fee gas gas-price]}] - [react/view - [wallet.components/cartouche {:on-press #(do (re-frame/dispatch [:wallet.send/clear-gas]) - (re-frame/dispatch [:navigate-to :wallet-transaction-fee]))} - (i18n/label :t/wallet-transaction-fee) - [react/view {:style styles/advanced-options-text-wrapper - :accessibility-label :transaction-fee-button} - [react/text {:style styles/advanced-fees-text} - (str max-fee " " (wallet.utils/display-symbol native-currency))] - [react/text {:style styles/advanced-fees-details-text} - (str (money/to-fixed gas) " * " (money/to-fixed (money/wei-> :gwei gas-price)) (i18n/label :t/gwei))]]]]) - -(defn- advanced-options [advanced? native-currency transaction scroll] - [react/view {:style styles/advanced-wrapper} - [react/touchable-highlight {:on-press (fn [] - (re-frame/dispatch [:wallet.send/toggle-advanced (not advanced?)]) - (when (and scroll @scroll) (utils/set-timeout #(.scrollToEnd @scroll) 350)))} - [react/view {:style styles/advanced-button-wrapper} - [react/view {:style styles/advanced-button - :accessibility-label :advanced-button} - [react/i18n-text {:style (merge wallet.components.styles/label - styles/advanced-label) - :key :wallet-advanced}] - [vector-icons/icon (if advanced? :icons/up :icons/down) {:color :white}]]]] - (when advanced? - [advanced-cartouche native-currency transaction])]) - ;; ---------------------------------------------------------------------- ;; Step 1 choosing an address or contact to send the transaction to ;; ---------------------------------------------------------------------- @@ -106,29 +69,26 @@ :align-items :center :justify-content :center :border-bottom-width 2 - :border-bottom-color (if current? colors/white "rgba(0,0,0,0)")} - [react/text {:style {:color (if current? :white "rgba(255,255,255,0.4)") + :border-bottom-color (if current? colors/white colors/transparent)} + [react/text {:style {:color (if current? colors/white colors/white-transparent) :font-size 15}} name]]]])) tab-map)] (when-let [component-thunk (some-> tab-map tab-name :component)] [component-thunk])])))) -;; just a helper for the buttons in choose address view (defn- address-button [{:keys [disabled? on-press underlay-color background-color]} content] [react/touchable-highlight {:underlay-color underlay-color - :disabled disabled? - :on-press on-press - :style {:height 44 - :background-color background-color - :border-radius 8 - :flex 1 - :align-items :center - :justify-content :center - :margin 3}} + :disabled disabled? + :on-press on-press + :style {:height 44 + :background-color background-color + :border-radius 8 + :flex 1 + :align-items :center + :justify-content :center + :margin 3}} content]) -;; event code - (defn open-qr-scanner [chain text-input transaction] (.blur @text-input) (re-frame/dispatch [:navigate-to :recipient-qr-code @@ -136,7 +96,7 @@ (fn [qr-data] (if-let [parsed-qr-data (events/extract-qr-code-details chain qr-data)] (let [{:keys [chain-id]} parsed-qr-data - tx-data (events/qr-data->transaction-data parsed-qr-data)] + tx-data (events/qr-data->transaction-data parsed-qr-data)] (if (= chain-id (ethereum/chain-keyword->chain-id chain)) (swap! transaction merge tx-data) (utils/show-popup (i18n/label :t/error) @@ -156,7 +116,7 @@ value #(if (ethereum/address? %) (swap! transaction assoc :to-ens value :to %) - (reset! error-message "Unknown ENS name")))) + (reset! error-message (i18n/label :t/error-unknown-ens-name))))) (do (swap! transaction assoc :to value) (reset! error-message nil)))) @@ -176,34 +136,36 @@ :font-size 12 :bottom-value 15}]) [react/text-input - {:on-change-text (partial update-recipient chain transaction error-message) - :auto-focus true - :auto-capitalize :none - :auto-correct false - :placeholder "0x... or name.eth" - :placeholder-text-color "rgb(143,162,234)" - :multiline true - :max-length 84 - :ref #(reset! text-input %) - ;;NOTE(goranjovic)- :default-value instead of :value to prevent the flickering due to two way binding - :default-value (or (:to-ens @transaction) (:to @transaction)) - :selection-color colors/green - :accessibility-label :recipient-address-input - :style styles/choose-recipient-text-input}]] + {:on-change-text (partial update-recipient chain transaction error-message) + :auto-focus true + :auto-capitalize :none + :auto-correct false + :placeholder (i18n/label :t/address-or-ens-placeholder) + :placeholder-text-color colors/blue-shadow + :multiline true + :max-length 84 + :ref #(reset! text-input %) + :default-value (or (:to-ens @transaction) (:to @transaction)) + :selection-color colors/green + :accessibility-label :recipient-address-input + :style styles/choose-recipient-text-input}]] [react/view {:flex 1}] - [react/view {:flex-direction :row :padding 3} - [address-button {:underlay-color colors/white-transparent + [react/view {:flex-direction :row + :padding 3} + [address-button {:underlay-color colors/white-transparent :background-color colors/black-transparent - :on-press #(react/get-from-clipboard - (fn [addr] - (when (and addr (not (string/blank? addr))) - (swap! transaction assoc :to (string/trim addr)))))} - [react/view {:flex-direction :row + :on-press #(react/get-from-clipboard + (fn [addr] + (when (and addr (not (string/blank? addr))) + (swap! transaction assoc :to (string/trim addr)))))} + [react/view {:flex-direction :row :padding-horizontal 18} [vector-icons/icon :icons/paste {:color colors/white-transparent}] - [react/view {:flex 1 :flex-direction :row :justify-content :center} - [react/text {:style {:color colors/white - :font-size 15 + [react/view {:flex 1 + :flex-direction :row + :justify-content :center} + [react/text {:style {:color colors/white + :font-size 15 :line-height 22}} (i18n/label :t/paste)]]]] [address-button {:underlay-color colors/white-transparent @@ -219,66 +181,66 @@ (utils/show-popup (i18n/label :t/error) (i18n/label :t/camera-access-error))) 50)}]))} - [react/view {:flex-direction :row + [react/view {:flex-direction :row :padding-horizontal 18} [vector-icons/icon :icons/qr {:color colors/white-transparent}] - [react/view {:flex 1 :flex-direction :row :justify-content :center} - [react/text {:style {:color colors/white - :font-size 15 + [react/view {:flex 1 + :flex-direction :row + :justify-content :center} + [react/text {:style {:color colors/white + :font-size 15 :line-height 22}} (i18n/label :t/scan)]]]] (let [disabled? (string/blank? (:to @transaction))] - [address-button {:disabled? disabled? - :underlay-color colors/black-transparent + [address-button {:disabled? disabled? + :underlay-color colors/black-transparent :background-color (if disabled? colors/blue colors/white) :on-press #(events/chosen-recipient chain (:to @transaction) on-address (fn on-error [_] (reset! error-message (i18n/label :t/invalid-address))))} - [react/text {:style {:color (if disabled? colors/white colors/blue) - :font-size 15 + [react/text {:style {:color (if disabled? colors/white colors/blue) + :font-size 15 :line-height 22}} (i18n/label :t/next)]])]])))) -;; #(re-frame/dispatch [:wallet/fill-request-from-contact contact]) - (defn info-page [message] - [react/view {:style {:flex 1 - :align-items :center - :justify-content :center + [react/view {:style {:flex 1 + :align-items :center + :justify-content :center :background-color colors/blue}} [vector-icons/icon :icons/info {:color colors/white}] - [react/text {:style {:max-width 144 - :margin-top 15 - :color colors/white - :font-size 15 - :text-align :center + [react/text {:style {:max-width 144 + :margin-top 15 + :color colors/white + :font-size 15 + :text-align :center :line-height 22}} message]]) (defn render-contact [on-contact contact] {:pre [(fn? on-contact) (map? contact) (:address contact)]} [react/touchable-highlight {:underlay-color colors/white-transparent - :on-press #(on-contact contact)} - [react/view {:flex 1 + :on-press #(on-contact contact)} + [react/view {:flex 1 :flex-direction :row - :padding-right 23 - :padding-left 16 - :padding-top 12} + :padding-right 23 + :padding-left 16 + :padding-top 12} [react/view {:margin-top 3} [photos/photo (:photo-path contact) {:size list.styles/image-size}]] [react/view {:margin-left 16 - :flex 1} + :flex 1} [react/view {:accessibility-label :contact-name-text - :margin-bottom 2} - [react/text {:style {:font-size 15 + :margin-bottom 2} + [react/text {:style {:font-size 15 :font-weight "500" :line-height 22 - :color colors/white}} + :color colors/white}} (:name contact)]] - [react/text {:style {:font-size 15 - :line-height 22 - :color "rgba(255,255,255,0.4)"} + [react/text {:style {:font-size 15 + :line-height 22 + :color colors/white-transparent} :accessibility-label :contact-address-text} (ethereum/normalized-address (:address contact))]]]]) @@ -293,42 +255,33 @@ render-contact on-contact)}]])) -;; TODO clean up all dependencies here, leaving these in place until all behavior is verified on -;; all platforms -(defn- choose-address-contact [{:keys [modal? contacts scroll advanced? transaction network all-tokens amount-input network-status] :as opts}] - - (let [transaction (reagent/atom transaction) - chain (ethereum/network->chain-keyword network) - native-currency (tokens/native-currency chain) - {:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol) - online? (= :online network-status)] +(defn- choose-address-contact [{:keys [modal? contacts transaction network network-status]}] + (let [transaction (reagent/atom transaction) + chain (ethereum/network->chain-keyword network) + native-currency (tokens/native-currency chain) + online? (= :online network-status)] [wallet.components/simple-screen {:avoid-keyboard? (not modal?) :status-bar-type (if modal? :modal-wallet :wallet)} - [toolbar modal? (i18n/label :t/send-to)] + [toolbar :wallet (i18n/label :t/send-to) nil] [simple-tab-navigator - {:address - {:name "Address" - :component (choose-address-view - {:chain chain - :transaction transaction - :on-address - #(re-frame/dispatch [:navigate-to :wallet-choose-amount - {:transaction (swap! transaction assoc :to %) - :native-currency native-currency - :modal? modal?}])})} - :contacts - {:name "Contacts" - :component - (partial choose-contact-view - {:contacts contacts - :on-contact - (fn [{:keys [address] :as contact}] - (re-frame/dispatch - [:navigate-to :wallet-choose-amount - {:modal? modal? - :native-currency native-currency - :contact contact - :transaction (swap! transaction assoc :to address)}]))})}} + {:address {:name (i18n/label :t/wallet-address-tab-title) + :component (choose-address-view + {:chain chain + :transaction transaction + :on-address #(re-frame/dispatch [:navigate-to :wallet-choose-amount + {:transaction (swap! transaction assoc :to %) + :native-currency native-currency + :modal? modal?}])})} + :contacts {:name (i18n/label :t/wallet-contacts-tab-title) + :component (partial choose-contact-view + {:contacts contacts + :on-contact (fn [{:keys [address] :as contact}] + (re-frame/dispatch + [:navigate-to :wallet-choose-amount + {:modal? modal? + :native-currency native-currency + :contact contact + :transaction (swap! transaction assoc :to address)}]))})}} :address]])) ;; ---------------------------------------------------------------------- @@ -340,24 +293,31 @@ ;; worthy abstraction (defn- anim-ref-send "Call one of the methods in an animation ref. + Takes an animation ref (a map of keys to animation tiggering methods) + a keyword that should equal one of the keys in the map and optional args to be sent to the animation. -Takes an animation ref (a map of keys to animation tiggering methods) - -A keyword that should equal one of the keys in the map - -and optional args to be sent to the animation. - -Example: -(anim-ref-send slider-ref :open!) -(anim-ref-send slider-ref :move-top-left! 25 25)" + Example: + (anim-ref-send slider-ref :open!) + (anim-ref-send slider-ref :move-top-left! 25 25)" [anim-ref signal & args] (when anim-ref (assert (get anim-ref signal) - (str "Key " signal - " was not found in animation ref. Should be in " + (str "Key " signal " was not found in animation ref. Should be in " (pr-str (keys anim-ref))))) (some-> anim-ref (get signal) (apply args))) +(defn static-modal [children] + (let [modal-screen-bg-color (colors/alpha colors/black 0.7)] + [react/view {:style + {:position :absolute + :top 0 + :bottom 0 + :left 0 + :right 0 + :z-index 1 + :background-color modal-screen-bg-color}} + children])) + (defn- slide-up-modal "Creates a modal that slides up from the bottom of the screen and responds to a swipe down gesture to dismiss @@ -370,7 +330,7 @@ Example: Options: :anim-ref - takes a function that will be called with a map of animation methods. - :swipe-dismiss? - a boolean that determines wether the modal screen + :swipe-dismiss? - a boolean that determines whether the modal screen should be dismissed on swipe down gesture This slide-up-modal will callback the `anim-ref` fn and provides a @@ -380,7 +340,6 @@ Example: :close! - closes the modal" [{:keys [anim-ref swipe-dismiss?]} children] {:pre [(fn? anim-ref)]} - ;; Add swipe down to dissmiss (let [window-height (:height (react/get-dimensions "window") 1000) bottom-position (animation/create-value (- window-height)) @@ -388,8 +347,8 @@ Example: modal-screen-bg-color (animation/interpolate bottom-position {:inputRange [(- window-height) 0] - :outputRange ["rgba(0,0,0,0)" - "rgba(0,0,0,0.7)"]}) + :outputRange [colors/black + (colors/alpha colors/black 0.7)]}) modal-screen-top (animation/interpolate bottom-position {:inputRange [(- window-height) @@ -447,36 +406,33 @@ Example: (defn- custom-gas-panel-action [{:keys [label active on-press icon background-color]} child] {:pre [label (boolean? active) on-press icon background-color]} - [react/view {:style {:flex-direction :row + [react/view {:style {:flex-direction :row :padding-horizontal 22 - :padding-vertical 11 - :align-items :center}} + :padding-vertical 11 + :align-items :center}} [react/touchable-highlight {:disabled active :on-press on-press} - [react/animated-view {:style {:border-radius 21 - :width 40 - :height 40 - :justify-content :center - :align-items :center + [react/animated-view {:style {:border-radius 21 + :width 40 + :height 40 + :justify-content :center + :align-items :center :background-color background-color}} [vector-icons/icon icon {:color (if active colors/white colors/gray)}]]] [react/touchable-highlight {:disabled active :on-press on-press - :style {:flex 1}} - [react/text {:style {:color colors/black - :font-size 17 + :style {:flex 1}} + [react/text {:style {:color colors/black + :font-size 17 :padding-left 17 - :line-height 40}} + :line-height 40}} label]] child]) (defn- custom-gas-edit - [{:keys [on-gas-input-change - on-gas-price-input-change - gas-input - gas-price-input]}] + [_opts] (let [gas-error (reagent/atom nil) gas-price-error (reagent/atom nil)] (fn [{:keys [on-gas-input-change @@ -484,69 +440,68 @@ Example: gas-input gas-price-input]}] [react/view {:style {:padding-horizontal 22 - :padding-vertical 11}} - [react/text "Gas price"] + :padding-vertical 11}} + [react/text (i18n/label :t/gas-price)] (when @gas-price-error [react/view {:style {:z-index 100}} [tooltip/tooltip @gas-price-error {:color colors/blue-light :font-size 12 :bottom-value -3}]]) - [react/view {:style {:border-radius 8 - :background-color colors/gray-light - :padding-vertical 16 + [react/view {:style {:border-radius 8 + :background-color colors/gray-light + :padding-vertical 16 :padding-horizontal 16 - :flex-direction :row - :align-items :flex-end - :margin-vertical 7}} - [react/text-input {:keyboard-type :numeric - :placeholder "0" + :flex-direction :row + :align-items :center + :margin-vertical 7}} + [react/text-input {:keyboard-type :numeric + :placeholder "0" :on-change-text (fn [x] (if-not (money/bignumber x) - (reset! gas-price-error "Invalid number format") + (reset! gas-price-error (i18n/label :t/invalid-number-format)) (reset! gas-price-error nil)) (on-gas-price-input-change x)) - :value gas-price-input - :style {:font-size 15 - :flex 1}}] - [react/text "Gwei"]] + :default-value gas-price-input + :style {:font-size 15 + :flex 1}}] + [react/text (i18n/label :t/gwei)]] [react/text {:style {:color colors/gray :font-size 12}} - "Gas price is the amount you are willing to pay per unit of gas. Increasing this price may help your transaction get processed faster."] - [react/text {:style {:margin-top 22}} "Gas limit"] + (i18n/label :t/gas-cost-explanation)] + [react/text {:style {:margin-top 22}} (i18n/label :t/gas-limit)] (when @gas-error [react/view {:style {:z-index 100}} [tooltip/tooltip @gas-error {:color colors/blue-light :font-size 12 :bottom-value -3}]]) - [react/view {:style {:border-radius 8 - :background-color colors/gray-light - :padding-vertical 16 + [react/view {:style {:border-radius 8 + :background-color colors/gray-light + :padding-vertical 16 :padding-horizontal 16 - :flex-direction :row - :align-items :flex-end - :margin-vertical 7}} - [react/text-input {:keyboard-type :numeric - :placeholder "0" - :on-change-text - (fn [x] - (if-not (money/bignumber x) - (reset! gas-error "Invalid number format") - (reset! gas-error nil)) - (on-gas-input-change x)) - :value gas-input - :style {:font-size 15 - :flex 1}}]] - [react/text {:style {:color colors/gray + :flex-direction :row + :align-items :flex-end + :margin-vertical 7}} + [react/text-input {:keyboard-type :numeric + :placeholder "0" + :on-change-text (fn [x] + (if-not (money/bignumber x) + (reset! gas-error (i18n/label :t/invalid-number-format)) + (reset! gas-error nil)) + (on-gas-input-change x)) + :default-value gas-input + :style {:font-size 15 + :flex 1}}]] + [react/text {:style {:color colors/gray :font-size 12}} - "Gas limit is the maximum units of gas you're willing to spend on this transaction."]]))) + (i18n/label :t/gas-limit-explanation)]]))) (defn custom-gas-derived-state [{:keys [gas-input gas-price-input custom-open?]} {:keys [custom-gas custom-gas-price optimal-gas optimal-gas-price gas-gas-price->fiat - fiat-currency] :as opts}] + fiat-currency]}] (let [custom-input-gas (or (when (not (string/blank? gas-input)) (money/bignumber gas-input)) @@ -583,8 +538,8 @@ Example: gas-gas-price->fiat on-submit] :as opts}] {:pre [optimal-gas optimal-gas-price gas-gas-price->fiat on-submit]} (let [custom-open? (and custom-gas custom-gas-price) - state-atom (reagent.core/atom {:custom-open? (boolean custom-open?) - :gas-input nil + state-atom (reagent.core/atom {:custom-open? (boolean custom-open?) + :gas-input nil :gas-price-input nil}) ;; slider animations @@ -595,12 +550,12 @@ Example: optimal-button-bg-color (animation/interpolate slider-height - {:inputRange [0 200 290] + {:inputRange [0 200 290] :outputRange [colors/blue colors/gray-light colors/gray-light]}) custom-button-bg-color (animation/interpolate slider-height - {:inputRange [0 200 290] + {:inputRange [0 200 290] :outputRange [colors/gray-light colors/blue colors/blue]}) open-slider! #(do @@ -616,137 +571,133 @@ Example: gas-input-value gas-map-for-submit]} (custom-gas-derived-state @state-atom opts)] - [react/view {:style {:background-color colors/white - :border-top-left-radius 8 + [react/view {:style {:background-color colors/white + :border-top-left-radius 8 :border-top-right-radius 8}} [react/view {:style {:justify-content :center - :padding-top 22 - :padding-bottom 7}} + :padding-top 22 + :padding-bottom 7}} [react/text {:style {:color colors/black - :font-size 22 + :font-size 22 :line-height 28 :font-weight :bold - :text-align :center}} - "Network fee settings"] + :text-align :center}} + (i18n/label :t/network-fee-settings)] [react/text - {:style {:color colors/gray - :font-size 15 - :line-height 22 - :text-align :center + {:style {:color colors/gray + :font-size 15 + :line-height 22 + :text-align :center :padding-horizontal 45 - :padding-vertical 8}} - "This fee, known as gas is paid directly to the Ethereum network. Status does not collect any of these funds"]] + :padding-vertical 8}} + (i18n/label :t/network-fee-explanation)]] [react/view {:style {:border-top-width 1 :border-top-color colors/black-transparent - :padding-top 11 - :padding-bottom 7}} - (custom-gas-panel-action - {:icon :icons/time - :label "Optimal" - :on-press close-slider! - :background-color optimal-button-bg-color - :active (not (:custom-open? @state-atom))} - [react/text {:style {:color colors/gray - :font-size 17 - :padding-left 17 - :line-height 20}} - optimal-fiat-price]) - (custom-gas-panel-action - {:icon :icons/sliders - :label "Custom" - :on-press open-slider! - :background-color custom-button-bg-color - :active (:custom-open? @state-atom)} - [react/text {:style {:color colors/gray - :font-size 17 - :padding-left 17 - :line-height 20 - :text-align :center - :min-width 60}} - custom-fiat-price]) + :padding-top 11 + :padding-bottom 7}} + (custom-gas-panel-action {:icon :icons/time + :label (i18n/label :t/optimal-gas-option) + :on-press close-slider! + :background-color optimal-button-bg-color + :active (not (:custom-open? @state-atom))} + [react/text {:style {:color colors/gray + :font-size 17 + :padding-left 17 + :line-height 20}} + optimal-fiat-price]) + (custom-gas-panel-action {:icon :icons/sliders + :label (i18n/label :t/custom-gas-option) + :on-press open-slider! + :background-color custom-button-bg-color + :active (:custom-open? @state-atom)} + [react/text {:style {:color colors/gray + :font-size 17 + :padding-left 17 + :line-height 20 + :text-align :center + :min-width 60}} + custom-fiat-price]) [react/animated-view {:style {:background-color colors/white - :height slider-height - :overflow :hidden}} + :height slider-height + :overflow :hidden}} [custom-gas-edit - {:on-gas-price-input-change - #(when (money/bignumber %) - (swap! state-atom assoc :gas-price-input %)) - :on-gas-input-change - #(when (money/bignumber %) - (swap! state-atom assoc :gas-input %)) - :gas-price-input gas-price-input-value - :gas-input gas-input-value}]] - [react/view {:style {:flex-direction :row - :justify-content :center + {:on-gas-price-input-change #(when (money/bignumber %) + (swap! state-atom assoc :gas-price-input %)) + :on-gas-input-change #(when (money/bignumber %) + (swap! state-atom assoc :gas-input %)) + :gas-price-input gas-price-input-value + :gas-input gas-input-value}]] + [react/view {:style {:flex-direction :row + :justify-content :center :padding-vertical 16}} [react/touchable-highlight {:on-press #(on-submit gas-map-for-submit) - :style {:padding-horizontal 39 - :padding-vertical 12 - :border-radius 8 - :background-color colors/blue-light}} - [react/text {:style {:font-size 15 + :style {:padding-horizontal 39 + :padding-vertical 12 + :border-radius 8 + :background-color colors/blue-light}} + [react/text {:style {:font-size 15 :line-height 22 - :color colors/blue}} - "Update"]]]]])))) + :color colors/blue}} + (i18n/label :t/update)]]]]])))) ;; Choosing the asset (defn white-toolbar [modal? title] (let [action (if modal? actions/close actions/back)] - [toolbar/toolbar {:style {:background-color colors/white + [toolbar/toolbar {:style {:background-color colors/white :border-bottom-width 1 :border-bottom-color colors/black-transparent}} [toolbar/nav-button (action (if modal? #(re-frame/dispatch [:wallet/discard-transaction-navigate-back]) #(actions/default-handler)))] - [toolbar/content-title {:color colors/black :font-size 17 :font-weight :bold} title]])) + [toolbar/content-title {:color colors/black + :font-size 17 + :font-weight :bold} title]])) -(defn- render-token-item [{:keys [symbol name icon decimals amount] :as token}] +(defn- render-token-item [{:keys [name icon decimals amount] :as coin}] [list/item [list/item-image icon] [list/item-content [react/text {:style {:margin-right 10, :color colors/black}} name] [list/item-secondary (str (wallet.utils/format-amount amount decimals) " " - (wallet.utils/display-symbol token))]]]) + (wallet.utils/display-symbol coin))]]]) -;; TODO parameterize this with on-asset handler (defview choose-asset [] (letsubs [assets [:wallet/transferrable-assets-with-amount] {:keys [on-asset]} [:get-screen-params :wallet-choose-asset]] - [react/keyboard-avoiding-view {:flex 1 :background-color colors/white} + [react/keyboard-avoiding-view {:flex 1 + :background-color colors/white} [status-bar/status-bar {:type :modal-white}] - [white-toolbar false "Choose asset" #_(i18n/label :t/wallet-assets)] + [white-toolbar false (i18n/label :t/choose-asset)] [react/view {:style (assoc components.styles/flex :background-color :white)} [list/flat-list {:default-separator? false ;true :data assets :key-fn (comp str :symbol) :render-fn #(do - [react/touchable-highlight {:on-press - (fn [] - (on-asset %)) + [react/touchable-highlight {:on-press (fn [] (on-asset %)) :underlay-color colors/black-transparent} (render-token-item %)])}]]])) (defn show-current-asset [{:keys [name icon decimals amount] :as token}] - [react/view {:style {:flex-direction :row, - :justify-content :center + [react/view {:style {:flex-direction :row, + :justify-content :center :padding-horizontal 21 - :padding-vertical 12}} + :padding-vertical 12}} [list/item-image icon] [react/view {:margin-horizontal 9 - :flex 1} + :flex 1} [list/item-content [react/text {:style {:margin-right 10, - :font-weight "500" - :font-size 15 - :color colors/white}} name] - [react/text {:style {:font-size 14 - :padding-top 4 - :color "rgba(255,255,255,0.4)"} - :ellipsize-mode :middle + :font-weight "500" + :font-size 15 + :color colors/white}} name] + [react/text {:style {:font-size 14 + :padding-top 4 + :color colors/white-transparent} + :ellipsize-mode :middle :number-of-lines 1} (str (wallet.utils/format-amount amount decimals) " " @@ -769,24 +720,21 @@ Example: (ethereum/network->chain-keyword network) token-symbol))) -(defn create-initial-state [{:keys [symbol decimals] :as token} amount] - {:input-amount (when amount - (when-let [amount' (money/internal->formatted amount symbol decimals)] - (str amount'))) - :inverted false - :edit-gas false +(defn create-initial-state [{:keys [symbol decimals]} amount] + {:input-amount (when amount + (when-let [amount' (money/internal->formatted amount symbol decimals)] + (str amount'))) + :inverted false + :edit-gas false :error-message nil}) -(defn toggle-edit-gas [state] - (swap! state update :edit-gas not)) - -(defn input-currency-symbol [{:keys [inverted] :as state} {:keys [symbol] :as token} {:keys [code] :as fiat-currency}] +(defn input-currency-symbol [{:keys [inverted] :as state} {:keys [symbol] :as coin} {:keys [code]}] {:pre [(boolean? inverted) (keyword? symbol) (string? code)]} - (if-not (:inverted state) (name (:symbol token)) code)) + (if-not (:inverted state) (wallet.utils/display-symbol coin) code)) -(defn converted-currency-symbol [{:keys [inverted] :as state} {:keys [symbol] :as token} {:keys [code] :as fiat-currency}] +(defn converted-currency-symbol [{:keys [inverted] :as state} {:keys [symbol] :as coin} {:keys [code]}] {:pre [(boolean? inverted) (keyword? symbol) (string? code)]} - (if (:inverted state) (name (:symbol token)) code)) + (if (:inverted state) (wallet.utils/display-symbol coin) code)) (defn token->fiat-conversion [prices token fiat-currency value] {:pre [(map? prices) (map? token) (map? fiat-currency) value]} @@ -808,7 +756,6 @@ Example: (defn valid-input-amount? [input-amount] (and (not (string/blank? input-amount)) - ;; we are ignoring precision for this case (not (:error (wallet.db/parse-amount input-amount 100))))) (defn converted-currency-amount [{:keys [input-amount inverted]} token fiat-currency prices] @@ -836,7 +783,7 @@ Example: (defn update-input-errors [{:keys [input-amount inverted] :as state} token fiat-currency prices] {:pre [(map? state) (map? token) (map? fiat-currency) (map? prices)]} - (let [{:keys [value error]} + (let [{:keys [_value error]} (wallet.db/parse-amount input-amount (if inverted 2 (:decimals token)))] (if-let [error-msg @@ -844,7 +791,7 @@ Example: error error (not (money/sufficient-funds? (current-token-input-amount state token fiat-currency prices) (:amount token))) - "Insufficient funds" + (i18n/label :t/wallet-insufficient-funds) :else nil)] (assoc state :error-message error-msg) state))) @@ -858,8 +805,9 @@ Example: (update-input-errors token fiat-currency prices))) (defn max-fee [{:keys [gas gas-price]}] - {:pre [gas gas-price]} - (money/wei->ether (.times gas gas-price))) + (if (and gas gas-price) + (money/wei->ether (.times gas gas-price)) + 0)) (defn network-fees [prices token fiat-currency gas-ether-price] (some-> (token->fiat-conversion prices token fiat-currency gas-ether-price) @@ -873,50 +821,50 @@ Example: (cb {:optimal-gas (ethereum/estimate-gas symbol) :optimal-gas-price gas-price}))))) -(defn optimal-gas-present? [{:keys [optimal-gas optimal-gas-price] :as transaction}] +(defn optimal-gas-present? [{:keys [optimal-gas optimal-gas-price]}] (and optimal-gas optimal-gas-price)) -(defn current-gas [{:keys [gas gas-price optimal-gas optimal-gas-price] :as transaction}] +(defn current-gas [{:keys [gas gas-price optimal-gas optimal-gas-price]}] {:gas (or gas optimal-gas) :gas-price (or gas-price optimal-gas-price)}) -;; TODO derived state +(defn refresh-optimal-gas [symbol tx-atom] + (fetch-optimal-gas symbol + (fn [res] + (swap! tx-atom merge res)))) -;; !!! only send gas and gas-price in a transaction if they are custom gas prices!!! -(defn choose-amount-token-helper [{:keys [balance network prices fiat-currency +(defn choose-amount-token-helper [{:keys [network native-currency all-tokens - modal? contact transaction]}] {:pre [(map? native-currency)]} - (let [tx-atom (reagent/atom transaction) - token (or (fetch-token all-tokens network (:symbol transaction)) - native-currency) - state-atom (reagent/atom (create-initial-state token (:amount transaction))) + (let [tx-atom (reagent/atom transaction) + coin (or (fetch-token all-tokens network (:symbol transaction)) + native-currency) + state-atom (reagent/atom (create-initial-state coin (:amount transaction))) network-fees-modal-ref (atom nil) - open-network-fees! #(anim-ref-send @network-fees-modal-ref :open!) - close-network-fees! #(anim-ref-send @network-fees-modal-ref :close!)] - ;; initialize the starting gas price + open-network-fees! #(anim-ref-send @network-fees-modal-ref :open!) + close-network-fees! #(anim-ref-send @network-fees-modal-ref :close!)] (when-not (optimal-gas-present? transaction) - (fetch-optimal-gas - (some :symbol [transaction native-currency]) - #(swap! tx-atom merge %))) + (refresh-optimal-gas + (some :symbol [transaction native-currency]) tx-atom)) (fn [{:keys [balance network prices fiat-currency native-currency all-tokens modal?]}] - (let [symbol (some :symbol [@tx-atom native-currency]) - token (-> (tokens/asset-for all-tokens (ethereum/network->chain-keyword network) symbol) + (let [symbol (some :symbol [@tx-atom native-currency]) + coin (-> (tokens/asset-for all-tokens (ethereum/network->chain-keyword network) symbol) (assoc :amount (get balance symbol (money/bignumber 0)))) gas-gas-price->fiat (fn [gas-map] - (network-fees prices token fiat-currency (max-fee gas-map)))] + (network-fees prices coin fiat-currency (max-fee gas-map))) + update-amount-field #(swap! state-atom update-input-amount % coin fiat-currency prices)] [wallet.components/simple-screen {:avoid-keyboard? (not modal?) :status-bar-type (if modal? :modal-wallet :wallet)} - [toolbar modal? "Send amount"] + [toolbar :wallet (i18n/label :t/send-amount) nil] (if (empty? balance) - (info-page "You don't have any assets yet") + (info-page (i18n/label :t/wallet-no-assets-enabled)) (let [{:keys [error-message input-amount] :as state} @state-atom - input-symbol (input-currency-symbol state token fiat-currency) - converted-phrase (converted-currency-phrase state token fiat-currency prices)] + input-symbol (input-currency-symbol state coin fiat-currency) + converted-phrase (converted-currency-phrase state coin fiat-currency prices)] [react/view {:flex 1} ;; network fees modal (when (optimal-gas-present? @tx-atom) @@ -931,150 +879,310 @@ Example: (when (and gas gas-price) (swap! tx-atom assoc :gas gas :gas-price gas-price)) (close-network-fees!))))]]) - [react/touchable-highlight {:style {:background-color colors/black-transparent} - :on-press #(re-frame/dispatch - [:navigate-to - :wallet-choose-asset - {:on-asset (fn [{:keys [symbol]}] - (when symbol - (swap! tx-atom assoc :symbol symbol)) - (re-frame/dispatch [:navigate-back]))}]) + [react/touchable-highlight {:style {:background-color colors/black-transparent} + :on-press #(re-frame/dispatch + [:navigate-to :wallet-choose-asset + {:on-asset (fn [{:keys [symbol]}] + (when symbol + (if-not (= symbol (:symbol @tx-atom)) + (update-amount-field nil)) + (swap! tx-atom assoc :symbol symbol) + (refresh-optimal-gas symbol tx-atom)) + (re-frame/dispatch [:navigate-back]))}]) :underlay-color colors/white-transparent} - [show-current-asset token]] + [show-current-asset coin]] [react/view {:flex 1} [react/view {:flex 1}] [react/view {:justify-content :center - :align-items :flex-end - :flex-direction :row} + :align-items :center + :flex-direction :row} (when error-message [tooltip/tooltip error-message {:color colors/white :font-size 12 :bottom-value 15}]) [react/text-input - {:on-change-text #(swap! state-atom update-input-amount % token fiat-currency prices) - :keyboard-type :numeric - :accessibility-label :amount-input - :auto-focus true - :auto-capitalize :none - :auto-correct false - :placeholder "0" - :placeholder-text-color "rgb(143,162,234)" - :multiline true - :max-length 42 - :value input-amount - :selection-color colors/green - :style {:color colors/white - :font-size 30 - :font-weight :bold - :padding-horizontal 10 - :max-width 290}}] - [react/text {:style {:color (if (not (string/blank? input-amount)) - colors/white - "rgb(143,162,234)") - :font-size 30 + {:on-change-text update-amount-field + :keyboard-type :numeric + :accessibility-label :amount-input + :auto-focus true + :auto-capitalize :none + :auto-correct false + :placeholder "0" + :placeholder-text-color colors/blue-shadow + :multiline true + :max-length 20 + :default-value input-amount + :selection-color colors/green + :style {:color colors/white + :font-size 30 + :font-weight :bold + :padding-horizontal 10 + :max-width 290}}] + [react/text {:style {:color (if (not (string/blank? input-amount)) + colors/white + colors/blue-shadow) + :font-size 30 :font-weight :bold}} input-symbol]] [react/view {} - [react/text {:style {:text-align :center - :margin-top 16 - :font-size 15 + [react/text {:style {:text-align :center + :margin-top 16 + :font-size 15 :line-height 22 - :color "rgb(143,162,234)"}} + :color colors/blue-shadow}} converted-phrase]] - [react/view {:justify-content :center :flex-direction :row} + [react/view {:justify-content :center + :flex-direction :row} [react/touchable-highlight {:on-press open-network-fees! - :style {:background-color colors/black-transparent - :padding-horizontal 13 - :padding-vertical 7 - :margin-top 1 - :border-radius 8 - :opacity (if (valid-input-amount? input-amount) 1 0)}} - [react/text {:style {:color colors/white - :font-size 15 + :style {:background-color colors/black-transparent + :padding-horizontal 13 + :padding-vertical 7 + :margin-top 1 + :border-radius 8 + :opacity (if (valid-input-amount? input-amount) 1 0)}} + [react/text {:style {:color colors/white + :font-size 15 :line-height 22}} - - (str "network fee ~ " - (when (optimal-gas-present? @tx-atom) - (gas-gas-price->fiat (current-gas @tx-atom))) - " " - (:code fiat-currency))]]] + (i18n/label :t/network-fee-amount {:amount (when (optimal-gas-present? @tx-atom) + (or (gas-gas-price->fiat (current-gas @tx-atom)) "0")) + :currency (:code fiat-currency)})]]] [react/view {:flex 1}] - [react/view {:flex-direction :row :padding 3} - [address-button {:underlay-color colors/white-transparent + [react/view {:flex-direction :row + :padding 3} + [address-button {:underlay-color colors/white-transparent :background-color colors/black-transparent - :on-press #(swap! state-atom update :inverted not)} + :on-press #(swap! state-atom update :inverted not)} [react/view {:flex-direction :row} [react/text {:style {:color colors/white - :font-size 15 - :line-height 22 + :font-size 15 + :line-height 22 :padding-right 10}} (:code fiat-currency)] [vector-icons/icon :icons/change {:color colors/white-transparent}] - [react/text {:style {:color colors/white - :font-size 15 - :line-height 22 + [react/text {:style {:color colors/white + :font-size 15 + :line-height 22 :padding-left 11}} - (name symbol)]]] + (wallet.utils/display-symbol coin)]]] (let [disabled? (string/blank? input-amount)] - [address-button {:disabled? disabled? - :underlay-color colors/black-transparent + [address-button {:disabled? disabled? + :underlay-color colors/black-transparent :background-color (if disabled? colors/blue colors/white) - :token token - :on-press - #(re-frame/dispatch [:navigate-to - :wallet-txn-overview - {:modal? modal? - :contact contact - :transaction - (assoc - @tx-atom - :amount - (money/formatted->internal - (money/bignumber input-amount) - (:symbol token) - (:decimals token)))}])} - [react/text {:style {:color (if disabled? colors/white colors/blue) - :font-size 15 + :token coin + :on-press #(re-frame/dispatch [:navigate-to :wallet-txn-overview + {:modal? modal? + :contact contact + :transaction (assoc @tx-atom + :amount (money/formatted->internal + (money/bignumber input-amount) + (:symbol coin) + (:decimals coin)))}])} + [react/text {:style {:color (if disabled? colors/white colors/blue) + :font-size 15 :line-height 22}} (i18n/label :t/next)]])]]]))])))) (defview choose-amount-token [] (letsubs [{:keys [transaction modal? contact native-currency]} [:get-screen-params :wallet-choose-amount] - balance [:balance] - prices [:prices] - network [:account/network] - all-tokens [:wallet/all-tokens] + balance [:balance] + prices [:prices] + network [:account/network] + all-tokens [:wallet/all-tokens] fiat-currency [:wallet/currency]] - [choose-amount-token-helper {:balance balance - :network network - :all-tokens all-tokens - :modal? modal? - :prices prices + [choose-amount-token-helper {:balance balance + :network network + :all-tokens all-tokens + :modal? modal? + :prices prices :native-currency native-currency - :fiat-currency fiat-currency - :contact contact - :transaction transaction}])) + :fiat-currency fiat-currency + :contact contact + :transaction transaction}])) ;; ---------------------------------------------------------------------- ;; Step 3 Final Overview ;; ---------------------------------------------------------------------- ;; TODOS -;; wire in final send transation ;; look at duplicate logic and create a model so that we can simply execute methods against that model -;; instead of peicing together various information for each individual computation - -(defn transaction-overview [{:keys [modal? transaction contact token native-currency - fiat-currency prices] :as data}] - (let [tx-atom (atom transaction) +;; instead of piecing together various information for each individual computation + +(def signing-popup + {:background-color colors/white + :border-top-left-radius 8 + :border-top-right-radius 8 + :position :absolute + :left 0 + :right 0 + :bottom 0}) + +(defn confirm-modal [signing? {:keys [transaction total-amount gas-amount native-currency fiat-currency total-fiat]}] + [react/view {:style signing-popup} + [react/text {:style {:color colors/black + :font-size 15 + :line-height 22 + :margin-top 23 + :text-align :center}} + (i18n/label :t/total)] + [react/text {:style {:color colors/black + :margin-top 4 + :font-weight :bold + :font-size 22 + :line-height 28 + :text-align :center}} + (str total-amount " " (name (:symbol transaction)))] + (when-not (= :ETH (:symbol transaction)) + [react/text {:style {:color colors/black + :margin-top 13 + :font-weight :bold + :font-size 22 + :line-height 28 + :text-align :center}} + (str gas-amount " " (name (:symbol native-currency)))]) + [react/text {:style {:color colors/gray + :text-align :center + :margin-top 3 + :line-height 21 + :font-size 15}} + (str "~ " (:symbol fiat-currency "$") total-fiat)] + [react/view {:style {:flex-direction :row + :justify-content :center + :padding-top 16 + :padding-bottom 24}} + [react/touchable-highlight + {:on-press #(reset! signing? true) + :style {:padding-horizontal 39 + :padding-vertical 12 + :border-radius 8 + :background-color colors/blue-light}} + [react/text {:style {:font-size 15 + :line-height 22 + :color colors/blue}} + (i18n/label :t/confirm)]]]]) + +(defn- phrase-word [word] + [react/text {:style {:color colors/blue + :font-size 15 + :line-height 22 + :font-weight "500" + :width "33%" + :text-align :center}} + word]) + +(defn- phrase-separator [] + [react/view {:style {:height "100%" + :width 1 + :background-color colors/gray-light}}]) + +(defview sign-modal [account {:keys [transaction contact total-amount gas-amount native-currency fiat-currency + total-fiat all-tokens chain flow]}] + (letsubs [password (reagent/atom nil) + in-progress? (reagent/atom nil)] + (let [phrase (string/split (:signing-phrase account) #" ")] + [react/view {:style {:position :absolute + :left 0 + :right 0 + :bottom 0}} + [tooltip/tooltip (i18n/label :t/wallet-passphrase-reminder) + {:bottom-value 12 + :color colors/blue + :text-color colors/white}] + [react/view {:style {:background-color colors/white + :border-top-left-radius 8 + :border-top-right-radius 8}} + [react/view {:flex 1 + :height 46 + :margin-top 18 + :flex-direction :row + :align-items :center + :margin-horizontal "15%" + :border-width 1 + :border-color colors/gray-light + :border-radius 218} + [phrase-word (first phrase)] + [phrase-separator] + [phrase-word (second phrase)] + [phrase-separator] + [phrase-word (last phrase)]] + [react/text {:style {:color colors/black + :margin-top 13 + :font-weight :bold + :font-size 22 + :line-height 28 + :text-align :center}} + (str "Send" " " total-amount " " (name (:symbol transaction)))] + (when-not (= :ETH (:symbol transaction)) + [react/text {:style {:color colors/black + :margin-top 13 + :font-weight :bold + :font-size 22 + :line-height 28 + :text-align :center}} + (str "Send" " " gas-amount " " (name (:symbol native-currency)))]) + [react/text {:style {:color colors/gray + :text-align :center + :margin-top 3 + :line-height 21 + :font-size 15}} + (str "~ " (:symbol fiat-currency "$") total-fiat)] + [react/text-input + {:auto-focus true + :secure-text-entry true + :placeholder (i18n/label :t/enter-your-login-password) + :placeholder-text-color colors/gray + :on-change-text #(reset! password %) + :style {:flex 1 + :margin-top 15 + :margin-horizontal 15 + :padding 14 + :padding-bottom 18 + :background-color colors/gray-lighter + :border-radius 8 + :font-size 15 + :letter-spacing -0.2 + :height 52} + :accessibility-label :enter-password-input + :auto-capitalize :none}] + [react/view {:style {:flex-direction :row + :justify-content :center + :padding-top 16 + :padding-bottom 24}} + [react/touchable-highlight + {:on-press #(events/send-transaction-wrapper {:transaction transaction + :password @password + :flow flow + :all-tokens all-tokens + :in-progress? in-progress? + :chain chain + :contact contact + :account account}) + :disabled @in-progress? + :style {:padding-horizontal 39 + :padding-vertical 12 + :border-radius 8 + :background-color colors/blue-light}} + [react/text {:style {:font-size 15 + :line-height 22 + :color colors/blue}} + (i18n/label :t/send)]]]]]))) + +(defview confirm-and-sign [params] + (letsubs [signing? (reagent/atom false) + account [:account/account]] + (if-not @signing? + [confirm-modal signing? params] + [sign-modal account params]))) + +(defn transaction-overview [{:keys [flow transaction contact token native-currency + fiat-currency prices all-tokens chain]}] + (let [tx-atom (reagent/atom transaction) network-fees-modal-ref (atom nil) - open-network-fees! #(anim-ref-send @network-fees-modal-ref :open!) - close-network-fees! #(anim-ref-send @network-fees-modal-ref :close!)] + open-network-fees! #(anim-ref-send @network-fees-modal-ref :open!) + close-network-fees! #(anim-ref-send @network-fees-modal-ref :close!) + modal? (= :dapp flow)] (when-not (optimal-gas-present? transaction) - (fetch-optimal-gas - (some :symbol [transaction native-currency]) - #(swap! tx-atom merge %))) + (refresh-optimal-gas (some :symbol [transaction native-currency]) tx-atom)) (fn [] (let [transaction @tx-atom gas-gas-price->fiat @@ -1091,28 +1199,29 @@ Example: (:symbol token) (:decimals token)) amount-str (str formatted-amount - " " (name (:symbol token))) + " " (wallet.utils/display-symbol token)) fiat-amount (some-> (token->fiat-conversion prices token fiat-currency formatted-amount) (money/with-precision 2)) - total-eth (some-> (.add (money/bignumber formatted-amount) network-fee-eth) - (money/with-precision 11)) - - total-fiat (some-> (token->fiat-conversion prices token fiat-currency total-eth) - (money/with-precision 2)) + total-amount (some-> (if (= :ETH (:symbol transaction)) + (.add (money/bignumber formatted-amount) network-fee-eth) + (money/bignumber formatted-amount)) + (money/with-precision (:decimals token))) + gas-amount (some-> (when-not (= :ETH (:symbol transaction)) + (money/bignumber network-fee-eth)) + (money/with-precision 18)) - #_fee-fiat-amount - #_(some-> (token->fiat-conversion prices token fiat-currency formated-amount) - (money/with-precision 2))] + total-fiat (some-> (token->fiat-conversion prices token fiat-currency total-amount) + (money/with-precision 2))] [wallet.components/simple-screen {:avoid-keyboard? (not modal?) :status-bar-type (if modal? :modal-wallet :wallet)} - [toolbar modal? "Send amount"] - [react/view {:style {:flex 1 + [toolbar flow (i18n/label :t/send-amount) (:public-key contact)] + [react/view {:style {:flex 1 :border-top-width 1 :border-top-color colors/white-light-transparent}} (when (optimal-gas-present? @tx-atom) - [slide-up-modal {:anim-ref #(reset! network-fees-modal-ref %) + [slide-up-modal {:anim-ref #(reset! network-fees-modal-ref %) :swipe-dismiss? true} [custom-gas-input-panel (-> (select-keys @tx-atom [:gas :gas-price :optimal-gas :optimal-gas-price]) @@ -1125,170 +1234,122 @@ Example: (close-network-fees!))))]]) [react/text {:style {:margin-top 18 :text-align :center - :font-size 15 - :color colors/white-transparent}} - "Recipient"] + :font-size 15 + :color colors/white-transparent}} + (i18n/label :t/recipient)] [react/view (when contact - [react/view {:style {:margin-top 10 - :flex-direction :row + [react/view {:style {:margin-top 10 + :flex-direction :row :justify-content :center}} [photos/photo (:photo-path contact) {:size list.styles/image-size}]]) - [react/text {:style {:color colors/white + [react/text {:style {:color colors/white :margin-horizontal 24 - :margin-top 10 - :line-height 22 - :font-size 15 - :text-align :center}} + :margin-top 10 + :line-height 22 + :font-size 15 + :text-align :center}} (ethereum/normalized-address (:to transaction))]] [react/text {:style {:margin-top 18 - :font-size 15 + :font-size 15 :text-align :center - :color colors/white-transparent}} - "Amount"] - [react/view {:style {:flex-direction :row - :align-items :center - :margin-top 10 + :color colors/white-transparent}} + (i18n/label :t/amount)] + [react/view {:style {:flex-direction :row + :align-items :center + :margin-top 10 :margin-horizontal 24}} - [react/text {:style {:color colors/white - :font-size 15}} "Sending"] + [react/text {:style {:color colors/white + :font-size 15}} (i18n/label :t/sending)] [react/view {:style {:flex 1}} - [react/text {:style {:color colors/white + [react/text {:style {:color colors/white :line-height 21 - :font-size 15 + :font-size 15 :font-weight "500" - :text-align :right}} + :text-align :right}} amount-str] - [react/text {:style {:color colors/white-transparent + [react/text {:style {:color colors/white-transparent :line-height 21 - :font-size 15 - :text-align :right}} + :font-size 15 + :text-align :right}} (str "~ " (:symbol fiat-currency "$") fiat-amount " " (:code fiat-currency))]]] [react/view {:style {:margin-horizontal 24 - :margin-top 10 - :padding-top 10 - :border-top-width 1 - :border-top-color colors/white-light-transparent}} + :margin-top 10 + :padding-top 10 + :border-top-width 1 + :border-top-color colors/white-light-transparent}} [react/view {:style {:flex-direction :row - :align-items :center}} + :align-items :center}} [react/touchable-highlight {:on-press #(open-network-fees!) - :style {:background-color colors/black-transparent - :padding-horizontal 16 - :padding-vertical 9 - :border-radius 8}} + :style {:background-color colors/black-transparent + :padding-horizontal 16 + :padding-vertical 9 + :border-radius 8}} [react/view {:style {:flex-direction :row - :align-items :center}} - [react/text {:style {:color colors/white + :align-items :center}} + [react/text {:style {:color colors/white :padding-right 10 - :font-size 15}} "Network fee"] + :font-size 15}} (i18n/label :t/network-fee)] [vector-icons/icon :icons/settings {:color colors/white}]]] [react/view {:style {:flex 1}} - [react/text {:style {:color colors/white + [react/text {:style {:color colors/white :line-height 21 - :font-size 15 + :font-size 15 :font-weight "500" - :text-align :right}} - (str network-fee-eth " " (name (:symbol native-currency)))] - [react/text {:style {:color colors/white-transparent + :text-align :right}} + (str network-fee-eth " " (wallet.utils/display-symbol native-currency))] + [react/text {:style {:color colors/white-transparent :line-height 21 - :font-size 15 - :text-align :right}} + :font-size 15 + :text-align :right}} (str "~ " network-fee-fiat " " (:code fiat-currency))]]]] - [react/view {:style {:background-color colors/white - :border-top-left-radius 8 - :border-top-right-radius 8 - :position :absolute - :left 0 - :right 0 - :bottom 0}} - [react/text {:style {:color colors/black - :font-size 15 - :line-height 22 - :margin-top 23 - :text-align :center}} - "Total"] - [react/text {:style {:color colors/black - :margin-top 4 - :font-weight :bold - :font-size 22 - :line-height 28 - :text-align :center}} - (str total-eth " " (name (:symbol native-currency)))] - [react/text {:style {:color colors/gray - :text-align :center - :margin-top 3 - :line-height 21 - :font-size 15}} - (str "~ " (:symbol fiat-currency "$") total-fiat)] - [react/view {:style {:flex-direction :row - :justify-content :center - :padding-top 16 - :padding-bottom 24}} - [react/touchable-highlight - {:on-press (fn [] #_TODO) - :style {:padding-horizontal 39 - :padding-vertical 12 - :border-radius 8 - :background-color colors/blue-light}} - [react/text {:style {:font-size 15 - :line-height 22 - :color colors/blue}} - "Confirm"]]]] - - #_[react/text "Here we are"]]])))) + [static-modal + [confirm-and-sign {:transaction transaction + :contact contact + :total-amount total-amount + :gas-amount gas-amount + :native-currency native-currency + :fiat-currency fiat-currency + :total-fiat total-fiat + :all-tokens all-tokens + :chain chain + :flow flow}]]]])))) (defview txn-overview [] - (letsubs [{:keys [transaction modal? contact]} - [:get-screen-params :wallet-txn-overview] - balance [:balance] - prices [:prices] - network [:account/network] - all-tokens [:wallet/all-tokens] - fiat-currency [:wallet/currency] - chain (ethereum/network->chain-keyword network) - native-currency (tokens/native-currency chain)] - ;; TODO look up contact don't pass it forward - (let [token (tokens/asset-for - all-tokens - (ethereum/network->chain-keyword network) (:symbol symbol))] - [transaction-overview {:transaction transaction - :modal? modal? - :contact contact - :prices prices - :network network - :token token + (letsubs [{:keys [transaction flow contact]} [:get-screen-params :wallet-txn-overview] + prices [:prices] + network [:account/network] + all-tokens [:wallet/all-tokens] + fiat-currency [:wallet/currency]] + (let [chain (ethereum/network->chain-keyword network) + native-currency (tokens/native-currency chain) + token (tokens/asset-for all-tokens + (ethereum/network->chain-keyword network) (:symbol transaction))] + [transaction-overview {:transaction transaction + :flow flow + :contact contact + :prices prices + :network network + :token token :native-currency native-currency - :fiat-currency fiat-currency}]))) + :fiat-currency fiat-currency + :all-tokens all-tokens + :chain chain}]))) ;; MAIN SEND TRANSACTION VIEW -(defn- send-transaction-view [{:keys [scroll] :as opts}] - (let [amount-input (atom nil) - handler (fn [_] - (when (and scroll @scroll @amount-input - (.isFocused @amount-input)) - (log/debug "Amount field focused, scrolling down") - (.scrollToEnd @scroll)))] - (reagent/create-class - {:component-will-mount (fn [_] - ;;NOTE(goranjovic): keyboardDidShow is for android and keyboardWillShow for ios - (.addListener react/keyboard "keyboardDidShow" handler) - (.addListener react/keyboard "keyboardWillShow" handler)) - :reagent-render (fn [opts] [choose-address-contact (assoc opts :amount-input amount-input)])}))) +(defn- send-transaction-view [_opts] + (reagent/create-class + {:reagent-render (fn [opts] [choose-address-contact opts])})) ;; SEND TRANSACTION FROM WALLET (CHAT) (defview send-transaction [] (letsubs [transaction [:wallet.send/transaction] - advanced? [:wallet.send/advanced?] network [:account/network] - scroll (atom nil) network-status [:network-status] all-tokens [:wallet/all-tokens] contacts [:contacts/all-added-people-contacts]] [send-transaction-view {:modal? false - ;; TODO only send gas and gas-price when they are custom :transaction (dissoc transaction :gas :gas-price) - :scroll scroll - :advanced? advanced? :network network :all-tokens all-tokens :contacts contacts @@ -1296,141 +1357,22 @@ Example: ;; SEND TRANSACTION FROM DAPP (defview send-transaction-modal [] - (letsubs [transaction [:wallet.send/transaction] - advanced? [:wallet.send/advanced?] - network [:account/network] - scroll (atom nil) - network-status [:network-status] - all-tokens [:wallet/all-tokens]] - (if transaction - [send-transaction-view {:modal? true - :transaction transaction - :scroll scroll - :advanced? advanced? - :network network - :all-tokens all-tokens - :network-status network-status}] - [react/view wallet.styles/wallet-modal-container - [react/view components.styles/flex - [status-bar/status-bar {:type :modal-wallet}] - [toolbar true (i18n/label :t/send-transaction)] - [react/i18n-text {:style styles/empty-text - :key :unsigned-transaction-expired}]]]))) - -(defview password-input-panel [message-label spinning?] - (letsubs [account [:account/account] - wrong-password? [:wallet.send/wrong-password?] - signing-phrase (:signing-phrase @account) - bottom-value (animation/create-value -250) - opacity-value (animation/create-value 0)] - {:component-did-mount #(send.animations/animate-sign-panel opacity-value bottom-value)} - [react/animated-view {:style (styles/animated-sign-panel bottom-value)} - (when wrong-password? - [tooltip/tooltip (i18n/label :t/wrong-password) styles/password-error-tooltip]) - [react/animated-view {:style (styles/sign-panel opacity-value)} - [react/view styles/spinner-container - (when spinning? - [react/activity-indicator {:animating true - :size :large}])] - [react/view styles/signing-phrase-container - [react/text {:style styles/signing-phrase - :accessibility-label :signing-phrase-text} - signing-phrase]] - [react/i18n-text {:style styles/signing-phrase-description :key message-label}] - [react/view {:style styles/password-container - :important-for-accessibility :no-hide-descendants} - [react/text-input - {:auto-focus true - :secure-text-entry true - :placeholder (i18n/label :t/enter-password) - :placeholder-text-color colors/gray - :on-change-text #(re-frame/dispatch [:wallet.send/set-password (security/mask-data %)]) - :style styles/password - :accessibility-label :enter-password-input - :auto-capitalize :none}]]]])) - -;; "Cancel" and "Sign Transaction >" or "Sign >" buttons, signing with password -(defview enter-password-buttons [spinning? cancel-handler sign-handler sign-label] - (letsubs [sign-enabled? [:wallet.send/sign-password-enabled?] - network-status [:network-status]] - [bottom-buttons/bottom-buttons - styles/sign-buttons - [button/button {:style components.styles/flex - :on-press cancel-handler - :accessibility-label :cancel-button} - (i18n/label :t/cancel)] - [button/button {:style (wallet.styles/button-container sign-enabled?) - :on-press sign-handler - :disabled? (or spinning? - (not sign-enabled?) - (= :offline network-status)) - :accessibility-label :sign-transaction-button} - (i18n/label sign-label) - [vector-icons/icon :icons/forward {:color colors/white}]]])) - -;; "Sign Transaction >" button -(defn- sign-transaction-button [amount-error to amount sufficient-funds? sufficient-gas? modal? online?] - (let [sign-enabled? (and (nil? amount-error) - (or modal? (not (empty? to))) ;;NOTE(goranjovic) - contract creation will have empty `to` - (not (nil? amount)) - sufficient-funds? - sufficient-gas? - online?)] - [bottom-buttons/bottom-buttons - styles/sign-buttons - [react/view] - [button/button {:style components.styles/flex - :disabled? (not sign-enabled?) - :on-press #(re-frame/dispatch [:set-in - [:wallet :send-transaction :show-password-input?] - true]) - :text-style {:color :white} - :accessibility-label :sign-transaction-button} - (i18n/label :t/transactions-sign-transaction) - [vector-icons/icon :icons/forward {:color (if sign-enabled? colors/white colors/white-light-transparent)}]]])) - -(defn- render-send-transaction-view [{:keys [modal? transaction scroll advanced? network all-tokens amount-input network-status]}] - (let [{:keys [amount amount-text amount-error asset-error show-password-input? to to-name sufficient-funds? - sufficient-gas? in-progress? from-chat? symbol]} transaction - chain (ethereum/network->chain-keyword network) - native-currency (tokens/native-currency chain) - {:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol) - online? (= :online network-status)] - [wallet.components/simple-screen {:avoid-keyboard? (not modal?) - :status-bar-type (if modal? :modal-wallet :wallet)} - [toolbar modal? (i18n/label :t/send-transaction)] - [react/view components.styles/flex - [common/network-info {:text-color :white}] - [react/scroll-view {:keyboard-should-persist-taps :always - :ref #(reset! scroll %) - :on-content-size-change #(when (and (not modal?) scroll @scroll) - (.scrollToEnd @scroll))} - (when-not online? - [wallet.main.views/snackbar :t/error-cant-send-transaction-offline]) - [react/view styles/send-transaction-form - [components/recipient-selector {:disabled? (or from-chat? modal?) - :address to - :name to-name - :modal? modal?}] - [components/asset-selector {:disabled? (or from-chat? modal?) - :error asset-error - :type :send - :symbol symbol}] - [components/amount-selector {:disabled? (or from-chat? modal?) - :error (or amount-error - (when-not sufficient-funds? (i18n/label :t/wallet-insufficient-funds)) - (when-not sufficient-gas? (i18n/label :t/wallet-insufficient-gas))) - :amount amount - :amount-text amount-text - :input-options {:on-change-text #(re-frame/dispatch [:wallet.send/set-and-validate-amount % symbol decimals]) - :ref (partial reset! amount-input)}} token] - [advanced-options advanced? native-currency transaction scroll]]] - (if show-password-input? - [enter-password-buttons in-progress? - #(re-frame/dispatch [:wallet/cancel-entering-password]) - #(re-frame/dispatch [:wallet/send-transaction]) - :t/transactions-sign-transaction] - [sign-transaction-button amount-error to amount sufficient-funds? sufficient-gas? modal? online?]) - (when show-password-input? - [password-input-panel :t/signing-phrase-description in-progress?]) - (when in-progress? [react/view styles/processing-view])]])) + (letsubs [{:keys [transaction flow contact]} [:get-screen-params :wallet-send-transaction-modal] + prices [:prices] + network [:account/network] + all-tokens [:wallet/all-tokens] + fiat-currency [:wallet/currency]] + (let [chain (ethereum/network->chain-keyword network) + native-currency (tokens/native-currency chain) + token (tokens/asset-for all-tokens + (ethereum/network->chain-keyword network) (:symbol transaction))] + [transaction-overview {:transaction transaction + :flow flow + :contact contact + :prices prices + :network network + :token token + :native-currency native-currency + :fiat-currency fiat-currency + :all-tokens all-tokens + :chain chain}]))) diff --git a/src/status_im/ui/screens/wallet/transaction_fee/views.cljs b/src/status_im/ui/screens/wallet/transaction_fee/views.cljs deleted file mode 100644 index 77917b429a4..00000000000 --- a/src/status_im/ui/screens/wallet/transaction_fee/views.cljs +++ /dev/null @@ -1,102 +0,0 @@ -(ns status-im.ui.screens.wallet.transaction-fee.views - (:require-macros [status-im.utils.views :refer [defview letsubs]]) - (:require [re-frame.core :as re-frame] - [status-im.i18n :as i18n] - [status-im.ui.components.bottom-buttons.view :as bottom-buttons] - [status-im.ui.components.button.view :as button] - [status-im.ui.components.react :as react] - [status-im.ui.components.styles :as components.styles] - [status-im.ui.components.toolbar.actions :as act] - [status-im.ui.components.toolbar.view :as toolbar] - [status-im.ui.components.tooltip.views :as tooltip] - [status-im.ui.screens.wallet.components.views :as components] - [status-im.ui.screens.wallet.send.styles :as styles] - [status-im.ui.screens.wallet.styles :as wallet.styles] - [status-im.utils.money :as money] - [status-im.utils.ethereum.tokens :as tokens] - [status-im.utils.ethereum.core :as ethereum] - [status-im.ui.screens.wallet.utils :as wallet.utils])) - -(defn- toolbar [title] - [toolbar/toolbar {:style wallet.styles/toolbar} - [toolbar/nav-button (act/close-white act/default-handler)] - [toolbar/content-title {:color :white} title]]) - -(defview transaction-fee [] - (letsubs [send-transaction [:wallet.send/transaction] - network [:account/network] - {gas-edit :gas - max-fee :max-fee - gas-price-edit :gas-price} [:wallet/edit] - all-tokens [:wallet/all-tokens]] - (let [{:keys [amount symbol]} send-transaction - gas (:value gas-edit) - gas-price (:value gas-price-edit) - chain (ethereum/network->chain-keyword network) - native-currency (tokens/native-currency chain) - {:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol)] - [components/simple-screen {:status-bar-type :modal-wallet} - [toolbar (i18n/label :t/wallet-transaction-fee)] - [react/view components.styles/flex - [react/view {:flex-direction :row} - - [react/view styles/gas-container-wrapper - [components/cartouche {} - (i18n/label :t/gas-limit) - [react/view styles/gas-input-wrapper - [react/text-input (merge styles/transaction-fee-input - {:on-change-text #(re-frame/dispatch [:wallet.send/edit-value :gas %]) - :default-value gas - :accessibility-label :gas-limit-input})]]] - (when (:invalid? gas-edit) - [tooltip/tooltip (i18n/label :t/invalid-number) styles/gas-input-error-tooltip])] - - [react/view styles/gas-container-wrapper - [components/cartouche {} - (i18n/label :t/gas-price) - [react/view styles/gas-input-wrapper - [react/text-input (merge styles/transaction-fee-input - {:on-change-text #(re-frame/dispatch [:wallet.send/edit-value :gas-price %]) - :default-value gas-price - :accessibility-label :gas-price-input})] - [components/cartouche-secondary-text - (i18n/label :t/gwei)]]] - (when (:invalid? gas-price-edit) - [tooltip/tooltip - (i18n/label (if (= :invalid-number (:invalid? gas-price-edit)) - :t/invalid-number - :t/wallet-send-min-wei)) - styles/gas-input-error-tooltip])]] - - [react/view styles/transaction-fee-info - [react/view styles/transaction-fee-info-icon - [react/text {:style styles/transaction-fee-info-icon-text} "?"]] - [react/view styles/transaction-fee-info-text-wrapper - [react/i18n-text {:style styles/advanced-fees-text - :key :wallet-transaction-fee-details}]]] - [components/separator] - [react/view styles/transaction-fee-block-wrapper - [components/cartouche {:disabled? true} - (i18n/label :t/amount) - [react/view {:accessibility-label :amount-input} - [components/cartouche-text-content - (str (money/to-fixed (money/internal->formatted amount symbol decimals))) - (wallet.utils/display-symbol token)]]] - [components/cartouche {:disabled? true} - (i18n/label :t/wallet-transaction-total-fee) - [react/view {:accessibility-label :total-fee-input} - [components/cartouche-text-content - (str max-fee " " (wallet.utils/display-symbol native-currency))]]]] - - [bottom-buttons/bottom-buttons styles/fee-buttons - [button/button {:on-press #(re-frame/dispatch [:wallet.send/reset-gas-default]) - :accessibility-label :reset-to-default-button} - (i18n/label :t/reset-default)] - [button/button {:on-press #(do (re-frame/dispatch [:wallet.send/set-gas-details - (:value-number gas-edit) - (:value-number gas-price-edit)]) - (act/default-handler)) - :accessibility-label :done-button - :disabled? (or (:invalid? gas-edit) - (:invalid? gas-price-edit))} - (i18n/label :t/done)]]]]))) diff --git a/src/status_im/ui/screens/wallet/transaction_sent/views.cljs b/src/status_im/ui/screens/wallet/transaction_sent/views.cljs index 14e8de8a967..04febb238e9 100644 --- a/src/status_im/ui/screens/wallet/transaction_sent/views.cljs +++ b/src/status_im/ui/screens/wallet/transaction_sent/views.cljs @@ -61,13 +61,13 @@ (bottom-action-button on-next)]) (defview transaction-sent [] - (letsubs [chat-id [:chats/current-chat-id]] + (letsubs [{:keys [chat-id flow]} [:get-screen-params :wallet-transaction-sent]] [react/view {:flex 1 :background-color colors/blue} [status-bar/status-bar {:type :transparent}] - (sent-screen {:on-next #(re-frame/dispatch [:close-transaction-sent-screen chat-id])})])) + (sent-screen {:on-next #(re-frame/dispatch [:close-transaction-sent-screen chat-id flow])})])) (defview transaction-sent-modal [] (letsubs [chat-id [:chats/current-chat-id]] [react/view {:flex 1 :background-color colors/blue} [status-bar/status-bar {:type :modal-wallet}] - (sent-screen {:on-next #(re-frame/dispatch [:close-transaction-sent-screen chat-id])})])) + (sent-screen {:on-next #(re-frame/dispatch [:close-transaction-sent-screen chat-id :dapp])})])) diff --git a/src/status_im/utils/ethereum/erc20.cljs b/src/status_im/utils/ethereum/erc20.cljs index 9822cea8547..39799464441 100644 --- a/src/status_im/utils/ethereum/erc20.cljs +++ b/src/status_im/utils/ethereum/erc20.cljs @@ -112,13 +112,13 @@ (defn balance-of [web3 contract address cb] (.balanceOf (get-instance web3 contract) address cb)) -(defn transfer [contract from to value gas gas-price masked-password on-completed] +(defn transfer [contract from to value gas gas-price password on-completed] (status/send-transaction (types/clj->json (merge (ethereum/call-params contract "transfer(address,uint256)" to value) {:from from :gas gas :gasPrice gas-price})) - (security/safe-unmask-data masked-password) + password on-completed)) (defn transfer-from [web3 contract from-address to-address value cb] diff --git a/translations/en.json b/translations/en.json index d8d10a5db93..d450f1bffbb 100644 --- a/translations/en.json +++ b/translations/en.json @@ -738,7 +738,6 @@ "view-profile": "View profile", "message": "Message", "here-is-your-passphrase": "Here is your passphrase, *write this down and keep this safe!* You will need it to recover your account.", - "add-mailserver": "Add Mailserver", "currency-display-name-ttd": "Trinidad and Tobago Dollar", "wallet-assets": "Assets", "are-you-sure-description": "You will not be able to see the whole recovery phrase again", @@ -865,4 +864,26 @@ "account-and-db-password-mismatch-title": "The problem occurred!", "account-and-db-password-mismatch-content": "Account's and realm db passwords do not match.", "recover-account-warning": "Your wallet information will be exposed by importing this account." + "error-unknown-ens-name": "Unknown ENS name", + "address-or-ens-placeholder": "0x... or name.eth", + "wallet-address-tab-title": "Address", + "wallet-contacts-tab-title": "Contacts", + "invalid-number-format": "Invalid number format", + "gas-cost-explanation": "Gas price is the amount you are willing to pay per unit of gas. Increasing this price may help your transaction get processed faster.", + "gas-limit-explanation": "Gas limit is the maximum units of gas you're willing to spend on this transaction.", + "network-fee-settings": "Network fee settings", + "network-fee-explanation": "This fee, known as gas is paid directly to the Ethereum network. Status does not collect any of these funds", + "optimal-gas-option": "Optimal", + "custom-gas-option": "Custom", + "update": "Update", + "choose-asset": "Choose asset", + "wallet-no-assets-enabled": "You don't have any assets yet", + "network-fee-amount": "network fee ~ {{amount}} {{currency}}", + "total": "Total", + "wallet-passphrase-reminder": "Only send the transaction if you recognize\nyour three words", + "send-amount-currency": "Send {{amount}} {{currency}}", + "enter-your-login-password": "Enter your login password...", + "send": "Send", + "sending": "Sending", + "network-fee": "Network fee" }