diff --git a/src/status_im/accounts/core.cljs b/src/status_im/accounts/core.cljs index d21ea66aeb..c38bf7583d 100644 --- a/src/status_im/accounts/core.cljs +++ b/src/status_im/accounts/core.cljs @@ -2,14 +2,13 @@ (:require [re-frame.core :as re-frame] [status-im.accounts.update.core :as accounts.update] [status-im.i18n :as i18n] - [status-im.ui.screens.navigation :as navigation] [status-im.native-module.core :as native-module] - [status-im.ui.screens.wallet.settings.models :as wallet.settings.models] + [status-im.ui.screens.navigation :as navigation] + [status-im.utils.build :as build] [status-im.utils.config :as config] - [status-im.utils.utils :as utils] [status-im.utils.fx :as fx] [status-im.utils.platform :as platform] - [status-im.utils.build :as build])) + [status-im.utils.utils :as utils])) (re-frame/reg-fx ::chaos-mode-changed @@ -49,7 +48,6 @@ [{:keys [db] :as cofx} modal?] (fx/merge cofx (continue-after-wallet-onboarding modal?) - (wallet.settings.models/wallet-autoconfig-tokens) (accounts.update/account-update {:wallet-set-up-passed? true} {}))) (fx/defn update-dev-server-state diff --git a/src/status_im/accounts/login/core.cljs b/src/status_im/accounts/login/core.cljs index 6a62cb1cb3..44882bd2d6 100644 --- a/src/status_im/accounts/login/core.cljs +++ b/src/status_im/accounts/login/core.cljs @@ -7,7 +7,6 @@ [status-im.ethereum.transactions.core :as transactions] [status-im.fleet.core :as fleet] [status-im.i18n :as i18n] - [status-im.models.wallet :as models.wallet] [status-im.native-module.core :as status] [status-im.node.core :as node] [status-im.protocol.core :as protocol] @@ -22,6 +21,7 @@ [status-im.utils.security :as security] [status-im.utils.types :as types] [status-im.utils.universal-links.core :as universal-links] + [status-im.wallet.core :as wallet] [taoensso.timbre :as log])) (def rpc-endpoint "https://goerli.infura.io/v3/f315575765b14720b32382a61a89341a") @@ -84,10 +84,10 @@ (fx/defn initialize-wallet [cofx] (fx/merge cofx - (models.wallet/initialize-tokens) + (wallet/initialize-tokens) (transactions/initialize) (ethereum.subscriptions/initialize) - (models.wallet/update-wallet))) + (wallet/update-wallet))) (fx/defn user-login [{:keys [db] :as cofx} create-database?] (let [{:keys [address password]} (accounts.db/credentials cofx)] diff --git a/src/status_im/chat/commands/impl/transactions.cljs b/src/status_im/chat/commands/impl/transactions.cljs index ecf1adad99..fdd73ac25e 100644 --- a/src/status_im/chat/commands/impl/transactions.cljs +++ b/src/status_im/chat/commands/impl/transactions.cljs @@ -185,7 +185,7 @@ (defview send-status [tx-hash outgoing] (letsubs [{:keys [exists? confirmed?]} [:chats/transaction-status tx-hash]] [react/touchable-highlight {:on-press #(when exists? - (re-frame/dispatch [:show-transaction-details tx-hash]))} + (re-frame/dispatch [:wallet.ui/show-transaction-details tx-hash]))} [react/view transactions-styles/command-send-status-container [vector-icons/icon (if confirmed? :tiny-icons/tiny-check diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index 8a6eb6e430..57f31d4259 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -103,11 +103,7 @@ (defn default-account-settings [] {:web3-opt-in? true :preview-privacy? false - :wallet {:visible-tokens {:testnet #{:STT :HND} - :mainnet #{:SNT} - :rinkeby #{:MOKSHA :KDO} - :xdai #{} - :poa #{}}}}) + :wallet {:visible-tokens {}}}) (def currencies {:aed {:id :aed :code "AED" :display-name (i18n/label :t/currency-display-name-aed) :symbol "د.إ"} diff --git a/src/status_im/ethereum/transactions/core.cljs b/src/status_im/ethereum/transactions/core.cljs index 99f6047f96..fe9abff875 100644 --- a/src/status_im/ethereum/transactions/core.cljs +++ b/src/status_im/ethereum/transactions/core.cljs @@ -8,6 +8,7 @@ [status-im.utils.ethereum.core :as ethereum] [status-im.utils.fx :as fx] [status-im.utils.types :as types] + [status-im.wallet.core :as wallet] [taoensso.timbre :as log])) (def confirmations-count-threshold 12) @@ -180,14 +181,18 @@ ;; ----------------------------------------------- (fx/defn new - [{:keys [db]} {:keys [hash] :as transaction}] - {:db (assoc-in db [:wallet :transactions hash] transaction)}) + [{:keys [db] :as cofx} {:keys [hash] :as transaction}] + (fx/merge cofx + {:db (assoc-in db [:wallet :transactions hash] transaction)} + wallet/update-wallet)) (fx/defn handle-history - [{:keys [db]} transactions] - {:db (update-in db - [:wallet :transactions] - #(merge transactions %))}) + [{:keys [db] :as cofx} transactions] + (fx/merge cofx + {:db (update-in db + [:wallet :transactions] + #(merge transactions %))} + wallet/update-wallet)) (fx/defn handle-token-history [{:keys [db]} transactions] diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 7bb5d7b857..e30456593a 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -57,6 +57,7 @@ [status-im.utils.handlers :as handlers] [status-im.utils.logging.core :as logging] [status-im.utils.utils :as utils] + [status-im.wallet.core :as wallet] [status-im.wallet.db :as wallet.db] [status-im.web3.core :as web3] [taoensso.timbre :as log] @@ -2147,6 +2148,12 @@ (ethereum.transactions/new cofx transaction))) ;; wallet events + +(handlers/register-handler-fx + :wallet.ui/pull-to-refresh + (fn [cofx _] + (wallet/update-wallet cofx))) + (handlers/register-handler-fx :wallet.transactions/add-filter (fn [{:keys [db]} [_ id]] @@ -2162,3 +2169,91 @@ (fn [{:keys [db]} _] {:db (assoc-in db [:wallet :filters] wallet.db/default-wallet-filters)})) + +(handlers/register-handler-fx + :wallet.settings/toggle-visible-token + (fn [cofx [_ symbol checked?]] + (wallet/toggle-visible-token cofx symbol checked?))) + +(handlers/register-handler-fx + :wallet/token-found + (fn [cofx [_ symbol balance]] + (wallet/configure-token-balance-and-visibility cofx symbol balance))) + +(handlers/register-handler-fx + :TODO.remove/update-wallet + (fn [cofx _] + (wallet/update-wallet cofx))) + +(handlers/register-handler-fx + :wallet.settings.ui/navigate-back-pressed + (fn [cofx [_ on-close]] + (fx/merge cofx + (when on-close + {:dispatch on-close}) + (navigation/navigate-back) + (wallet/update-wallet)))) + +(handlers/register-handler-fx + :wallet.callback/update-balance-success + (fn [cofx [_ balance]] + (wallet/update-balance cofx balance))) + +(handlers/register-handler-fx + :wallet.callback/update-balance-fail + (fn [cofx [_ err]] + (wallet/on-update-balance-fail cofx err))) + +(handlers/register-handler-fx + :wallet.callback/update-token-balance-success + (fn [cofx [_ symbol balance]] + (wallet/update-token-balance cofx symbol balance))) + +(handlers/register-handler-fx + :wallet.callback/update-token-balance-fail + (fn [cofx [_ symbol err]] + (wallet/on-update-token-balance-fail cofx symbol err))) + +(handlers/register-handler-fx + :wallet.callback/update-prices-success + (fn [cofx [_ prices]] + (wallet/update-prices cofx prices))) + +(handlers/register-handler-fx + :wallet.callback/update-prices-fail + (fn [cofx [_ err]] + (wallet/on-update-prices-fail cofx err))) + +(handlers/register-handler-fx + :wallet.ui/show-transaction-details + (fn [cofx [_ hash]] + (wallet/open-transaction-details cofx hash))) + +(handlers/register-handler-fx + :wallet/show-sign-transaction + (fn [cofx [_ {:keys [id method]} from-chat?]] + (wallet/open-send-transaction-modal cofx id method from-chat?))) + +(handlers/register-handler-fx + :wallet/update-gas-price-success + (fn [cofx [_ price edit?]] + (wallet/update-gas-price cofx price edit?))) + +(handlers/register-handler-fx + :TODO.remove/update-estimated-gas + (fn [{:keys [db]} [_ obj]] + {:update-estimated-gas {:web3 (:web3 db) + :obj obj + :success-event :wallet/update-estimated-gas-success}})) + +(handlers/register-handler-fx + :wallet/update-estimated-gas-success + (fn [cofx [_ gas]] + (wallet/update-estimated-gas-price cofx gas))) + +(handlers/register-handler-fx + :wallet.setup.ui/navigate-back-pressed + (fn [{:keys [db] :as cofx}] + (fx/merge cofx + {:db (assoc-in db [:wallet :send-transaction] {})} + (navigation/navigate-back)))) diff --git a/src/status_im/extensions/capacities/ethereum.cljs b/src/status_im/extensions/capacities/ethereum.cljs index 8857b16743..4de54e8de2 100644 --- a/src/status_im/extensions/capacities/ethereum.cljs +++ b/src/status_im/extensions/capacities/ethereum.cljs @@ -2,17 +2,17 @@ (:require [clojure.string :as string] [status-im.constants :as constants] [status-im.i18n :as i18n] - [status-im.models.wallet :as models.wallet] - [status-im.utils.hex :as hex] + [status-im.native-module.core :as status] [status-im.ui.screens.navigation :as navigation] [status-im.utils.ethereum.abi-spec :as abi-spec] - [status-im.utils.fx :as fx] - [status-im.utils.ethereum.ens :as ens] [status-im.utils.ethereum.core :as ethereum] + [status-im.utils.ethereum.ens :as ens] + [status-im.utils.fx :as fx] [status-im.utils.handlers :as handlers] + [status-im.utils.hex :as hex] [status-im.utils.money :as money] [status-im.utils.types :as types] - [status-im.native-module.core :as status])) + [status-im.wallet.core :as wallet])) (handlers/register-handler-fx :extensions/wallet-ui-on-success @@ -72,7 +72,7 @@ (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))) + (wallet/open-modal-wallet-for-transaction db transaction tx-object))) (handlers/register-handler-fx :extensions/ethereum-send-transaction diff --git a/src/status_im/hardwallet/core.cljs b/src/status_im/hardwallet/core.cljs index 1c61b9c177..47120b6919 100644 --- a/src/status_im/hardwallet/core.cljs +++ b/src/status_im/hardwallet/core.cljs @@ -1,24 +1,24 @@ (ns status-im.hardwallet.core - (:require [re-frame.core :as re-frame] - status-im.hardwallet.fx + (:require [clojure.string :as string] + [re-frame.core :as re-frame] + [status-im.accounts.create.core :as accounts.create] + [status-im.accounts.login.core :as accounts.login] + [status-im.accounts.logout.core :as accounts.logout] + [status-im.accounts.recover.core :as accounts.recover] + [status-im.data-store.accounts :as accounts-store] + [status-im.i18n :as i18n] + [status-im.node.core :as node] [status-im.ui.screens.navigation :as navigation] [status-im.utils.config :as config] + [status-im.utils.datetime :as utils.datetime] + [status-im.utils.ethereum.core :as ethereum] + [status-im.utils.ethereum.mnemonic :as mnemonic] [status-im.utils.fx :as fx] [status-im.utils.platform :as platform] - [taoensso.timbre :as log] - [status-im.i18n :as i18n] [status-im.utils.types :as types] - [status-im.accounts.create.core :as accounts.create] - [status-im.node.core :as node] - [status-im.utils.datetime :as utils.datetime] - [status-im.data-store.accounts :as accounts-store] - [status-im.utils.ethereum.core :as ethereum] - [clojure.string :as string] - [status-im.accounts.login.core :as accounts.login] - [status-im.accounts.recover.core :as accounts.recover] - [status-im.models.wallet :as models.wallet] - [status-im.utils.ethereum.mnemonic :as mnemonic] - [status-im.accounts.logout.core :as accounts.logout])) + [status-im.wallet.core :as wallet] + [taoensso.timbre :as log] + status-im.hardwallet.fx)) (def default-pin "000000") @@ -54,7 +54,7 @@ (if navigate-to-browser? (fx/merge cofx {:db (assoc-in db [:hardwallet :on-card-connected] nil)} - (models.wallet/discard-transaction) + (wallet/discard-transaction) (navigation/navigate-to-cofx :browser nil)) (if (= :enter-pin-login (:view-id db)) (navigation/navigate-to-clean cofx :accounts nil) diff --git a/src/status_im/models/wallet.cljs b/src/status_im/models/wallet.cljs deleted file mode 100644 index c6d3bb6cb9..0000000000 --- a/src/status_im/models/wallet.cljs +++ /dev/null @@ -1,285 +0,0 @@ -(ns status-im.models.wallet - (:require [clojure.set :as set] - [status-im.constants :as constants] - [status-im.i18n :as i18n] - [status-im.ui.screens.navigation :as navigation] - [status-im.ui.screens.wallet.utils :as wallet.utils] - [status-im.utils.config :as config] - [status-im.utils.core :as utils.core] - [status-im.utils.ethereum.core :as ethereum] - [status-im.utils.ethereum.tokens :as tokens] - [status-im.utils.fx :as fx] - [status-im.utils.hex :as utils.hex] - [status-im.utils.money :as money])) - -(def min-gas-price-wei (money/bignumber 1)) - -(defmulti invalid-send-parameter? (fn [type _] type)) - -(defmethod invalid-send-parameter? :gas-price [_ value] - (cond - (not value) :invalid-number - (.lt (money/->wei :gwei value) min-gas-price-wei) :not-enough-wei - (-> (money/->wei :gwei value) .decimalPlaces pos?) :invalid-number)) - -(defmethod invalid-send-parameter? :default [_ value] - (when (or (not value) - (<= value 0)) - :invalid-number)) - -(defn- calculate-max-fee - [gas gas-price] - (if (and gas gas-price) - (money/to-fixed (money/wei->ether (.times gas gas-price))) - "0")) - -(defn- edit-max-fee [edit] - (let [gas (get-in edit [:gas-price :value-number]) - gas-price (get-in edit [:gas :value-number])] - (assoc edit :max-fee (calculate-max-fee gas gas-price)))) - -(defn add-max-fee [{:keys [gas gas-price] :as transaction}] - (assoc transaction :max-fee (calculate-max-fee gas gas-price))) - -(defn build-edit [edit-value key value] - "Takes the previous edit, either :gas or :gas-price and a value as string. - Wei for gas, and gwei for gas price. - Validates them and sets max fee" - (let [bn-value (money/bignumber value) - invalid? (invalid-send-parameter? key bn-value) - data (if invalid? - {:value value - :max-fee 0 - :invalid? invalid?} - {:value value - :value-number (if (= :gas-price key) - (money/->wei :gwei bn-value) - bn-value) - :invalid? false})] - (-> edit-value - (assoc key data) - edit-max-fee))) - -(defn edit-value - [key value {:keys [db]}] - {:db (update-in db [:wallet :edit] build-edit key value)}) - -;; DAPP TRANSACTION -> SEND TRANSACTION -(defn prepare-dapp-transaction [{{:keys [id method params]} :payload message-id :message-id} contacts] - (let [{:keys [to value data gas gasPrice nonce]} (first params) - contact (get contacts (utils.hex/normalize-hex to))] - (cond-> {:id (str id) - :to-name (or (when (nil? to) - (i18n/label :t/new-contract)) - contact) - :symbol :ETH - :method method - :to to - :amount (money/bignumber (or value 0)) - :gas (cond - gas - (money/bignumber gas) - (and value (empty? data)) - (money/bignumber 21000)) - :gas-price (when gasPrice - (money/bignumber gasPrice)) - :data data - :on-result [:wallet.dapp/transaction-on-result message-id] - :on-error [:wallet.dapp/transaction-on-error message-id]} - nonce - (assoc :nonce nonce)))) - -;; SEND TRANSACTION -> RPC TRANSACTION -(defn prepare-send-transaction [from {:keys [amount to gas 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)} - data - (assoc :data data) - nonce - (assoc :nonce nonce))) - -;; NOTE (andrey) we need this function, because params may be mixed up, so we need to figure out which one is address -;; and which message -(defn normalize-sign-message-params [params] - (let [first_param (first params) - second_param (second params) - first-param-address? (ethereum/address? first_param) - second-param-address? (ethereum/address? second_param)] - (when (or first-param-address? second-param-address?) - (if first-param-address? - [first_param second_param] - [second_param first_param])))) - -(defn web3-error-callback [fx {:keys [webview-bridge]} message-id message] - (assoc fx :browser/send-to-bridge {:message {:type constants/web3-send-async-callback - :messageId message-id - :error message} - :webview webview-bridge})) - -(defn dapp-complete-transaction [id result method message-id webview keycard?] - (cond-> {:browser/send-to-bridge {:message {:type constants/web3-send-async-callback - :messageId message-id - :result {:jsonrpc "2.0" - :id (int id) - :result result}} - :webview webview} - :dispatch [:navigate-back]} - - (constants/web3-sign-message? method) - (assoc :dispatch (if keycard? [:navigate-to :browser] [:navigate-back])) - - (= method constants/web3-send-transaction) - (assoc :dispatch [:navigate-to-clean :wallet-transaction-sent-modal]))) - -(fx/defn discard-transaction - [{:keys [db]}] - (let [{:keys [on-error]} (get-in db [:wallet :send-transaction])] - (merge {:db (update db :wallet - assoc - :send-transaction {} - :transactions-queue nil)} - (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)] - (let [chain (:chain db) - token (tokens/symbol->token all-tokens (keyword chain) (:symbol transaction))] - (-> transaction - (assoc :confirmations "0" - :timestamp (str now) - :type :outbound - :hash hash - :value (:amount transaction) - :token token - :gas-limit (str (:gas transaction))) - (update :gas-price str) - (dissoc :message-id :id :gas))))) - -(fx/defn handle-transaction-error - [{:keys [db] :as cofx} {:keys [code message]}] - (let [{:keys [on-error]} (get-in db [:wallet :send-transaction])] - (case code - ;;WRONG PASSWORD - constants/send-transaction-err-decrypt - {:db (-> db - (assoc-in [:wallet :send-transaction :wrong-password?] true))} - - (fx/merge cofx - (merge {:db (-> db - (assoc-in [:wallet :transactions-queue] nil) - (assoc-in [:wallet :send-transaction] {})) - :wallet/show-transaction-error message} - (when on-error - {:dispatch (conj on-error message)})) - navigation/navigate-back)))) - -(defn clear-error-message [db error-type] - (update-in db [:wallet :errors] dissoc error-type)) - -(defn tokens-symbols [visible-token-symbols all-tokens chain] - (set/difference (set visible-token-symbols) (set (map :symbol (tokens/nfts-for all-tokens chain))))) - -(fx/defn initialize-tokens - [{:keys [db]}] - (let [network-id (get-in db [:account/account :network]) - network (get-in db [:account/account :networks network-id]) - custom-tokens (get-in db [:account/account :settings :wallet :custom-tokens]) - chain (ethereum/network->chain-keyword network)] - (merge - {:db (assoc db :wallet/all-tokens - (merge-with merge - (utils.core/map-values #(utils.core/index-by :address %) tokens/all-default-tokens) - custom-tokens))} - (when config/erc20-contract-warnings-enabled? - {:wallet/validate-tokens {:web3 (:web3 db) - :tokens (get tokens/all-default-tokens chain)}})))) - -(fx/defn update-wallet - [{{:keys [web3 network network-status] - {:keys [address settings]} :account/account :as db} :db}] - (let [all-tokens (:wallet/all-tokens db) - network (get-in db [:account/account :networks network]) - chain (ethereum/network->chain-keyword network) - mainnet? (= :mainnet chain) - assets (get-in settings [:wallet :visible-tokens chain]) - tokens (tokens-symbols (get-in settings [:wallet :visible-tokens chain]) all-tokens chain) - currency-id (or (get-in settings [:wallet :currency]) :usd) - currency (get constants/currencies currency-id)] - (when (not= network-status :offline) - {:get-balance {:web3 web3 - :account-id address - :success-event :update-balance-success - :error-event :update-balance-fail} - :get-tokens-balance {:web3 web3 - :account-id address - :symbols assets - :chain chain - :all-tokens all-tokens - :success-event :update-token-balance-success - :error-event :update-token-balance-fail} - :get-prices {:from (if mainnet? - (conj tokens "ETH") - [(-> (tokens/native-currency chain) - (wallet.utils/exchange-symbol))]) - :to [(:code currency)] - :mainnet? mainnet? - :success-event :update-prices-success - :error-event :update-prices-fail - :chaos-mode? (:chaos-mode? settings)} - :db (-> db - (clear-error-message :prices-update) - (clear-error-message :balance-update) - (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 - {:keys [wallet-set-up-passed?]} (:account/account db)] - {:db (-> db - (assoc-in [:navigation/screen-params :wallet-send-modal-stack :modal?] true) - (assoc-in [:wallet :send-transaction] transaction) - (assoc-in [:wallet :send-transaction :original-gas] gas)) - :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)]]})) - -(fx/defn open-sign-transaction-flow - [{:keys [db] :as cofx} {:keys [gas gas-price] :as transaction}] - (let [go-to-view-id (if (get-in db [:account/account :wallet-set-up-passed?]) - :wallet-send-modal-stack - :wallet-send-modal-stack-with-onboarding)] - (fx/merge cofx - (cond-> {:db (-> db - (assoc-in [:navigation/screen-params :wallet-send-modal-stack :modal?] true) - (assoc-in [:wallet :send-transaction] - transaction) - (assoc-in [:wallet :send-transaction :original-gas] - gas))} - (not gas) - (assoc :update-estimated-gas - {:web3 (:web3 db) - :obj (select-keys transaction [:to :data]) - :success-event :wallet/update-estimated-gas-success}) - - (not gas-price) - (assoc :update-gas-price - {:web3 (:web3 db) - :success-event :wallet/update-gas-price-success - :edit? false})) - (update-wallet) - (navigation/navigate-to-cofx go-to-view-id {})))) - -(defn send-transaction-screen-did-load - [{:keys [db]}] - {:db (assoc-in db [:navigation/screen-params :wallet-send-modal-stack :modal?] false)}) diff --git a/src/status_im/stickers/core.cljs b/src/status_im/stickers/core.cljs index fccccb7a0a..3039e2a471 100644 --- a/src/status_im/stickers/core.cljs +++ b/src/status_im/stickers/core.cljs @@ -1,17 +1,17 @@ (ns status-im.stickers.core - (:require [status-im.utils.fx :as fx] - [cljs.reader :as edn] - [status-im.accounts.core :as accounts] - [status-im.ui.screens.navigation :as navigation] + (:require [cljs.reader :as edn] [re-frame.core :as re-frame] - [status-im.utils.multihash :as multihash] + [status-im.accounts.core :as accounts] [status-im.constants :as constants] - [status-im.utils.ethereum.core :as ethereum] - [status-im.utils.ethereum.stickers :as ethereum.stickers] - [status-im.models.wallet :as models.wallet] - [status-im.utils.money :as money] + [status-im.ui.screens.navigation :as navigation] [status-im.utils.ethereum.abi-spec :as abi-spec] - [status-im.utils.ethereum.erc20 :as erc20])) + [status-im.utils.ethereum.core :as ethereum] + [status-im.utils.ethereum.erc20 :as erc20] + [status-im.utils.ethereum.stickers :as ethereum.stickers] + [status-im.utils.fx :as fx] + [status-im.utils.money :as money] + [status-im.utils.multihash :as multihash] + [status-im.wallet.core :as wallet])) (fx/defn init-stickers-packs [{:keys [db]}] (let [sticker-packs (into {} (map #(let [pack (edn/read-string %)] @@ -82,7 +82,7 @@ data (abi-spec/encode "buyToken(uint256,address)" [pack-id address]) tx-object {:to (get erc20/snt-contracts chain) :data (abi-spec/encode "approveAndCall(address,uint256,bytes)" [stickers-contract price data])}] - (models.wallet/open-modal-wallet-for-transaction + (wallet/open-modal-wallet-for-transaction db (prepare-transaction "approve" tx-object [:stickers/pending-pack pack-id]) tx-object))) diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index fc2cb85f18..8b9ebbccc5 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -11,11 +11,9 @@ [status-im.constants :as constants] [status-im.contact.db :as contact.db] [status-im.ethereum.transactions.core :as transactions] + [status-im.ethereum.transactions.etherscan :as transactions.etherscan] [status-im.fleet.core :as fleet] [status-im.i18n :as i18n] - [status-im.ethereum.transactions.core :as transactions] - [status-im.ethereum.transactions.etherscan :as transactions.etherscan] - [status-im.models.wallet :as models.wallet] [status-im.ui.components.bottom-bar.styles :as tabs.styles] [status-im.ui.components.toolbar.styles :as toolbar.styles] [status-im.ui.screens.add-new.new-public-chat.db :as db] @@ -29,18 +27,18 @@ [status-im.utils.datetime :as datetime] [status-im.utils.ethereum.core :as ethereum] [status-im.utils.ethereum.tokens :as tokens] - [status-im.utils.hex :as utils.hex] [status-im.utils.identicon :as identicon] [status-im.utils.money :as money] [status-im.utils.platform :as platform] [status-im.utils.security :as security] [status-im.utils.universal-links.core :as links] + [status-im.wallet.core :as wallet] + [status-im.wallet.db :as wallet.db] status-im.tribute-to-talk.subs status-im.ui.screens.hardwallet.connect.subs status-im.ui.screens.hardwallet.settings.subs status-im.ui.screens.hardwallet.pin.subs - status-im.ui.screens.hardwallet.setup.subs - [status-im.wallet.db :as wallet.db])) + status-im.ui.screens.hardwallet.setup.subs)) ;; TOP LEVEL =========================================================================================================== @@ -1128,7 +1126,7 @@ :contact to-contact :address to)) :time-formatted (datetime/timestamp->time timestamp) - :on-touch-fn #(re-frame/dispatch [:show-transaction-details hash])))) + :on-touch-fn #(re-frame/dispatch [:wallet.ui/show-transaction-details hash])))) (defn- group-transactions-by-date [transactions] @@ -1257,12 +1255,12 @@ [transaction edit] (cond-> edit (not (get-in edit [:gas-price :value])) - (models.wallet/build-edit + (wallet/build-edit :gas-price (money/to-fixed (money/wei-> :gwei (:gas-price transaction)))) (not (get-in edit [:gas :value])) - (models.wallet/build-edit + (wallet/build-edit :gas (money/to-fixed (:gas transaction))))) @@ -1299,7 +1297,7 @@ :<- [:balance] (fn [[{:keys [amount symbol] :as transaction} balance]] (-> transaction - (models.wallet/add-max-fee) + (wallet/add-max-fee) (check-sufficient-funds balance symbol amount) (check-sufficient-gas balance symbol amount)))) diff --git a/src/status_im/ui/screens/currency_settings/models.cljs b/src/status_im/ui/screens/currency_settings/models.cljs index feed815f5d..e39200bed4 100644 --- a/src/status_im/ui/screens/currency_settings/models.cljs +++ b/src/status_im/ui/screens/currency_settings/models.cljs @@ -1,7 +1,7 @@ (ns status-im.ui.screens.currency-settings.models (:require [status-im.accounts.update.core :as accounts.update] - [status-im.models.wallet :as wallet] - [status-im.utils.fx :as fx])) + [status-im.utils.fx :as fx] + [status-im.wallet.core :as wallet])) (fx/defn set-currency [{:keys [db] :as cofx} currency] diff --git a/src/status_im/ui/screens/events.cljs b/src/status_im/ui/screens/events.cljs index 7c1c2e1323..4dcc391c3e 100644 --- a/src/status_im/ui/screens/events.cljs +++ b/src/status_im/ui/screens/events.cljs @@ -10,30 +10,29 @@ status-im.ui.screens.add-new.new-chat.navigation status-im.ui.screens.profile.events status-im.ui.screens.extensions.add.events - status-im.ui.screens.wallet.events status-im.ui.screens.wallet.collectibles.events status-im.ui.screens.wallet.send.events status-im.ui.screens.wallet.request.events - status-im.ui.screens.wallet.settings.events status-im.ui.screens.wallet.choose-recipient.events status-im.ui.screens.wallet.collectibles.cryptokitties.events status-im.ui.screens.wallet.collectibles.cryptostrikers.events status-im.ui.screens.wallet.collectibles.etheremon.events status-im.ui.screens.wallet.collectibles.superrare.events status-im.ui.screens.wallet.collectibles.kudos.events + status-im.ui.screens.wallet.navigation status-im.utils.keychain.events [re-frame.core :as re-frame] - [status-im.hardwallet.core :as hardwallet] [status-im.chat.models :as chat] - [status-im.native-module.core :as status] + [status-im.hardwallet.core :as hardwallet] [status-im.mailserver.core :as mailserver] + [status-im.native-module.core :as status] [status-im.ui.components.permissions :as permissions] [status-im.utils.dimensions :as dimensions] + [status-im.utils.fx :as fx] [status-im.utils.handlers :as handlers] [status-im.utils.http :as http] [status-im.utils.utils :as utils] - [status-im.utils.fx :as fx] - [status-im.models.wallet :as wallet])) + [status-im.wallet.core :as wallet])) (defn- http-get [{:keys [url response-validator success-event-creator failure-event-creator timeout-ms]}] (let [on-success #(re-frame/dispatch (success-event-creator %)) diff --git a/src/status_im/ui/screens/wallet/events.cljs b/src/status_im/ui/screens/wallet/events.cljs deleted file mode 100644 index f94fc8d7a1..0000000000 --- a/src/status_im/ui/screens/wallet/events.cljs +++ /dev/null @@ -1,240 +0,0 @@ -(ns status-im.ui.screens.wallet.events - (:require [re-frame.core :as re-frame] - [status-im.i18n :as i18n] - [status-im.models.wallet :as models] - [status-im.ui.screens.navigation :as navigation] - status-im.ui.screens.wallet.navigation - [status-im.utils.ethereum.core :as ethereum] - [status-im.utils.ethereum.erc20 :as erc20] - [status-im.utils.ethereum.tokens :as tokens] - [status-im.utils.fx :as fx] - [status-im.utils.handlers :as handlers] - [status-im.utils.money :as money] - [status-im.utils.prices :as prices] - [status-im.utils.utils :as utils.utils] - [taoensso.timbre :as log])) - -(defn get-balance [{:keys [web3 account-id on-success on-error]}] - (if (and web3 account-id) - (.getBalance - (.-eth web3) - account-id - (fn [err resp] - (if-not err - (on-success resp) - (on-error err)))) - (on-error "web3 or account-id not available"))) - -(defn get-token-balance [{:keys [web3 contract account-id on-success on-error]}] - (if (and web3 contract account-id) - (erc20/balance-of - web3 - contract - (ethereum/normalized-address account-id) - (fn [err resp] - (if-not err - (on-success resp) - (on-error err)))) - (on-error "web3, contract or account-id not available"))) - -(defn assoc-error-message [db error-type err] - (assoc-in db [:wallet :errors error-type] (or err :unknown-error))) - -;; FX - -(re-frame/reg-fx - :get-balance - (fn [{:keys [web3 account-id success-event error-event]}] - (get-balance {:web3 web3 - :account-id account-id - :on-success #(re-frame/dispatch [success-event %]) - :on-error #(re-frame/dispatch [error-event %])}))) - -(re-frame/reg-fx - :get-tokens-balance - (fn [{:keys [web3 symbols all-tokens chain account-id success-event error-event]}] - (doseq [symbol symbols] - (let [contract (:address (tokens/symbol->token all-tokens chain symbol))] - (get-token-balance {:web3 web3 - :contract contract - :account-id account-id - :on-success #(re-frame/dispatch [success-event symbol %]) - :on-error #(re-frame/dispatch [error-event symbol %])}))))) - -;; TODO(oskarth): At some point we want to get list of relevant assets to get prices for -(re-frame/reg-fx - :get-prices - (fn [{:keys [from to mainnet? success-event error-event chaos-mode?]}] - (prices/get-prices from - to - mainnet? - #(re-frame/dispatch [success-event %]) - #(re-frame/dispatch [error-event %]) - chaos-mode?))) - -(re-frame/reg-fx - :update-gas-price - (fn [{:keys [web3 success-event edit?]}] - (ethereum/gas-price web3 #(re-frame/dispatch [success-event %2 edit?])))) - -(re-frame/reg-fx - :update-estimated-gas - (fn [{:keys [web3 obj success-event]}] - (ethereum/estimate-gas-web3 web3 (clj->js obj) #(re-frame/dispatch [success-event %2])))) - -(defn- validate-token-name! [web3 {:keys [address symbol name]}] - (erc20/name web3 address #(when (and (seq %2) ;;NOTE(goranjovic): skipping check if field not set in contract - (not= name %2)) - (let [message (i18n/label :t/token-auto-validate-name-error - {:symbol symbol - :expected name - :actual %2 - :address address})] - (log/warn message) - (utils.utils/show-popup (i18n/label :t/warning) message))))) - -(defn- validate-token-symbol! [web3 {:keys [address symbol]}] - (erc20/symbol web3 address #(when (and (seq %2) ;;NOTE(goranjovic): skipping check if field not set in contract - (not= (clojure.core/name symbol) %2)) - (let [message (i18n/label :t/token-auto-validate-symbol-error - {:symbol symbol - :expected (clojure.core/name symbol) - :actual %2 - :address address})] - (log/warn message) - (utils.utils/show-popup (i18n/label :t/warning) message))))) - -(defn- validate-token-decimals! [web3 {:keys [address symbol decimals nft? skip-decimals-check?]}] - ;;NOTE(goranjovic): only skipping check if skip-decimals-check? flag is present because we can't differentiate - ;;between unset decimals and 0 decimals. - (when-not skip-decimals-check? - (erc20/decimals web3 address #(when (and %2 - (not nft?) - (not= decimals (int %2))) - (let [message (i18n/label :t/token-auto-validate-decimals-error - {:symbol symbol - :expected decimals - :actual %2 - :address address})] - (log/warn message) - (utils.utils/show-popup (i18n/label :t/warning) message)))))) - -(re-frame/reg-fx - :wallet/validate-tokens - (fn [{:keys [web3 tokens]}] - (doseq [token tokens] - (validate-token-decimals! web3 token) - (validate-token-symbol! web3 token) - (validate-token-name! web3 token)))) - -;; Handlers -(handlers/register-handler-fx - :update-wallet - (fn [cofx _] - (models/update-wallet cofx))) - -(handlers/register-handler-fx - :update-wallet-and-nav-back - (fn [cofx [_ on-close]] - (fx/merge cofx - (when on-close - {:dispatch on-close}) - (navigation/navigate-back) - (models/update-wallet)))) - -(handlers/register-handler-fx - :update-balance-success - (fn [{:keys [db]} [_ balance]] - {:db (-> db - (assoc-in [:wallet :balance :ETH] balance) - (assoc-in [:wallet :balance-loading?] false))})) - -(handlers/register-handler-fx - :update-balance-fail - (fn [{:keys [db]} [_ err]] - (log/debug "Unable to get balance: " err) - {:db (-> db - (assoc-error-message :balance-update :error-unable-to-get-balance) - (assoc-in [:wallet :balance-loading?] false))})) - -(fx/defn update-token-balance-success [{:keys [db]} symbol balance] - {:db (-> db - (assoc-in [:wallet :balance symbol] balance) - (assoc-in [:wallet :balance-loading?] false))}) - -(handlers/register-handler-fx - :update-token-balance-success - (fn [cofx [_ symbol balance]] - (update-token-balance-success cofx symbol balance))) - -(handlers/register-handler-fx - :update-token-balance-fail - (fn [{:keys [db]} [_ symbol err]] - (log/debug "Unable to get token " symbol "balance: " err) - {:db (-> db - (assoc-error-message :balance-update :error-unable-to-get-token-balance) - (assoc-in [:wallet :balance-loading?] false))})) - -(handlers/register-handler-fx - :update-prices-success - (fn [{:keys [db]} [_ prices]] - {:db (assoc db - :prices prices - :prices-loading? false)})) - -(handlers/register-handler-fx - :update-prices-fail - (fn [{:keys [db]} [_ err]] - (log/debug "Unable to get prices: " err) - {:db (-> db - (assoc-error-message :prices-update :error-unable-to-get-prices) - (assoc :prices-loading? false))})) - -(handlers/register-handler-fx - :show-transaction-details - (fn [{:keys [db]} [_ hash]] - {:db (assoc-in db [:wallet :current-transaction] hash) - :dispatch [:navigate-to :wallet-transaction-details]})) - -(handlers/register-handler-fx - :wallet/show-sign-transaction - (fn [{:keys [db]} [_ {:keys [id method]} from-chat?]] - {:db (assoc-in db [:wallet :send-transaction] {:id id - :method method - :from-chat? from-chat?}) - :dispatch [:navigate-to-clean :wallet-send-transaction-modal]})) - -(handlers/register-handler-fx - :wallet/update-gas-price-success - (fn [{:keys [db] :as cofx} [_ price edit?]] - (if edit? - (models/edit-value - :gas-price - (money/to-fixed - (money/wei-> :gwei price)) - cofx) - {:db (assoc-in db [:wallet :send-transaction :gas-price] price)}))) - -(handlers/register-handler-fx - :wallet/update-estimated-gas - (fn [{:keys [db]} [_ obj]] - {:update-estimated-gas {:web3 (:web3 db) - :obj obj - :success-event :wallet/update-estimated-gas-success}})) - -(handlers/register-handler-fx - :wallet/update-estimated-gas-success - (fn [{:keys [db]} [_ gas]] - (when gas - (let [adjusted-gas (money/bignumber (int (* gas 1.2))) - db-with-adjusted-gas (assoc-in db [:wallet :send-transaction :gas] adjusted-gas)] - {:db (if (some? (-> db :wallet :send-transaction :original-gas)) - db-with-adjusted-gas - (assoc-in db-with-adjusted-gas [:wallet :send-transaction :original-gas] adjusted-gas))})))) - -(handlers/register-handler-fx - :wallet.setup-ui/navigate-back-pressed - (fn [{:keys [db] :as cofx}] - (fx/merge cofx - {:db (assoc-in db [:wallet :send-transaction] {})} - (navigation/navigate-back)))) diff --git a/src/status_im/ui/screens/wallet/main/views.cljs b/src/status_im/ui/screens/wallet/main/views.cljs index f278e83ac2..e4e7d02109 100644 --- a/src/status_im/ui/screens/wallet/main/views.cljs +++ b/src/status_im/ui/screens/wallet/main/views.cljs @@ -167,11 +167,7 @@ [react/scroll-view {:end-fill-color colors/white :refresh-control (reagent/as-element - [react/refresh-control {:on-refresh (fn [_] - ;;TODO temporay fix to update balance, should be fixed - ;;properly later - (re-frame/dispatch [:wallet.ui/pull-to-refresh]) - (re-frame/dispatch [:update-wallet])) + [react/refresh-control {:on-refresh #(re-frame/dispatch [:wallet.ui/pull-to-refresh]) :tint-color :white :refreshing false}])} (if error-message diff --git a/src/status_im/ui/screens/wallet/navigation.cljs b/src/status_im/ui/screens/wallet/navigation.cljs index 2f03b1b42d..ea606f14bb 100644 --- a/src/status_im/ui/screens/wallet/navigation.cljs +++ b/src/status_im/ui/screens/wallet/navigation.cljs @@ -2,29 +2,7 @@ (:require [re-frame.core :as re-frame] [status-im.constants :as constants] [status-im.ui.screens.navigation :as navigation] - [status-im.utils.ethereum.core :as ethereum] - [status-im.constants :as constants] - [status-im.utils.utils :as utils])) - -(defmethod navigation/preload-data! :wallet - [db _] - ;;TODO(goranjovic) - get rid of this preload hook completely - ;;TODO(andrey) - temporary "improvement" with timeout, to fix screen rendering, wallet update should be optimized - (utils/set-timeout (fn [] - (re-frame/dispatch [:wallet.ui/pull-to-refresh]) - (re-frame/dispatch [:update-wallet])) - 500) - db) - -(defmethod navigation/preload-data! :wallet-stack - [db _] - ;;TODO(goranjovic) - get rid of this preload hook completely - ;;TODO(andrey) - temporary "improvement" with timeout, to fix screen rendering, wallet update should be optimized - (utils/set-timeout (fn [] - (re-frame/dispatch [:wallet.ui/pull-to-refresh]) - (re-frame/dispatch [:update-wallet])) - 500) - db) + [status-im.utils.ethereum.core :as ethereum])) (def transaction-send-default (let [symbol :ETH] diff --git a/src/status_im/ui/screens/wallet/onboarding/views.cljs b/src/status_im/ui/screens/wallet/onboarding/views.cljs index 913b47a8d5..181473d323 100644 --- a/src/status_im/ui/screens/wallet/onboarding/views.cljs +++ b/src/status_im/ui/screens/wallet/onboarding/views.cljs @@ -55,7 +55,7 @@ ^{:key "toolbar"} [wallet.components/toolbar {:transparent? true} - (actions/back-white #(re-frame/dispatch [:wallet.setup-ui/navigate-back-pressed])) + (actions/back-white #(re-frame/dispatch [:wallet.setup.ui/navigate-back-pressed])) (i18n/label :t/wallet-set-up-title)]) (defn main-panel [signing-phrase on-confirm] diff --git a/src/status_im/ui/screens/wallet/send/events.cljs b/src/status_im/ui/screens/wallet/send/events.cljs index be7ff0c9a7..53e753969f 100644 --- a/src/status_im/ui/screens/wallet/send/events.cljs +++ b/src/status_im/ui/screens/wallet/send/events.cljs @@ -3,11 +3,9 @@ [status-im.chat.commands.sending :as commands-sending] [status-im.constants :as constants] [status-im.i18n :as i18n] - [status-im.models.wallet :as models.wallet] [status-im.native-module.core :as status] [status-im.transport.utils :as transport.utils] [status-im.ui.screens.navigation :as navigation] - [status-im.wallet.db :as wallet.db] [status-im.utils.ethereum.core :as ethereum] [status-im.utils.ethereum.erc20 :as erc20] [status-im.utils.ethereum.tokens :as tokens] @@ -16,7 +14,9 @@ [status-im.utils.money :as money] [status-im.utils.security :as security] [status-im.utils.types :as types] - [status-im.utils.utils :as utils])) + [status-im.utils.utils :as utils] + [status-im.wallet.core :as wallet] + [status-im.wallet.db :as wallet.db])) ;;;; FX @@ -66,7 +66,7 @@ {:db (-> db (assoc-in [:wallet :send-transaction :wrong-password?] false) (assoc-in [:wallet :send-transaction :in-progress?] true)) - ::send-transaction [(models.wallet/prepare-send-transaction from transaction) + ::send-transaction [(wallet/prepare-send-transaction from transaction) all-tokens symbol chain @@ -116,7 +116,7 @@ modal-screen-was-used? (get-in db [:navigation/screen-params :wallet-send-modal-stack :modal?])] (if error ;; ERROR - (models.wallet/handle-transaction-error (assoc cofx :db db') error) + (wallet/handle-transaction-error (assoc cofx :db db') error) ;; RESULT (fx/merge cofx (merge @@ -124,7 +124,7 @@ (not (constants/web3-sign-message? method)) (assoc-in [:wallet :transactions result] - (models.wallet/prepare-unconfirmed-transaction db now result)))} + (wallet/prepare-unconfirmed-transaction db now result)))} (when on-result {:dispatch (conj on-result id result method)})) #(when (or (not on-result) @@ -168,7 +168,7 @@ db' (assoc-in db [:wallet :send-transaction :in-progress?] false)] (if error ;; ERROR - (models.wallet/handle-transaction-error (assoc cofx :db db') error) + (wallet/handle-transaction-error (assoc cofx :db db') error) ;; RESULT (fx/merge cofx {:db (-> db @@ -186,19 +186,19 @@ (handlers/register-handler-fx :wallet/discard-transaction (fn [cofx _] - (models.wallet/discard-transaction cofx))) + (wallet/discard-transaction cofx))) (handlers/register-handler-fx :wallet.dapp/transaction-on-result (fn [{db :db} [_ message-id id result method]] (let [webview (:webview-bridge db) keycard? (boolean (get-in db [:account/account :keycard-instance-uid]))] - (models.wallet/dapp-complete-transaction (int id) result method message-id webview keycard?)))) + (wallet/dapp-complete-transaction (int id) result method message-id webview keycard?)))) (handlers/register-handler-fx :wallet.dapp/transaction-on-error (fn [{db :db} [_ message-id message]] - (models.wallet/web3-error-callback {} db message-id message))) + (wallet/web3-error-callback {} db message-id message))) ;; DAPP TRANSACTIONS QUEUE ;; NOTE(andrey) We need this queue because dapp can send several transactions in a row, this is bad behaviour @@ -219,13 +219,13 @@ ;;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))) + (let [transaction (wallet/prepare-dapp-transaction queued-transaction (:contacts/contacts db))] + (wallet/open-modal-wallet-for-transaction db' transaction (first params))) ;;SIGN MESSAGE (constants/web3-sign-message? method) (let [typed? (not= constants/web3-personal-sign method) - [address data] (models.wallet/normalize-sign-message-params params)] + [address data] (wallet/normalize-sign-message-params params)] (if (and address data) (let [signing-phrase (-> (get-in db [:account/account :signing-phrase]) (clojure.string/replace-all #" " " ")) @@ -259,7 +259,7 @@ (fn [cofx _] (fx/merge cofx (navigation/navigate-back) - (models.wallet/discard-transaction)))) + (wallet/discard-transaction)))) (defn update-gas-price ([db edit? success-event] @@ -311,7 +311,7 @@ (handlers/register-handler-fx :wallet.send/edit-value (fn [cofx [_ key value]] - (models.wallet/edit-value key value cofx))) + (wallet/edit-value key value cofx))) (handlers/register-handler-fx :wallet.send/set-gas-details @@ -333,7 +333,7 @@ (money/to-fixed (ethereum/estimate-gas (-> db :wallet :send-transaction :symbol))))] - (assoc (models.wallet/edit-value + (assoc (wallet/edit-value :gas gas-default cofx) @@ -364,9 +364,9 @@ (defn- prepare-keycard-transaction [transaction from symbol chain all-tokens] (if (= :ETH symbol) - (models.wallet/prepare-send-transaction from transaction) + (wallet/prepare-send-transaction from transaction) (let [contract (:address (tokens/symbol->token all-tokens (keyword chain) symbol)) - {:keys [gas gasPrice to from value]} (models.wallet/prepare-send-transaction from transaction)] + {:keys [gas gasPrice to from value]} (wallet/prepare-send-transaction from transaction)] (merge (ethereum/call-params contract "transfer(address,uint256)" to value) {:from from :gas gas diff --git a/src/status_im/ui/screens/wallet/settings/events.cljs b/src/status_im/ui/screens/wallet/settings/events.cljs deleted file mode 100644 index 636fe3f244..0000000000 --- a/src/status_im/ui/screens/wallet/settings/events.cljs +++ /dev/null @@ -1,19 +0,0 @@ -(ns status-im.ui.screens.wallet.settings.events - (:require [status-im.ui.screens.wallet.settings.models :as models] - - [status-im.utils.handlers :as handlers])) - -(handlers/register-handler-fx - :wallet.settings/toggle-visible-token - (fn [cofx [_ symbol checked?]] - (models/toggle-visible-token cofx symbol checked?))) - -(handlers/register-handler-fx - :configure-token-balance-and-visibility - (fn [cofx [_ symbol balance]] - (models/configure-token-balance-and-visibility cofx symbol balance))) - -(handlers/register-handler-fx - :wallet.ui/pull-to-refresh - (fn [cofx _] - (models/wallet-autoconfig-tokens cofx))) diff --git a/src/status_im/ui/screens/wallet/settings/models.cljs b/src/status_im/ui/screens/wallet/settings/models.cljs deleted file mode 100644 index adc841190c..0000000000 --- a/src/status_im/ui/screens/wallet/settings/models.cljs +++ /dev/null @@ -1,58 +0,0 @@ -(ns status-im.ui.screens.wallet.settings.models - (:require [re-frame.core :as re-frame] - [status-im.accounts.update.core :as accounts.update] - [status-im.ui.screens.wallet.events :as wallet.events] - [status-im.utils.ethereum.core :as ethereum] - [status-im.utils.ethereum.tokens :as tokens] - [status-im.utils.fx :as fx])) - -(defn- set-checked [ids id checked?] - (if checked? - (conj (or ids #{}) id) - (disj ids id))) - -(defn update-toggle-in-settings [{{:account/keys [account]} :db} symbol checked?] - (let [network (get (:networks account) (:network account)) - chain (ethereum/network->chain-keyword network) - settings (get account :settings)] - (update-in settings [:wallet :visible-tokens chain] #(set-checked % symbol checked?)))) - -(fx/defn toggle-visible-token [cofx symbol checked?] - (let [new-settings (update-toggle-in-settings cofx symbol checked?)] - (accounts.update/update-settings cofx new-settings {}))) - -(fx/defn add-custom-token [{{:account/keys [account]} :db :as cofx} {:keys [symbol address] :as token}] - (let [network (get (:networks account) (:network account)) - chain (ethereum/network->chain-keyword network) - settings (update-toggle-in-settings cofx symbol true) - new-settings (assoc-in settings [:wallet :custom-tokens chain address] token)] - (accounts.update/update-settings cofx new-settings {}))) - -(fx/defn remove-custom-token [{{:account/keys [account]} :db :as cofx} {:keys [symbol address]}] - (let [network (get (:networks account) (:network account)) - chain (ethereum/network->chain-keyword network) - settings (update-toggle-in-settings cofx symbol false) - new-settings (update-in settings [:wallet :custom-tokens chain] dissoc address)] - (accounts.update/update-settings cofx new-settings {}))) - -(fx/defn configure-token-balance-and-visibility [cofx symbol balance] - (fx/merge cofx - (toggle-visible-token symbol true) - ;;TODO(goranjovic): move `update-token-balance-success` function to wallet models - (wallet.events/update-token-balance-success symbol balance))) - -(fx/defn wallet-autoconfig-tokens [{:keys [db]}] - (let [{:keys [account/account web3 network-status] :wallet/keys [all-tokens]} db - network (get (:networks account) (:network account)) - chain (ethereum/network->chain-keyword network) - contracts (->> (tokens/tokens-for all-tokens chain) - (remove :hidden?))] - (when-not (= network-status :offline) - (doseq [{:keys [address symbol]} contracts] - ;;TODO(goranjovic): move `get-token-balance` function to wallet models - (wallet.events/get-token-balance {:web3 web3 - :contract address - :account-id (:address account) - :on-error #(re-frame/dispatch [:update-token-balance-fail symbol %]) - :on-success #(when (> % 0) - (re-frame/dispatch [:configure-token-balance-and-visibility symbol %]))}))))) diff --git a/src/status_im/ui/screens/wallet/settings/views.cljs b/src/status_im/ui/screens/wallet/settings/views.cljs index 351043d74c..389c60e7e7 100644 --- a/src/status_im/ui/screens/wallet/settings/views.cljs +++ b/src/status_im/ui/screens/wallet/settings/views.cljs @@ -19,7 +19,8 @@ (defn toolbar [] [toolbar/toolbar nil [toolbar/nav-button - (toolbar.actions/back #(re-frame/dispatch [:update-wallet-and-nav-back]))] + (toolbar.actions/back #(re-frame/dispatch + [:wallet.settings.ui/navigate-back-pressed]))] [toolbar/content-title (i18n/label :t/wallet-assets)]]) @@ -96,7 +97,7 @@ {:style {:border-bottom-color colors/white-light-transparent}} [toolbar/nav-button (actions/back-white - #(re-frame/dispatch [:update-wallet-and-nav-back + #(re-frame/dispatch [:wallet.settings.ui/navigate-back-pressed (when (fn? on-close) (on-close (create-payload address)))]))] [toolbar/content-title {:color colors/white} diff --git a/src/status_im/utils/ethereum/contracts.cljs b/src/status_im/utils/ethereum/contracts.cljs index 51003e7037..8cecd9f30a 100644 --- a/src/status_im/utils/ethereum/contracts.cljs +++ b/src/status_im/utils/ethereum/contracts.cljs @@ -1,10 +1,10 @@ (ns status-im.utils.ethereum.contracts (:require [re-frame.core :as re-frame] - [status-im.models.wallet :as wallet] [status-im.utils.ethereum.abi-spec :as abi-spec] [status-im.utils.ethereum.core :as ethereum] [status-im.utils.fx :as fx] - [status-im.utils.money :as money])) + [status-im.utils.money :as money] + [status-im.wallet.core :as wallet])) (def contracts {:status/snt diff --git a/src/status_im/wallet/core.cljs b/src/status_im/wallet/core.cljs new file mode 100644 index 0000000000..92373e0f98 --- /dev/null +++ b/src/status_im/wallet/core.cljs @@ -0,0 +1,557 @@ +(ns status-im.wallet.core + (:require [clojure.set :as set] + [re-frame.core :as re-frame] + [status-im.accounts.update.core :as accounts.update] + [status-im.constants :as constants] + [status-im.i18n :as i18n] + [status-im.ui.screens.navigation :as navigation] + [status-im.ui.screens.wallet.utils :as wallet.utils] + [status-im.utils.config :as config] + [status-im.utils.core :as utils.core] + [status-im.utils.ethereum.core :as ethereum] + [status-im.utils.ethereum.erc20 :as erc20] + [status-im.utils.ethereum.tokens :as tokens] + [status-im.utils.fx :as fx] + [status-im.utils.hex :as utils.hex] + [status-im.utils.money :as money] + [status-im.utils.prices :as prices] + [status-im.utils.utils :as utils.utils] + [taoensso.timbre :as log])) + +(defn get-balance [{:keys [web3 account-id on-success on-error]}] + (if (and web3 account-id) + (.getBalance + (.-eth web3) + account-id + (fn [err resp] + (if-not err + (on-success resp) + (on-error err)))) + (on-error "web3 or account-id not available"))) + +(defn get-token-balance + [{:keys [web3 contract account-id on-success on-error]}] + (if (and web3 contract account-id) + (erc20/balance-of + web3 + contract + (ethereum/normalized-address account-id) + (fn [err resp] + (if-not err + (on-success resp) + (on-error err)))) + (on-error "web3, contract or account-id not available"))) + +(defn assoc-error-message [db error-type err] + (assoc-in db [:wallet :errors error-type] (or err :unknown-error))) + +(fx/defn on-update-prices-fail + [{:keys [db]} err] + (log/debug "Unable to get prices: " err) + {:db (-> db + (assoc-error-message :prices-update :error-unable-to-get-prices) + (assoc :prices-loading? false))}) + +(fx/defn on-update-balance-fail + [{:keys [db]} err] + (log/debug "Unable to get balance: " err) + {:db (-> db + (assoc-error-message :balance-update :error-unable-to-get-balance) + (assoc-in [:wallet :balance-loading?] false))}) + +(fx/defn on-update-token-balance-fail + [{:keys [db]} symbol err] + (log/debug "Unable to get token " symbol "balance: " err) + {:db (-> db + (assoc-error-message :balance-update :error-unable-to-get-token-balance) + (assoc-in [:wallet :balance-loading?] false))}) + +(fx/defn open-transaction-details + [{:keys [db] :as cofx} hash] + (fx/merge cofx + {:db (assoc-in db [:wallet :current-transaction] hash)} + (navigation/navigate-to-cofx :wallet-transaction-details nil))) + +(fx/defn open-send-transaction-modal + [{:keys [db] :as cofx} id method from-chat?] + (fx/merge cofx + {:db (assoc-in db [:wallet :send-transaction] {:id id + :method method + :from-chat? from-chat?})} + (navigation/navigate-to-clean :wallet-send-transaction-modal nil))) + +;; FX + +(re-frame/reg-fx + :get-balance + (fn [{:keys [web3 account-id success-event error-event]}] + (get-balance {:web3 web3 + :account-id account-id + :on-success #(re-frame/dispatch [success-event %]) + :on-error #(re-frame/dispatch [error-event %])}))) + +(re-frame/reg-fx + :get-tokens-balance + (fn [{:keys [web3 symbols all-tokens chain account-id success-event error-event]}] + (doseq [symbol symbols] + (let [contract (:address (tokens/symbol->token all-tokens chain symbol))] + (get-token-balance {:web3 web3 + :contract contract + :account-id account-id + :on-success #(re-frame/dispatch [success-event symbol %]) + :on-error #(re-frame/dispatch [error-event symbol %])}))))) + +;; TODO(oskarth): At some point we want to get list of relevant assets to get prices for +(re-frame/reg-fx + :get-prices + (fn [{:keys [from to mainnet? success-event error-event chaos-mode?]}] + (prices/get-prices from + to + mainnet? + #(re-frame/dispatch [success-event %]) + #(re-frame/dispatch [error-event %]) + chaos-mode?))) + +(re-frame/reg-fx + :update-gas-price + (fn [{:keys [web3 success-event edit?]}] + (ethereum/gas-price web3 #(re-frame/dispatch [success-event %2 edit?])))) + +(re-frame/reg-fx + :update-estimated-gas + (fn [{:keys [web3 obj success-event]}] + (ethereum/estimate-gas-web3 web3 (clj->js obj) #(re-frame/dispatch [success-event %2])))) + +(defn- validate-token-name! [web3 {:keys [address symbol name]}] + (erc20/name web3 address #(when (and (seq %2) ;;NOTE(goranjovic): skipping check if field not set in contract + (not= name %2)) + (let [message (i18n/label :t/token-auto-validate-name-error + {:symbol symbol + :expected name + :actual %2 + :address address})] + (log/warn message) + (utils.utils/show-popup (i18n/label :t/warning) message))))) + +(defn- validate-token-symbol! [web3 {:keys [address symbol]}] + (erc20/symbol web3 address #(when (and (seq %2) ;;NOTE(goranjovic): skipping check if field not set in contract + (not= (clojure.core/name symbol) %2)) + (let [message (i18n/label :t/token-auto-validate-symbol-error + {:symbol symbol + :expected (clojure.core/name symbol) + :actual %2 + :address address})] + (log/warn message) + (utils.utils/show-popup (i18n/label :t/warning) message))))) + +(defn- validate-token-decimals! [web3 {:keys [address symbol decimals nft? skip-decimals-check?]}] + ;;NOTE(goranjovic): only skipping check if skip-decimals-check? flag is present because we can't differentiate + ;;between unset decimals and 0 decimals. + (when-not skip-decimals-check? + (erc20/decimals web3 address #(when (and %2 + (not nft?) + (not= decimals (int %2))) + (let [message (i18n/label :t/token-auto-validate-decimals-error + {:symbol symbol + :expected decimals + :actual %2 + :address address})] + (log/warn message) + (utils.utils/show-popup (i18n/label :t/warning) message)))))) + +(re-frame/reg-fx + :wallet/validate-tokens + (fn [{:keys [web3 tokens]}] + (doseq [token tokens] + (validate-token-decimals! web3 token) + (validate-token-symbol! web3 token) + (validate-token-name! web3 token)))) + +(re-frame/reg-fx + :wallet/check-all-known-tokens-balance + (fn [{:keys [web3 contracts account]}] + (doseq [{:keys [address symbol]} contracts] + ;;TODO(goranjovic): move `get-token-balance` function to wallet models + (get-token-balance {:web3 web3 + :contract address + :account-id (:address account) + :on-error #(re-frame/dispatch [:update-token-balance-fail symbol %]) + :on-success #(when (> % 0) + (re-frame/dispatch [:wallet/token-found symbol %]))})))) + +(fx/defn wallet-autoconfig-tokens + [{:keys [db] :as cofx}] + (let [{:keys [account/account web3 network-status] :wallet/keys [all-tokens]} db + network (get (:networks account) (:network account)) + chain (ethereum/network->chain-keyword network) + contracts (->> (tokens/tokens-for all-tokens chain) + (remove :hidden?)) + settings (:settings account) + assets (get-in settings [:wallet :visible-tokens chain])] + (when-not (or (= network-status :offline) + assets) + (let [new-settings (assoc-in settings + [:wallet :visible-tokens chain] + #{})] + (fx/merge cofx + {:wallet/check-all-known-tokens-balance {:web3 web3 + :contracts contracts + :account account}} + (accounts.update/update-settings new-settings {})))))) + +(def min-gas-price-wei (money/bignumber 1)) + +(defmulti invalid-send-parameter? (fn [type _] type)) + +(defmethod invalid-send-parameter? :gas-price [_ value] + (cond + (not value) :invalid-number + (.lt (money/->wei :gwei value) min-gas-price-wei) :not-enough-wei + (-> (money/->wei :gwei value) .decimalPlaces pos?) :invalid-number)) + +(defmethod invalid-send-parameter? :default [_ value] + (when (or (not value) + (<= value 0)) + :invalid-number)) + +(defn- calculate-max-fee + [gas gas-price] + (if (and gas gas-price) + (money/to-fixed (money/wei->ether (.times gas gas-price))) + "0")) + +(defn- edit-max-fee [edit] + (let [gas (get-in edit [:gas-price :value-number]) + gas-price (get-in edit [:gas :value-number])] + (assoc edit :max-fee (calculate-max-fee gas gas-price)))) + +(defn add-max-fee [{:keys [gas gas-price] :as transaction}] + (assoc transaction :max-fee (calculate-max-fee gas gas-price))) + +(defn build-edit [edit-value key value] + "Takes the previous edit, either :gas or :gas-price and a value as string. + Wei for gas, and gwei for gas price. + Validates them and sets max fee" + (let [bn-value (money/bignumber value) + invalid? (invalid-send-parameter? key bn-value) + data (if invalid? + {:value value + :max-fee 0 + :invalid? invalid?} + {:value value + :value-number (if (= :gas-price key) + (money/->wei :gwei bn-value) + bn-value) + :invalid? false})] + (-> edit-value + (assoc key data) + edit-max-fee))) + +(defn edit-value + [key value {:keys [db]}] + {:db (update-in db [:wallet :edit] build-edit key value)}) + +;; DAPP TRANSACTION -> SEND TRANSACTION +(defn prepare-dapp-transaction [{{:keys [id method params]} :payload message-id :message-id} contacts] + (let [{:keys [to value data gas gasPrice nonce]} (first params) + contact (get contacts (utils.hex/normalize-hex to))] + (cond-> {:id (str id) + :to-name (or (when (nil? to) + (i18n/label :t/new-contract)) + contact) + :symbol :ETH + :method method + :to to + :amount (money/bignumber (or value 0)) + :gas (cond + gas + (money/bignumber gas) + (and value (empty? data)) + (money/bignumber 21000)) + :gas-price (when gasPrice + (money/bignumber gasPrice)) + :data data + :on-result [:wallet.dapp/transaction-on-result message-id] + :on-error [:wallet.dapp/transaction-on-error message-id]} + nonce + (assoc :nonce nonce)))) + +;; SEND TRANSACTION -> RPC TRANSACTION +(defn prepare-send-transaction [from {:keys [amount to gas 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)} + data + (assoc :data data) + nonce + (assoc :nonce nonce))) + +;; NOTE (andrey) we need this function, because params may be mixed up, so we need to figure out which one is address +;; and which message +(defn normalize-sign-message-params [params] + (let [first_param (first params) + second_param (second params) + first-param-address? (ethereum/address? first_param) + second-param-address? (ethereum/address? second_param)] + (when (or first-param-address? second-param-address?) + (if first-param-address? + [first_param second_param] + [second_param first_param])))) + +(defn web3-error-callback [fx {:keys [webview-bridge]} message-id message] + (assoc fx :browser/send-to-bridge {:message {:type constants/web3-send-async-callback + :messageId message-id + :error message} + :webview webview-bridge})) + +(defn dapp-complete-transaction [id result method message-id webview keycard?] + (cond-> {:browser/send-to-bridge {:message {:type constants/web3-send-async-callback + :messageId message-id + :result {:jsonrpc "2.0" + :id (int id) + :result result}} + :webview webview} + :dispatch [:navigate-back]} + + (constants/web3-sign-message? method) + (assoc :dispatch (if keycard? [:navigate-to :browser] [:navigate-back])) + + (= method constants/web3-send-transaction) + (assoc :dispatch [:navigate-to-clean :wallet-transaction-sent-modal]))) + +(fx/defn discard-transaction + [{:keys [db]}] + (let [{:keys [on-error]} (get-in db [:wallet :send-transaction])] + (merge {:db (update db :wallet + assoc + :send-transaction {} + :transactions-queue nil)} + (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)] + (let [chain (:chain db) + token (tokens/symbol->token all-tokens (keyword chain) (:symbol transaction))] + (-> transaction + (assoc :confirmations "0" + :timestamp (str now) + :type :outbound + :hash hash + :value (:amount transaction) + :token token + :gas-limit (str (:gas transaction))) + (update :gas-price str) + (dissoc :message-id :id :gas))))) + +(fx/defn handle-transaction-error + [{:keys [db] :as cofx} {:keys [code message]}] + (let [{:keys [on-error]} (get-in db [:wallet :send-transaction])] + (case code + ;;WRONG PASSWORD + constants/send-transaction-err-decrypt + {:db (-> db + (assoc-in [:wallet :send-transaction :wrong-password?] true))} + + (fx/merge cofx + (merge {:db (-> db + (assoc-in [:wallet :transactions-queue] nil) + (assoc-in [:wallet :send-transaction] {})) + :wallet/show-transaction-error message} + (when on-error + {:dispatch (conj on-error message)})) + navigation/navigate-back)))) + +(defn clear-error-message [db error-type] + (update-in db [:wallet :errors] dissoc error-type)) + +(defn tokens-symbols [visible-token-symbols all-tokens chain] + (set/difference (set visible-token-symbols) (set (map :symbol (tokens/nfts-for all-tokens chain))))) + +(fx/defn initialize-tokens + [{:keys [db] :as cofx}] + (let [network-id (get-in db [:account/account :network]) + network (get-in db [:account/account :networks network-id]) + custom-tokens (get-in db [:account/account :settings :wallet :custom-tokens]) + chain (ethereum/network->chain-keyword network) + all-tokens (merge-with + merge + (utils.core/map-values #(utils.core/index-by :address %) + tokens/all-default-tokens) + custom-tokens)] + (fx/merge cofx + (merge + {:db (assoc db :wallet/all-tokens all-tokens)} + (when config/erc20-contract-warnings-enabled? + {:wallet/validate-tokens {:web3 (:web3 db) + :tokens (get tokens/all-default-tokens chain)}})) + wallet-autoconfig-tokens))) + +(fx/defn update-wallet + [{{:keys [web3 network network-status] + {:keys [address settings]} :account/account :as db} :db}] + (let [all-tokens (:wallet/all-tokens db) + network (get-in db [:account/account :networks network]) + chain (ethereum/network->chain-keyword network) + mainnet? (= :mainnet chain) + assets (get-in settings [:wallet :visible-tokens chain]) + tokens (tokens-symbols (get-in settings [:wallet :visible-tokens chain]) all-tokens chain) + currency-id (or (get-in settings [:wallet :currency]) :usd) + currency (get constants/currencies currency-id)] + (when (not= network-status :offline) + {:get-balance {:web3 web3 + :account-id address + :success-event :wallet.callback/update-balance-success + :error-event :wallet.callback/update-balance-fail} + :get-tokens-balance {:web3 web3 + :account-id address + :symbols assets + :chain chain + :all-tokens all-tokens + :success-event :wallet.callback/update-token-balance-success + :error-event :wallet.callback/update-token-balance-fail} + :get-prices {:from (if mainnet? + (conj tokens "ETH") + [(-> (tokens/native-currency chain) + (wallet.utils/exchange-symbol))]) + :to [(:code currency)] + :mainnet? mainnet? + :success-event :wallet.callback/update-prices-success + :error-event :wallet.callback/update-prices-fail + :chaos-mode? (:chaos-mode? settings)} + :db (-> db + (clear-error-message :prices-update) + (clear-error-message :balance-update) + (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 + {:keys [wallet-set-up-passed?]} (:account/account db)] + {:db (-> db + (assoc-in [:navigation/screen-params :wallet-send-modal-stack :modal?] true) + (assoc-in [:wallet :send-transaction] transaction) + (assoc-in [:wallet :send-transaction :original-gas] gas)) + :dispatch-n [[:TODO.remove/update-wallet] + (when-not gas + [:TODO.remove/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)]]})) +2 +(fx/defn open-sign-transaction-flow + [{:keys [db] :as cofx} {:keys [gas gas-price] :as transaction}] + (let [go-to-view-id (if (get-in db [:account/account :wallet-set-up-passed?]) + :wallet-send-modal-stack + :wallet-send-modal-stack-with-onboarding)] + (fx/merge cofx + (cond-> {:db (-> db + (assoc-in [:navigation/screen-params :wallet-send-modal-stack :modal?] true) + (assoc-in [:wallet :send-transaction] + transaction) + (assoc-in [:wallet :send-transaction :original-gas] + gas))} + (not gas) + (assoc :update-estimated-gas + {:web3 (:web3 db) + :obj (select-keys transaction [:to :data]) + :success-event :wallet/update-estimated-gas-success}) + + (not gas-price) + (assoc :update-gas-price + {:web3 (:web3 db) + :success-event :wallet/update-gas-price-success + :edit? false})) + (update-wallet) + (navigation/navigate-to-cofx go-to-view-id {})))) + +(defn send-transaction-screen-did-load + [{:keys [db]}] + {:db (assoc-in db + [:navigation/screen-params :wallet-send-modal-stack :modal?] + false)}) + +(defn- set-checked [ids id checked?] + (if checked? + (conj (or ids #{}) id) + (disj ids id))) + +(fx/defn update-prices + [{:keys [db]} prices] + {:db (assoc db + :prices prices + :prices-loading? false)}) + +(fx/defn update-balance + [{:keys [db]} balance] + {:db (-> db + (assoc-in [:wallet :balance :ETH] balance) + (assoc-in [:wallet :balance-loading?] false))}) + +(fx/defn update-token-balance + [{:keys [db]} symbol balance] + {:db (-> db + (assoc-in [:wallet :balance symbol] balance) + (assoc-in [:wallet :balance-loading?] false))}) + +(fx/defn update-gas-price + [{:keys [db] :as cofx} price edit?] + (if edit? + (edit-value + :gas-price + (money/to-fixed + (money/wei-> :gwei price)) + cofx) + {:db (assoc-in db [:wallet :send-transaction :gas-price] price)})) + +(fx/defn update-estimated-gas-price + [{:keys [db]} gas] + (when gas + (let [adjusted-gas (money/bignumber (int (* gas 1.2))) + db-with-adjusted-gas (assoc-in db + [:wallet :send-transaction :gas] + adjusted-gas)] + {:db (if (some? (-> db :wallet :send-transaction :original-gas)) + db-with-adjusted-gas + (assoc-in db-with-adjusted-gas + [:wallet :send-transaction :original-gas] + adjusted-gas))}))) + +(defn update-toggle-in-settings + [{{:account/keys [account]} :db} symbol checked?] + (let [network (get (:networks account) (:network account)) + chain (ethereum/network->chain-keyword network) + settings (get account :settings)] + (update-in settings [:wallet :visible-tokens chain] #(set-checked % symbol checked?)))) + +(fx/defn toggle-visible-token + [cofx symbol checked?] + (let [new-settings (update-toggle-in-settings cofx symbol checked?)] + (accounts.update/update-settings cofx new-settings {}))) + +(fx/defn add-custom-token + [{{:account/keys [account]} :db :as cofx} {:keys [symbol address] :as token}] + (let [network (get (:networks account) (:network account)) + chain (ethereum/network->chain-keyword network) + settings (update-toggle-in-settings cofx symbol true) + new-settings (assoc-in settings [:wallet :custom-tokens chain address] token)] + (accounts.update/update-settings cofx new-settings {}))) + +(fx/defn remove-custom-token [{{:account/keys [account]} :db :as cofx} {:keys [symbol address]}] + (let [network (get (:networks account) (:network account)) + chain (ethereum/network->chain-keyword network) + settings (update-toggle-in-settings cofx symbol false) + new-settings (update-in settings [:wallet :custom-tokens chain] dissoc address)] + (accounts.update/update-settings cofx new-settings {}))) + +(fx/defn configure-token-balance-and-visibility [cofx symbol balance] + (fx/merge cofx + (toggle-visible-token symbol true) + ;;TODO(goranjovic): move `update-token-balance-success` function to wallet models + (update-token-balance symbol balance))) diff --git a/src/status_im/wallet/custom_tokens/core.cljs b/src/status_im/wallet/custom_tokens/core.cljs index 1ef3793436..85fa604a15 100644 --- a/src/status_im/wallet/custom_tokens/core.cljs +++ b/src/status_im/wallet/custom_tokens/core.cljs @@ -8,7 +8,7 @@ [clojure.string :as string] [status-im.ethereum.decode :as decode] [status-im.utils.fx :as fx] - [status-im.ui.screens.wallet.settings.models :as models])) + [status-im.wallet.core :as wallet])) (re-frame/reg-fx :wallet.custom-token/get-decimals @@ -111,12 +111,12 @@ new-token {:address contract :name name :symbol symbol :custom? true :decimals (int decimals) :color (rand-nth colors/chat-colors)}] (fx/merge (assoc-in cofx [:db :wallet/all-tokens chain-key contract] new-token) - (models/add-custom-token new-token)))) + (wallet/add-custom-token new-token)))) (fx/defn remove-custom-token [{:keys [db] :as cofx} {:keys [address] :as token}] (let [chain-key (ethereum/get-chain-keyword db)] (fx/merge (update-in cofx [:db :wallet/all-tokens chain-key] dissoc address) - (models/remove-custom-token token)))) + (wallet/remove-custom-token token)))) (fx/defn field-is-edited [{:keys [db] :as cofx} field-key value] (case field-key @@ -133,4 +133,4 @@ :error-symbol (when (field-exists? db field-key (keyword value)) (i18n/label :t/you-already-have-an-asset {:value value}))})} - :decimals {:db (assoc-in db [:wallet/custom-token-screen :decimals] value)})) \ No newline at end of file + :decimals {:db (assoc-in db [:wallet/custom-token-screen :decimals] value)})) diff --git a/test/cljs/status_im/test/models/wallet.cljs b/test/cljs/status_im/test/models/wallet.cljs index b9872d61df..f36d1bb655 100644 --- a/test/cljs/status_im/test/models/wallet.cljs +++ b/test/cljs/status_im/test/models/wallet.cljs @@ -1,31 +1,31 @@ (ns status-im.test.models.wallet (:require [cljs.test :refer-macros [deftest is testing]] [status-im.utils.money :as money] - [status-im.models.wallet :as model])) + [status-im.wallet.core :as wallet])) (deftest valid-min-gas-price-test (testing "not an number" - (is (= :invalid-number (model/invalid-send-parameter? :gas-price nil)))) + (is (= :invalid-number (wallet/invalid-send-parameter? :gas-price nil)))) (testing "a number less than the minimum" - (is (= :not-enough-wei (model/invalid-send-parameter? :gas-price (money/bignumber "0.0000000001"))))) + (is (= :not-enough-wei (wallet/invalid-send-parameter? :gas-price (money/bignumber "0.0000000001"))))) (testing "a number greater than the mininum" - (is (not (model/invalid-send-parameter? :gas-price 3)))) + (is (not (wallet/invalid-send-parameter? :gas-price 3)))) (testing "the minimum" - (is (not (model/invalid-send-parameter? :gas-price (money/bignumber "0.000000001")))))) + (is (not (wallet/invalid-send-parameter? :gas-price (money/bignumber "0.000000001")))))) (deftest valid-gas (testing "not an number" - (is (= :invalid-number (model/invalid-send-parameter? :gas nil)))) + (is (= :invalid-number (wallet/invalid-send-parameter? :gas nil)))) (testing "0" - (is (= :invalid-number (model/invalid-send-parameter? :gas 0)))) + (is (= :invalid-number (wallet/invalid-send-parameter? :gas 0)))) (testing "a number" - (is (not (model/invalid-send-parameter? :gas 1))))) + (is (not (wallet/invalid-send-parameter? :gas 1))))) (deftest build-edit-test (testing "an invalid edit" (let [actual (-> {} - (model/build-edit :gas "invalid") - (model/build-edit :gas-price "0.00000000001"))] + (wallet/build-edit :gas "invalid") + (wallet/build-edit :gas-price "0.00000000001"))] (testing "it marks gas-price as invalid" (is (get-in actual [:gas-price :invalid?]))) (testing "it does not change value" @@ -38,13 +38,13 @@ (is (= "0" (:max-fee actual)))))) (testing "gas price in wei should be round" (let [actual (-> {} - (model/build-edit :gas "21000") - (model/build-edit :gas-price "0.0000000023"))] + (wallet/build-edit :gas "21000") + (wallet/build-edit :gas-price "0.0000000023"))] (is (get-in actual [:gas-price :invalid?])))) (testing "an valid edit" (let [actual (-> {} - (model/build-edit :gas "21000") - (model/build-edit :gas-price "10"))] + (wallet/build-edit :gas "21000") + (wallet/build-edit :gas-price "10"))] (testing "it does not mark gas-price as invalid" (is (not (get-in actual [:gas-price :invalid?])))) (testing "it sets the value in number for gas-price, in gwei"