[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]
|
(:require [re-frame.core :as re-frame]
|
||||||
[status-im.accounts.update.core :as accounts.update]
|
[status-im.accounts.update.core :as accounts.update]
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.ui.screens.navigation :as navigation]
|
|
||||||
[status-im.native-module.core :as native-module]
|
[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.config :as config]
|
||||||
[status-im.utils.utils :as utils]
|
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.fx :as fx]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.utils.build :as build]))
|
[status-im.utils.utils :as utils]))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::chaos-mode-changed
|
::chaos-mode-changed
|
||||||
|
@ -49,7 +48,6 @@
|
||||||
[{:keys [db] :as cofx} modal?]
|
[{:keys [db] :as cofx} modal?]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
(continue-after-wallet-onboarding modal?)
|
(continue-after-wallet-onboarding modal?)
|
||||||
(wallet.settings.models/wallet-autoconfig-tokens)
|
|
||||||
(accounts.update/account-update {:wallet-set-up-passed? true} {})))
|
(accounts.update/account-update {:wallet-set-up-passed? true} {})))
|
||||||
|
|
||||||
(fx/defn update-dev-server-state
|
(fx/defn update-dev-server-state
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
[status-im.ethereum.transactions.core :as transactions]
|
[status-im.ethereum.transactions.core :as transactions]
|
||||||
[status-im.fleet.core :as fleet]
|
[status-im.fleet.core :as fleet]
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.models.wallet :as models.wallet]
|
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.node.core :as node]
|
[status-im.node.core :as node]
|
||||||
[status-im.protocol.core :as protocol]
|
[status-im.protocol.core :as protocol]
|
||||||
|
@ -22,6 +21,7 @@
|
||||||
[status-im.utils.security :as security]
|
[status-im.utils.security :as security]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im.utils.universal-links.core :as universal-links]
|
[status-im.utils.universal-links.core :as universal-links]
|
||||||
|
[status-im.wallet.core :as wallet]
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]))
|
||||||
|
|
||||||
(def rpc-endpoint "https://goerli.infura.io/v3/f315575765b14720b32382a61a89341a")
|
(def rpc-endpoint "https://goerli.infura.io/v3/f315575765b14720b32382a61a89341a")
|
||||||
|
@ -84,10 +84,10 @@
|
||||||
|
|
||||||
(fx/defn initialize-wallet [cofx]
|
(fx/defn initialize-wallet [cofx]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
(models.wallet/initialize-tokens)
|
(wallet/initialize-tokens)
|
||||||
(transactions/initialize)
|
(transactions/initialize)
|
||||||
(ethereum.subscriptions/initialize)
|
(ethereum.subscriptions/initialize)
|
||||||
(models.wallet/update-wallet)))
|
(wallet/update-wallet)))
|
||||||
|
|
||||||
(fx/defn user-login [{:keys [db] :as cofx} create-database?]
|
(fx/defn user-login [{:keys [db] :as cofx} create-database?]
|
||||||
(let [{:keys [address password]} (accounts.db/credentials cofx)]
|
(let [{:keys [address password]} (accounts.db/credentials cofx)]
|
||||||
|
|
|
@ -185,7 +185,7 @@
|
||||||
(defview send-status [tx-hash outgoing]
|
(defview send-status [tx-hash outgoing]
|
||||||
(letsubs [{:keys [exists? confirmed?]} [:chats/transaction-status tx-hash]]
|
(letsubs [{:keys [exists? confirmed?]} [:chats/transaction-status tx-hash]]
|
||||||
[react/touchable-highlight {:on-press #(when exists?
|
[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
|
[react/view transactions-styles/command-send-status-container
|
||||||
[vector-icons/icon (if confirmed?
|
[vector-icons/icon (if confirmed?
|
||||||
:tiny-icons/tiny-check
|
:tiny-icons/tiny-check
|
||||||
|
|
|
@ -103,11 +103,7 @@
|
||||||
(defn default-account-settings []
|
(defn default-account-settings []
|
||||||
{:web3-opt-in? true
|
{:web3-opt-in? true
|
||||||
:preview-privacy? false
|
:preview-privacy? false
|
||||||
:wallet {:visible-tokens {:testnet #{:STT :HND}
|
:wallet {:visible-tokens {}}})
|
||||||
:mainnet #{:SNT}
|
|
||||||
:rinkeby #{:MOKSHA :KDO}
|
|
||||||
:xdai #{}
|
|
||||||
:poa #{}}}})
|
|
||||||
|
|
||||||
(def currencies
|
(def currencies
|
||||||
{:aed {:id :aed :code "AED" :display-name (i18n/label :t/currency-display-name-aed) :symbol "د.إ"}
|
{: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.ethereum.core :as ethereum]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.fx :as fx]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
|
[status-im.wallet.core :as wallet]
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]))
|
||||||
|
|
||||||
(def confirmations-count-threshold 12)
|
(def confirmations-count-threshold 12)
|
||||||
|
@ -180,14 +181,18 @@
|
||||||
;; -----------------------------------------------
|
;; -----------------------------------------------
|
||||||
|
|
||||||
(fx/defn new
|
(fx/defn new
|
||||||
[{:keys [db]} {:keys [hash] :as transaction}]
|
[{:keys [db] :as cofx} {:keys [hash] :as transaction}]
|
||||||
{:db (assoc-in db [:wallet :transactions hash] transaction)})
|
(fx/merge cofx
|
||||||
|
{:db (assoc-in db [:wallet :transactions hash] transaction)}
|
||||||
|
wallet/update-wallet))
|
||||||
|
|
||||||
(fx/defn handle-history
|
(fx/defn handle-history
|
||||||
[{:keys [db]} transactions]
|
[{:keys [db] :as cofx} transactions]
|
||||||
{:db (update-in db
|
(fx/merge cofx
|
||||||
[:wallet :transactions]
|
{:db (update-in db
|
||||||
#(merge transactions %))})
|
[:wallet :transactions]
|
||||||
|
#(merge transactions %))}
|
||||||
|
wallet/update-wallet))
|
||||||
|
|
||||||
(fx/defn handle-token-history
|
(fx/defn handle-token-history
|
||||||
[{:keys [db]} transactions]
|
[{:keys [db]} transactions]
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
[status-im.utils.handlers :as handlers]
|
[status-im.utils.handlers :as handlers]
|
||||||
[status-im.utils.logging.core :as logging]
|
[status-im.utils.logging.core :as logging]
|
||||||
[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]
|
[status-im.wallet.db :as wallet.db]
|
||||||
[status-im.web3.core :as web3]
|
[status-im.web3.core :as web3]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
|
@ -2147,6 +2148,12 @@
|
||||||
(ethereum.transactions/new cofx transaction)))
|
(ethereum.transactions/new cofx transaction)))
|
||||||
|
|
||||||
;; wallet events
|
;; wallet events
|
||||||
|
|
||||||
|
(handlers/register-handler-fx
|
||||||
|
:wallet.ui/pull-to-refresh
|
||||||
|
(fn [cofx _]
|
||||||
|
(wallet/update-wallet cofx)))
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:wallet.transactions/add-filter
|
:wallet.transactions/add-filter
|
||||||
(fn [{:keys [db]} [_ id]]
|
(fn [{:keys [db]} [_ id]]
|
||||||
|
@ -2162,3 +2169,91 @@
|
||||||
(fn [{:keys [db]} _]
|
(fn [{:keys [db]} _]
|
||||||
{:db (assoc-in db [:wallet :filters]
|
{:db (assoc-in db [:wallet :filters]
|
||||||
wallet.db/default-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]
|
(:require [clojure.string :as string]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.models.wallet :as models.wallet]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.utils.hex :as hex]
|
|
||||||
[status-im.ui.screens.navigation :as navigation]
|
[status-im.ui.screens.navigation :as navigation]
|
||||||
[status-im.utils.ethereum.abi-spec :as abi-spec]
|
[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.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.handlers :as handlers]
|
||||||
|
[status-im.utils.hex :as hex]
|
||||||
[status-im.utils.money :as money]
|
[status-im.utils.money :as money]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im.native-module.core :as status]))
|
[status-im.wallet.core :as wallet]))
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:extensions/wallet-ui-on-success
|
:extensions/wallet-ui-on-success
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
(let [tx-object (assoc (select-keys arguments [:to :gas :gas-price :value :nonce])
|
(let [tx-object (assoc (select-keys arguments [:to :gas :gas-price :value :nonce])
|
||||||
:data (when (and method params) (abi-spec/encode method params)))
|
:data (when (and method params) (abi-spec/encode method params)))
|
||||||
transaction (prepare-extension-transaction tx-object (:contacts/contacts db) on-success on-failure)]
|
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
|
(handlers/register-handler-fx
|
||||||
:extensions/ethereum-send-transaction
|
:extensions/ethereum-send-transaction
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
(ns status-im.hardwallet.core
|
(ns status-im.hardwallet.core
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [clojure.string :as string]
|
||||||
status-im.hardwallet.fx
|
[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.ui.screens.navigation :as navigation]
|
||||||
[status-im.utils.config :as config]
|
[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.fx :as fx]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[status-im.i18n :as i18n]
|
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im.accounts.create.core :as accounts.create]
|
[status-im.wallet.core :as wallet]
|
||||||
[status-im.node.core :as node]
|
[taoensso.timbre :as log]
|
||||||
[status-im.utils.datetime :as utils.datetime]
|
status-im.hardwallet.fx))
|
||||||
[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]))
|
|
||||||
|
|
||||||
(def default-pin "000000")
|
(def default-pin "000000")
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
(if navigate-to-browser?
|
(if navigate-to-browser?
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (assoc-in db [:hardwallet :on-card-connected] nil)}
|
{:db (assoc-in db [:hardwallet :on-card-connected] nil)}
|
||||||
(models.wallet/discard-transaction)
|
(wallet/discard-transaction)
|
||||||
(navigation/navigate-to-cofx :browser nil))
|
(navigation/navigate-to-cofx :browser nil))
|
||||||
(if (= :enter-pin-login (:view-id db))
|
(if (= :enter-pin-login (:view-id db))
|
||||||
(navigation/navigate-to-clean cofx :accounts nil)
|
(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
|
(ns status-im.stickers.core
|
||||||
(:require [status-im.utils.fx :as fx]
|
(:require [cljs.reader :as edn]
|
||||||
[cljs.reader :as edn]
|
|
||||||
[status-im.accounts.core :as accounts]
|
|
||||||
[status-im.ui.screens.navigation :as navigation]
|
|
||||||
[re-frame.core :as re-frame]
|
[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.constants :as constants]
|
||||||
[status-im.utils.ethereum.core :as ethereum]
|
[status-im.ui.screens.navigation :as navigation]
|
||||||
[status-im.utils.ethereum.stickers :as ethereum.stickers]
|
|
||||||
[status-im.models.wallet :as models.wallet]
|
|
||||||
[status-im.utils.money :as money]
|
|
||||||
[status-im.utils.ethereum.abi-spec :as abi-spec]
|
[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]}]
|
(fx/defn init-stickers-packs [{:keys [db]}]
|
||||||
(let [sticker-packs (into {} (map #(let [pack (edn/read-string %)]
|
(let [sticker-packs (into {} (map #(let [pack (edn/read-string %)]
|
||||||
|
@ -82,7 +82,7 @@
|
||||||
data (abi-spec/encode "buyToken(uint256,address)" [pack-id address])
|
data (abi-spec/encode "buyToken(uint256,address)" [pack-id address])
|
||||||
tx-object {:to (get erc20/snt-contracts chain)
|
tx-object {:to (get erc20/snt-contracts chain)
|
||||||
:data (abi-spec/encode "approveAndCall(address,uint256,bytes)" [stickers-contract price data])}]
|
: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
|
db
|
||||||
(prepare-transaction "approve" tx-object [:stickers/pending-pack pack-id])
|
(prepare-transaction "approve" tx-object [:stickers/pending-pack pack-id])
|
||||||
tx-object)))
|
tx-object)))
|
||||||
|
|
|
@ -11,11 +11,9 @@
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.contact.db :as contact.db]
|
[status-im.contact.db :as contact.db]
|
||||||
[status-im.ethereum.transactions.core :as transactions]
|
[status-im.ethereum.transactions.core :as transactions]
|
||||||
|
[status-im.ethereum.transactions.etherscan :as transactions.etherscan]
|
||||||
[status-im.fleet.core :as fleet]
|
[status-im.fleet.core :as fleet]
|
||||||
[status-im.i18n :as i18n]
|
[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.bottom-bar.styles :as tabs.styles]
|
||||||
[status-im.ui.components.toolbar.styles :as toolbar.styles]
|
[status-im.ui.components.toolbar.styles :as toolbar.styles]
|
||||||
[status-im.ui.screens.add-new.new-public-chat.db :as db]
|
[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.datetime :as datetime]
|
||||||
[status-im.utils.ethereum.core :as ethereum]
|
[status-im.utils.ethereum.core :as ethereum]
|
||||||
[status-im.utils.ethereum.tokens :as tokens]
|
[status-im.utils.ethereum.tokens :as tokens]
|
||||||
[status-im.utils.hex :as utils.hex]
|
|
||||||
[status-im.utils.identicon :as identicon]
|
[status-im.utils.identicon :as identicon]
|
||||||
[status-im.utils.money :as money]
|
[status-im.utils.money :as money]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.utils.security :as security]
|
[status-im.utils.security :as security]
|
||||||
[status-im.utils.universal-links.core :as links]
|
[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.tribute-to-talk.subs
|
||||||
status-im.ui.screens.hardwallet.connect.subs
|
status-im.ui.screens.hardwallet.connect.subs
|
||||||
status-im.ui.screens.hardwallet.settings.subs
|
status-im.ui.screens.hardwallet.settings.subs
|
||||||
status-im.ui.screens.hardwallet.pin.subs
|
status-im.ui.screens.hardwallet.pin.subs
|
||||||
status-im.ui.screens.hardwallet.setup.subs
|
status-im.ui.screens.hardwallet.setup.subs))
|
||||||
[status-im.wallet.db :as wallet.db]))
|
|
||||||
|
|
||||||
;; TOP LEVEL ===========================================================================================================
|
;; TOP LEVEL ===========================================================================================================
|
||||||
|
|
||||||
|
@ -1128,7 +1126,7 @@
|
||||||
:contact to-contact
|
:contact to-contact
|
||||||
:address to))
|
:address to))
|
||||||
:time-formatted (datetime/timestamp->time timestamp)
|
: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
|
(defn- group-transactions-by-date
|
||||||
[transactions]
|
[transactions]
|
||||||
|
@ -1257,12 +1255,12 @@
|
||||||
[transaction edit]
|
[transaction edit]
|
||||||
(cond-> edit
|
(cond-> edit
|
||||||
(not (get-in edit [:gas-price :value]))
|
(not (get-in edit [:gas-price :value]))
|
||||||
(models.wallet/build-edit
|
(wallet/build-edit
|
||||||
:gas-price
|
:gas-price
|
||||||
(money/to-fixed (money/wei-> :gwei (:gas-price transaction))))
|
(money/to-fixed (money/wei-> :gwei (:gas-price transaction))))
|
||||||
|
|
||||||
(not (get-in edit [:gas :value]))
|
(not (get-in edit [:gas :value]))
|
||||||
(models.wallet/build-edit
|
(wallet/build-edit
|
||||||
:gas
|
:gas
|
||||||
(money/to-fixed (:gas transaction)))))
|
(money/to-fixed (:gas transaction)))))
|
||||||
|
|
||||||
|
@ -1299,7 +1297,7 @@
|
||||||
:<- [:balance]
|
:<- [:balance]
|
||||||
(fn [[{:keys [amount symbol] :as transaction} balance]]
|
(fn [[{:keys [amount symbol] :as transaction} balance]]
|
||||||
(-> transaction
|
(-> transaction
|
||||||
(models.wallet/add-max-fee)
|
(wallet/add-max-fee)
|
||||||
(check-sufficient-funds balance symbol amount)
|
(check-sufficient-funds balance symbol amount)
|
||||||
(check-sufficient-gas balance symbol amount))))
|
(check-sufficient-gas balance symbol amount))))
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
(ns status-im.ui.screens.currency-settings.models
|
(ns status-im.ui.screens.currency-settings.models
|
||||||
(:require [status-im.accounts.update.core :as accounts.update]
|
(: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
|
(fx/defn set-currency
|
||||||
[{:keys [db] :as cofx} currency]
|
[{:keys [db] :as cofx} currency]
|
||||||
|
|
|
@ -10,30 +10,29 @@
|
||||||
status-im.ui.screens.add-new.new-chat.navigation
|
status-im.ui.screens.add-new.new-chat.navigation
|
||||||
status-im.ui.screens.profile.events
|
status-im.ui.screens.profile.events
|
||||||
status-im.ui.screens.extensions.add.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.collectibles.events
|
||||||
status-im.ui.screens.wallet.send.events
|
status-im.ui.screens.wallet.send.events
|
||||||
status-im.ui.screens.wallet.request.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.choose-recipient.events
|
||||||
status-im.ui.screens.wallet.collectibles.cryptokitties.events
|
status-im.ui.screens.wallet.collectibles.cryptokitties.events
|
||||||
status-im.ui.screens.wallet.collectibles.cryptostrikers.events
|
status-im.ui.screens.wallet.collectibles.cryptostrikers.events
|
||||||
status-im.ui.screens.wallet.collectibles.etheremon.events
|
status-im.ui.screens.wallet.collectibles.etheremon.events
|
||||||
status-im.ui.screens.wallet.collectibles.superrare.events
|
status-im.ui.screens.wallet.collectibles.superrare.events
|
||||||
status-im.ui.screens.wallet.collectibles.kudos.events
|
status-im.ui.screens.wallet.collectibles.kudos.events
|
||||||
|
status-im.ui.screens.wallet.navigation
|
||||||
status-im.utils.keychain.events
|
status-im.utils.keychain.events
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.hardwallet.core :as hardwallet]
|
|
||||||
[status-im.chat.models :as chat]
|
[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.mailserver.core :as mailserver]
|
||||||
|
[status-im.native-module.core :as status]
|
||||||
[status-im.ui.components.permissions :as permissions]
|
[status-im.ui.components.permissions :as permissions]
|
||||||
[status-im.utils.dimensions :as dimensions]
|
[status-im.utils.dimensions :as dimensions]
|
||||||
|
[status-im.utils.fx :as fx]
|
||||||
[status-im.utils.handlers :as handlers]
|
[status-im.utils.handlers :as handlers]
|
||||||
[status-im.utils.http :as http]
|
[status-im.utils.http :as http]
|
||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.utils :as utils]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.wallet.core :as wallet]))
|
||||||
[status-im.models.wallet :as wallet]))
|
|
||||||
|
|
||||||
(defn- http-get [{:keys [url response-validator success-event-creator failure-event-creator timeout-ms]}]
|
(defn- http-get [{:keys [url response-validator success-event-creator failure-event-creator timeout-ms]}]
|
||||||
(let [on-success #(re-frame/dispatch (success-event-creator %))
|
(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
|
[react/scroll-view {:end-fill-color colors/white
|
||||||
:refresh-control
|
:refresh-control
|
||||||
(reagent/as-element
|
(reagent/as-element
|
||||||
[react/refresh-control {:on-refresh (fn [_]
|
[react/refresh-control {:on-refresh #(re-frame/dispatch [:wallet.ui/pull-to-refresh])
|
||||||
;;TODO temporay fix to update balance, should be fixed
|
|
||||||
;;properly later
|
|
||||||
(re-frame/dispatch [:wallet.ui/pull-to-refresh])
|
|
||||||
(re-frame/dispatch [:update-wallet]))
|
|
||||||
:tint-color :white
|
:tint-color :white
|
||||||
:refreshing false}])}
|
:refreshing false}])}
|
||||||
(if error-message
|
(if error-message
|
||||||
|
|
|
@ -2,29 +2,7 @@
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.ui.screens.navigation :as navigation]
|
[status-im.ui.screens.navigation :as navigation]
|
||||||
[status-im.utils.ethereum.core :as ethereum]
|
[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)
|
|
||||||
|
|
||||||
(def transaction-send-default
|
(def transaction-send-default
|
||||||
(let [symbol :ETH]
|
(let [symbol :ETH]
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
^{:key "toolbar"}
|
^{:key "toolbar"}
|
||||||
[wallet.components/toolbar
|
[wallet.components/toolbar
|
||||||
{:transparent? true}
|
{: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)])
|
(i18n/label :t/wallet-set-up-title)])
|
||||||
|
|
||||||
(defn main-panel [signing-phrase on-confirm]
|
(defn main-panel [signing-phrase on-confirm]
|
||||||
|
|
|
@ -3,11 +3,9 @@
|
||||||
[status-im.chat.commands.sending :as commands-sending]
|
[status-im.chat.commands.sending :as commands-sending]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.models.wallet :as models.wallet]
|
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.transport.utils :as transport.utils]
|
[status-im.transport.utils :as transport.utils]
|
||||||
[status-im.ui.screens.navigation :as navigation]
|
[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.core :as ethereum]
|
||||||
[status-im.utils.ethereum.erc20 :as erc20]
|
[status-im.utils.ethereum.erc20 :as erc20]
|
||||||
[status-im.utils.ethereum.tokens :as tokens]
|
[status-im.utils.ethereum.tokens :as tokens]
|
||||||
|
@ -16,7 +14,9 @@
|
||||||
[status-im.utils.money :as money]
|
[status-im.utils.money :as money]
|
||||||
[status-im.utils.security :as security]
|
[status-im.utils.security :as security]
|
||||||
[status-im.utils.types :as types]
|
[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
|
;;;; FX
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:wallet :send-transaction :wrong-password?] false)
|
(assoc-in [:wallet :send-transaction :wrong-password?] false)
|
||||||
(assoc-in [:wallet :send-transaction :in-progress?] true))
|
(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
|
all-tokens
|
||||||
symbol
|
symbol
|
||||||
chain
|
chain
|
||||||
|
@ -116,7 +116,7 @@
|
||||||
modal-screen-was-used? (get-in db [:navigation/screen-params :wallet-send-modal-stack :modal?])]
|
modal-screen-was-used? (get-in db [:navigation/screen-params :wallet-send-modal-stack :modal?])]
|
||||||
(if error
|
(if error
|
||||||
;; ERROR
|
;; ERROR
|
||||||
(models.wallet/handle-transaction-error (assoc cofx :db db') error)
|
(wallet/handle-transaction-error (assoc cofx :db db') error)
|
||||||
;; RESULT
|
;; RESULT
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
(merge
|
(merge
|
||||||
|
@ -124,7 +124,7 @@
|
||||||
|
|
||||||
(not (constants/web3-sign-message? method))
|
(not (constants/web3-sign-message? method))
|
||||||
(assoc-in [:wallet :transactions result]
|
(assoc-in [:wallet :transactions result]
|
||||||
(models.wallet/prepare-unconfirmed-transaction db now result)))}
|
(wallet/prepare-unconfirmed-transaction db now result)))}
|
||||||
(when on-result
|
(when on-result
|
||||||
{:dispatch (conj on-result id result method)}))
|
{:dispatch (conj on-result id result method)}))
|
||||||
#(when (or (not on-result)
|
#(when (or (not on-result)
|
||||||
|
@ -168,7 +168,7 @@
|
||||||
db' (assoc-in db [:wallet :send-transaction :in-progress?] false)]
|
db' (assoc-in db [:wallet :send-transaction :in-progress?] false)]
|
||||||
(if error
|
(if error
|
||||||
;; ERROR
|
;; ERROR
|
||||||
(models.wallet/handle-transaction-error (assoc cofx :db db') error)
|
(wallet/handle-transaction-error (assoc cofx :db db') error)
|
||||||
;; RESULT
|
;; RESULT
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
|
@ -186,19 +186,19 @@
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:wallet/discard-transaction
|
:wallet/discard-transaction
|
||||||
(fn [cofx _]
|
(fn [cofx _]
|
||||||
(models.wallet/discard-transaction cofx)))
|
(wallet/discard-transaction cofx)))
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:wallet.dapp/transaction-on-result
|
:wallet.dapp/transaction-on-result
|
||||||
(fn [{db :db} [_ message-id id result method]]
|
(fn [{db :db} [_ message-id id result method]]
|
||||||
(let [webview (:webview-bridge db)
|
(let [webview (:webview-bridge db)
|
||||||
keycard? (boolean (get-in db [:account/account :keycard-instance-uid]))]
|
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
|
(handlers/register-handler-fx
|
||||||
:wallet.dapp/transaction-on-error
|
:wallet.dapp/transaction-on-error
|
||||||
(fn [{db :db} [_ message-id message]]
|
(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
|
;; DAPP TRANSACTIONS QUEUE
|
||||||
;; NOTE(andrey) We need this queue because dapp can send several transactions in a row, this is bad behaviour
|
;; 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
|
;;SEND TRANSACTION
|
||||||
(= method constants/web3-send-transaction)
|
(= method constants/web3-send-transaction)
|
||||||
(let [transaction (models.wallet/prepare-dapp-transaction queued-transaction (:contacts/contacts db))]
|
(let [transaction (wallet/prepare-dapp-transaction queued-transaction (:contacts/contacts db))]
|
||||||
(models.wallet/open-modal-wallet-for-transaction db' transaction (first params)))
|
(wallet/open-modal-wallet-for-transaction db' transaction (first params)))
|
||||||
|
|
||||||
;;SIGN MESSAGE
|
;;SIGN MESSAGE
|
||||||
(constants/web3-sign-message? method)
|
(constants/web3-sign-message? method)
|
||||||
(let [typed? (not= constants/web3-personal-sign 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)
|
(if (and address data)
|
||||||
(let [signing-phrase (-> (get-in db [:account/account :signing-phrase])
|
(let [signing-phrase (-> (get-in db [:account/account :signing-phrase])
|
||||||
(clojure.string/replace-all #" " " "))
|
(clojure.string/replace-all #" " " "))
|
||||||
|
@ -259,7 +259,7 @@
|
||||||
(fn [cofx _]
|
(fn [cofx _]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
(navigation/navigate-back)
|
(navigation/navigate-back)
|
||||||
(models.wallet/discard-transaction))))
|
(wallet/discard-transaction))))
|
||||||
|
|
||||||
(defn update-gas-price
|
(defn update-gas-price
|
||||||
([db edit? success-event]
|
([db edit? success-event]
|
||||||
|
@ -311,7 +311,7 @@
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:wallet.send/edit-value
|
:wallet.send/edit-value
|
||||||
(fn [cofx [_ key value]]
|
(fn [cofx [_ key value]]
|
||||||
(models.wallet/edit-value key value cofx)))
|
(wallet/edit-value key value cofx)))
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:wallet.send/set-gas-details
|
:wallet.send/set-gas-details
|
||||||
|
@ -333,7 +333,7 @@
|
||||||
(money/to-fixed
|
(money/to-fixed
|
||||||
(ethereum/estimate-gas
|
(ethereum/estimate-gas
|
||||||
(-> db :wallet :send-transaction :symbol))))]
|
(-> db :wallet :send-transaction :symbol))))]
|
||||||
(assoc (models.wallet/edit-value
|
(assoc (wallet/edit-value
|
||||||
:gas
|
:gas
|
||||||
gas-default
|
gas-default
|
||||||
cofx)
|
cofx)
|
||||||
|
@ -364,9 +364,9 @@
|
||||||
(defn- prepare-keycard-transaction
|
(defn- prepare-keycard-transaction
|
||||||
[transaction from symbol chain all-tokens]
|
[transaction from symbol chain all-tokens]
|
||||||
(if (= :ETH symbol)
|
(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))
|
(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)
|
(merge (ethereum/call-params contract "transfer(address,uint256)" to value)
|
||||||
{:from from
|
{:from from
|
||||||
:gas gas
|
: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 []
|
(defn toolbar []
|
||||||
[toolbar/toolbar nil
|
[toolbar/toolbar nil
|
||||||
[toolbar/nav-button
|
[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
|
[toolbar/content-title
|
||||||
(i18n/label :t/wallet-assets)]])
|
(i18n/label :t/wallet-assets)]])
|
||||||
|
|
||||||
|
@ -96,7 +97,7 @@
|
||||||
{:style {:border-bottom-color colors/white-light-transparent}}
|
{:style {:border-bottom-color colors/white-light-transparent}}
|
||||||
[toolbar/nav-button
|
[toolbar/nav-button
|
||||||
(actions/back-white
|
(actions/back-white
|
||||||
#(re-frame/dispatch [:update-wallet-and-nav-back
|
#(re-frame/dispatch [:wallet.settings.ui/navigate-back-pressed
|
||||||
(when (fn? on-close)
|
(when (fn? on-close)
|
||||||
(on-close (create-payload address)))]))]
|
(on-close (create-payload address)))]))]
|
||||||
[toolbar/content-title {:color colors/white}
|
[toolbar/content-title {:color colors/white}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
(ns status-im.utils.ethereum.contracts
|
(ns status-im.utils.ethereum.contracts
|
||||||
(:require [re-frame.core :as re-frame]
|
(: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.abi-spec :as abi-spec]
|
||||||
[status-im.utils.ethereum.core :as ethereum]
|
[status-im.utils.ethereum.core :as ethereum]
|
||||||
[status-im.utils.fx :as fx]
|
[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
|
(def contracts
|
||||||
{:status/snt
|
{: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]
|
[clojure.string :as string]
|
||||||
[status-im.ethereum.decode :as decode]
|
[status-im.ethereum.decode :as decode]
|
||||||
[status-im.utils.fx :as fx]
|
[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
|
(re-frame/reg-fx
|
||||||
:wallet.custom-token/get-decimals
|
:wallet.custom-token/get-decimals
|
||||||
|
@ -111,12 +111,12 @@
|
||||||
new-token {:address contract :name name :symbol symbol :custom? true
|
new-token {:address contract :name name :symbol symbol :custom? true
|
||||||
:decimals (int decimals) :color (rand-nth colors/chat-colors)}]
|
:decimals (int decimals) :color (rand-nth colors/chat-colors)}]
|
||||||
(fx/merge (assoc-in cofx [:db :wallet/all-tokens chain-key contract] new-token)
|
(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}]
|
(fx/defn remove-custom-token [{:keys [db] :as cofx} {:keys [address] :as token}]
|
||||||
(let [chain-key (ethereum/get-chain-keyword db)]
|
(let [chain-key (ethereum/get-chain-keyword db)]
|
||||||
(fx/merge (update-in cofx [:db :wallet/all-tokens chain-key] dissoc address)
|
(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]
|
(fx/defn field-is-edited [{:keys [db] :as cofx} field-key value]
|
||||||
(case field-key
|
(case field-key
|
||||||
|
|
|
@ -1,31 +1,31 @@
|
||||||
(ns status-im.test.models.wallet
|
(ns status-im.test.models.wallet
|
||||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||||
[status-im.utils.money :as money]
|
[status-im.utils.money :as money]
|
||||||
[status-im.models.wallet :as model]))
|
[status-im.wallet.core :as wallet]))
|
||||||
|
|
||||||
(deftest valid-min-gas-price-test
|
(deftest valid-min-gas-price-test
|
||||||
(testing "not an number"
|
(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"
|
(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"
|
(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"
|
(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
|
(deftest valid-gas
|
||||||
(testing "not an number"
|
(testing "not an number"
|
||||||
(is (= :invalid-number (model/invalid-send-parameter? :gas nil))))
|
(is (= :invalid-number (wallet/invalid-send-parameter? :gas nil))))
|
||||||
(testing "0"
|
(testing "0"
|
||||||
(is (= :invalid-number (model/invalid-send-parameter? :gas 0))))
|
(is (= :invalid-number (wallet/invalid-send-parameter? :gas 0))))
|
||||||
(testing "a number"
|
(testing "a number"
|
||||||
(is (not (model/invalid-send-parameter? :gas 1)))))
|
(is (not (wallet/invalid-send-parameter? :gas 1)))))
|
||||||
|
|
||||||
(deftest build-edit-test
|
(deftest build-edit-test
|
||||||
(testing "an invalid edit"
|
(testing "an invalid edit"
|
||||||
(let [actual (-> {}
|
(let [actual (-> {}
|
||||||
(model/build-edit :gas "invalid")
|
(wallet/build-edit :gas "invalid")
|
||||||
(model/build-edit :gas-price "0.00000000001"))]
|
(wallet/build-edit :gas-price "0.00000000001"))]
|
||||||
(testing "it marks gas-price as invalid"
|
(testing "it marks gas-price as invalid"
|
||||||
(is (get-in actual [:gas-price :invalid?])))
|
(is (get-in actual [:gas-price :invalid?])))
|
||||||
(testing "it does not change value"
|
(testing "it does not change value"
|
||||||
|
@ -38,13 +38,13 @@
|
||||||
(is (= "0" (:max-fee actual))))))
|
(is (= "0" (:max-fee actual))))))
|
||||||
(testing "gas price in wei should be round"
|
(testing "gas price in wei should be round"
|
||||||
(let [actual (-> {}
|
(let [actual (-> {}
|
||||||
(model/build-edit :gas "21000")
|
(wallet/build-edit :gas "21000")
|
||||||
(model/build-edit :gas-price "0.0000000023"))]
|
(wallet/build-edit :gas-price "0.0000000023"))]
|
||||||
(is (get-in actual [:gas-price :invalid?]))))
|
(is (get-in actual [:gas-price :invalid?]))))
|
||||||
(testing "an valid edit"
|
(testing "an valid edit"
|
||||||
(let [actual (-> {}
|
(let [actual (-> {}
|
||||||
(model/build-edit :gas "21000")
|
(wallet/build-edit :gas "21000")
|
||||||
(model/build-edit :gas-price "10"))]
|
(wallet/build-edit :gas-price "10"))]
|
||||||
(testing "it does not mark gas-price as invalid"
|
(testing "it does not mark gas-price as invalid"
|
||||||
(is (not (get-in actual [:gas-price :invalid?]))))
|
(is (not (get-in actual [:gas-price :invalid?]))))
|
||||||
(testing "it sets the value in number for gas-price, in gwei"
|
(testing "it sets the value in number for gas-price, in gwei"
|
||||||
|
|
Loading…
Reference in New Issue