[performance] improve wallet update performances
`wallet-autoconfig-token` is a very expensive call on mainnet because it checks the balance of every known token. it is called: - when wallet is refreshed by pulling - when user goes on any wallet screen this PR changes that by: - calling it only when the wallet is initialized and there is no visible-token configuration it only calls update-wallet when a new transaction arrives
This commit is contained in:
parent
2cd26c585d
commit
89680f4861
|
@ -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
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 "د.إ"}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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))))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)})
|
|
@ -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)))
|
||||
|
|
|
@ -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))))
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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 %))
|
||||
|
|
|
@ -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))))
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)))
|
|
@ -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 %]))})))))
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)))
|
|
@ -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)}))
|
||||
:decimals {:db (assoc-in db [:wallet/custom-token-screen :decimals] value)}))
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue