feature #6509 - validating token config against their contracts; moved token info from compile time list to app-db; fixed any discrepancies in existing info
Signed-off-by: Goran Jovic <goranjovic@gmail.com>
This commit is contained in:
parent
58dc06267c
commit
72e7ae2fff
1
.env
1
.env
|
@ -15,3 +15,4 @@ EXTENSIONS=1
|
||||||
HARDWALLET_ENABLED=0
|
HARDWALLET_ENABLED=0
|
||||||
PFS_ENCRYPTION_ENABLED=0
|
PFS_ENCRYPTION_ENABLED=0
|
||||||
DEV_BUILD=1
|
DEV_BUILD=1
|
||||||
|
ERC20_CONTRACT_WARNINGS=1
|
||||||
|
|
1
.env.e2e
1
.env.e2e
|
@ -10,3 +10,4 @@ DEBUG_WEBVIEW=1
|
||||||
GROUP_CHATS_ENABLED=1
|
GROUP_CHATS_ENABLED=1
|
||||||
EXTENSIONS=1
|
EXTENSIONS=1
|
||||||
PFS_ENCRYPTION_ENABLED=0
|
PFS_ENCRYPTION_ENABLED=0
|
||||||
|
ERC20_CONTRACT_WARNINGS=1
|
||||||
|
|
|
@ -14,3 +14,4 @@ CACHED_WEBVIEWS_ENABLED=1
|
||||||
EXTENSIONS=1
|
EXTENSIONS=1
|
||||||
PFS_ENCRYPTION_ENABLED=0
|
PFS_ENCRYPTION_ENABLED=0
|
||||||
PAIRING_ENABLED=1
|
PAIRING_ENABLED=1
|
||||||
|
ERC20_CONTRACT_WARNINGS=1
|
||||||
|
|
|
@ -13,3 +13,4 @@ PAIRING_ENABLED=1
|
||||||
MAINNET_WARNING_ENABLED=1
|
MAINNET_WARNING_ENABLED=1
|
||||||
EXTENSIONS=1
|
EXTENSIONS=1
|
||||||
PFS_ENCRYPTION_ENABLED=0
|
PFS_ENCRYPTION_ENABLED=0
|
||||||
|
ERC20_CONTRACT_WARNINGS=1
|
||||||
|
|
|
@ -11,3 +11,4 @@ GROUP_CHATS_ENABLED=0
|
||||||
MAINNET_WARNING_ENABLED=1
|
MAINNET_WARNING_ENABLED=1
|
||||||
EXTENSIONS=1
|
EXTENSIONS=1
|
||||||
PFS_ENCRYPTION_ENABLED=0
|
PFS_ENCRYPTION_ENABLED=0
|
||||||
|
ERC20_CONTRACT_WARNINGS=1
|
||||||
|
|
|
@ -13,3 +13,4 @@ GROUP_CHATS_ENABLED=0
|
||||||
MAINNET_WARNING_ENABLED=1
|
MAINNET_WARNING_ENABLED=1
|
||||||
EXTENSIONS=1
|
EXTENSIONS=1
|
||||||
PFS_ENCRYPTION_ENABLED=0
|
PFS_ENCRYPTION_ENABLED=0
|
||||||
|
ERC20_CONTRACT_WARNINGS=0
|
||||||
|
|
|
@ -87,12 +87,10 @@
|
||||||
|
|
||||||
(defn personal-send-request-short-preview
|
(defn personal-send-request-short-preview
|
||||||
[label-key {:keys [content]}]
|
[label-key {:keys [content]}]
|
||||||
(let [{:keys [amount asset network]} (:params content)
|
(let [{:keys [amount coin]} (:params content)]
|
||||||
token (when (and network asset)
|
|
||||||
(tokens/asset-for (keyword network) (keyword asset)))]
|
|
||||||
[chat-preview/text {}
|
[chat-preview/text {}
|
||||||
(i18n/label label-key {:amount (i18n/label-number amount)
|
(i18n/label label-key {:amount (i18n/label-number amount)
|
||||||
:asset (wallet.utils/display-symbol token)})]))
|
:asset (wallet.utils/display-symbol coin)})]))
|
||||||
|
|
||||||
(def personal-send-request-params
|
(def personal-send-request-params
|
||||||
[{:id :asset
|
[{:id :asset
|
||||||
|
@ -146,15 +144,16 @@
|
||||||
;;TODO(goranjovic): currently we only allow tokens which are enabled in Manage assets here
|
;;TODO(goranjovic): currently we only allow tokens which are enabled in Manage assets here
|
||||||
;; because balances are only fetched for them. Revisit this decision with regard to battery/network consequences
|
;; because balances are only fetched for them. Revisit this decision with regard to battery/network consequences
|
||||||
;; if we were to update all balances.
|
;; if we were to update all balances.
|
||||||
(defn- allowed-assets [{:account/keys [account] :keys [chain]}]
|
(defn- allowed-assets [{:account/keys [account] :keys [chain] :as db}]
|
||||||
(let [chain-keyword (keyword chain)
|
(let [all-tokens (:wallet/all-tokens db)
|
||||||
|
chain-keyword (keyword chain)
|
||||||
{:keys [symbol symbol-display decimals]} (tokens/native-currency chain-keyword)
|
{:keys [symbol symbol-display decimals]} (tokens/native-currency chain-keyword)
|
||||||
visible-tokens (get-in account [:settings :wallet :visible-tokens chain-keyword])]
|
visible-tokens (get-in account [:settings :wallet :visible-tokens chain-keyword])]
|
||||||
(into {(name (or symbol-display symbol)) decimals}
|
(into {(name (or symbol-display symbol)) decimals}
|
||||||
(comp (filter #(and (not (:nft? %))
|
(comp (filter #(and (not (:nft? %))
|
||||||
(contains? visible-tokens (:symbol %))))
|
(contains? visible-tokens (:symbol %))))
|
||||||
(map (juxt (comp name :symbol) :decimals)))
|
(map (juxt (comp name :symbol) :decimals)))
|
||||||
(tokens/tokens-for chain-keyword))))
|
(tokens/tokens-for all-tokens chain-keyword))))
|
||||||
|
|
||||||
(defn- personal-send-request-validation [{:keys [asset amount]} {:keys [db]}]
|
(defn- personal-send-request-validation [{:keys [asset amount]} {:keys [db]}]
|
||||||
(let [asset-decimals (get (allowed-assets db) asset)]
|
(let [asset-decimals (get (allowed-assets db) asset)]
|
||||||
|
@ -210,11 +209,12 @@
|
||||||
|
|
||||||
(defview send-preview
|
(defview send-preview
|
||||||
[{:keys [content timestamp-str outgoing group-chat]}]
|
[{:keys [content timestamp-str outgoing group-chat]}]
|
||||||
(letsubs [network [:network-name]]
|
(letsubs [network [:network-name]
|
||||||
|
all-tokens [:wallet/all-tokens]]
|
||||||
(let [{{:keys [amount fiat-amount tx-hash asset currency] send-network :network} :params} content
|
(let [{{:keys [amount fiat-amount tx-hash asset currency] send-network :network} :params} content
|
||||||
recipient-name (get-in content [:params :bot-db :public :recipient])
|
recipient-name (get-in content [:params :bot-db :public :recipient])
|
||||||
network-mismatch? (and (seq send-network) (not= network send-network))
|
network-mismatch? (and (seq send-network) (not= network send-network))
|
||||||
token (tokens/asset-for (keyword send-network) (keyword asset))]
|
token (tokens/asset-for all-tokens (keyword send-network) (keyword asset))]
|
||||||
[react/view transactions-styles/command-send-message-view
|
[react/view transactions-styles/command-send-message-view
|
||||||
[react/view
|
[react/view
|
||||||
[react/view transactions-styles/command-send-amount-row
|
[react/view transactions-styles/command-send-amount-row
|
||||||
|
@ -258,6 +258,12 @@
|
||||||
(defn- inject-network-info [parameters {:keys [db]}]
|
(defn- inject-network-info [parameters {:keys [db]}]
|
||||||
(assoc parameters :network (:chain db)))
|
(assoc parameters :network (:chain db)))
|
||||||
|
|
||||||
|
(defn- inject-coin-info [{:keys [network asset] :as parameters} {:keys [db]}]
|
||||||
|
(let [all-tokens (:wallet/all-tokens db)
|
||||||
|
coin (when (and network asset)
|
||||||
|
(tokens/asset-for all-tokens (keyword network) (keyword asset)))]
|
||||||
|
(assoc parameters :coin coin)))
|
||||||
|
|
||||||
(defn- inject-price-info [{:keys [amount asset] :as parameters} {:keys [db]}]
|
(defn- inject-price-info [{:keys [amount asset] :as parameters} {:keys [db]}]
|
||||||
(let [currency (-> db
|
(let [currency (-> db
|
||||||
currency-settings.subs/get-currency
|
currency-settings.subs/get-currency
|
||||||
|
@ -305,7 +311,8 @@
|
||||||
sender-account (:account/account db)
|
sender-account (:account/account db)
|
||||||
chain (keyword (:chain db))
|
chain (keyword (:chain db))
|
||||||
symbol-param (keyword asset)
|
symbol-param (keyword asset)
|
||||||
{:keys [symbol decimals]} (tokens/asset-for chain symbol-param)
|
all-tokens (:wallet/all-tokens db)
|
||||||
|
{:keys [symbol decimals]} (tokens/asset-for all-tokens chain symbol-param)
|
||||||
{:keys [value error]} (wallet.db/parse-amount amount decimals)
|
{:keys [value error]} (wallet.db/parse-amount amount decimals)
|
||||||
next-view-id (if (:wallet-set-up-passed? sender-account)
|
next-view-id (if (:wallet-set-up-passed? sender-account)
|
||||||
:wallet-send-transaction-modal
|
:wallet-send-transaction-modal
|
||||||
|
@ -330,10 +337,14 @@
|
||||||
(navigation/navigate-to-cofx next-view-id {}))))
|
(navigation/navigate-to-cofx next-view-id {}))))
|
||||||
protocol/EnhancedParameters
|
protocol/EnhancedParameters
|
||||||
(enhance-send-parameters [_ parameters cofx]
|
(enhance-send-parameters [_ parameters cofx]
|
||||||
(-> (inject-network-info parameters cofx)
|
(-> parameters
|
||||||
|
(inject-network-info cofx)
|
||||||
|
(inject-coin-info cofx)
|
||||||
(inject-price-info cofx)))
|
(inject-price-info cofx)))
|
||||||
(enhance-receive-parameters [_ parameters cofx]
|
(enhance-receive-parameters [_ parameters cofx]
|
||||||
(inject-price-info parameters cofx)))
|
(-> parameters
|
||||||
|
(inject-coin-info cofx)
|
||||||
|
(inject-price-info cofx))))
|
||||||
|
|
||||||
;; `/request` command
|
;; `/request` command
|
||||||
|
|
||||||
|
@ -465,7 +476,11 @@
|
||||||
(request-preview command-message))
|
(request-preview command-message))
|
||||||
protocol/EnhancedParameters
|
protocol/EnhancedParameters
|
||||||
(enhance-send-parameters [_ parameters cofx]
|
(enhance-send-parameters [_ parameters cofx]
|
||||||
(-> (inject-network-info parameters cofx)
|
(-> parameters
|
||||||
|
(inject-network-info cofx)
|
||||||
|
(inject-coin-info cofx)
|
||||||
(inject-price-info cofx)))
|
(inject-price-info cofx)))
|
||||||
(enhance-receive-parameters [_ parameters cofx]
|
(enhance-receive-parameters [_ parameters cofx]
|
||||||
(inject-price-info parameters cofx)))
|
(-> parameters
|
||||||
|
(inject-coin-info cofx)
|
||||||
|
(inject-price-info cofx))))
|
||||||
|
|
|
@ -64,6 +64,8 @@
|
||||||
extension/v12
|
extension/v12
|
||||||
account/v15])
|
account/v15])
|
||||||
|
|
||||||
|
(def v17 v16)
|
||||||
|
|
||||||
;; put schemas ordered by version
|
;; put schemas ordered by version
|
||||||
(def schemas [{:schema v1
|
(def schemas [{:schema v1
|
||||||
:schemaVersion 1
|
:schemaVersion 1
|
||||||
|
@ -112,4 +114,7 @@
|
||||||
:migration migrations/v15}
|
:migration migrations/v15}
|
||||||
{:schema v16
|
{:schema v16
|
||||||
:schemaVersion 16
|
:schemaVersion 16
|
||||||
:migration migrations/v16}])
|
:migration migrations/v16}
|
||||||
|
{:schema v17
|
||||||
|
:schemaVersion 17
|
||||||
|
:migration migrations/v17}])
|
||||||
|
|
|
@ -114,3 +114,16 @@
|
||||||
|
|
||||||
(defn v16 [old-realm new-realm]
|
(defn v16 [old-realm new-realm]
|
||||||
(log/debug "migrating base database v16: " old-realm new-realm))
|
(log/debug "migrating base database v16: " old-realm new-realm))
|
||||||
|
|
||||||
|
(defn v17 [old-realm new-realm]
|
||||||
|
(log/debug "migrating accounts schema v17")
|
||||||
|
(let [accounts (.objects new-realm "account")]
|
||||||
|
(dotimes [i (.-length accounts)]
|
||||||
|
(let [account (aget accounts i)
|
||||||
|
old-settings (deserialize (aget account "settings"))
|
||||||
|
new-settings (update-in old-settings [:wallet :visible-tokens :mainnet]
|
||||||
|
#(cond-> %
|
||||||
|
true (disj :BQX)
|
||||||
|
(contains? % :BQX) (conj :ETHOS)))
|
||||||
|
updated (serialize new-settings)]
|
||||||
|
(aset account "settings" updated)))))
|
||||||
|
|
|
@ -180,6 +180,7 @@
|
||||||
|
|
||||||
(defn initialize-wallet [cofx]
|
(defn initialize-wallet [cofx]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
|
(models.wallet/initialize-tokens)
|
||||||
(models.wallet/update-wallet)
|
(models.wallet/update-wallet)
|
||||||
(transactions/start-sync)))
|
(transactions/start-sync)))
|
||||||
|
|
||||||
|
|
|
@ -360,11 +360,11 @@
|
||||||
|
|
||||||
(defonce polling-executor (atom nil))
|
(defonce polling-executor (atom nil))
|
||||||
|
|
||||||
(defn transactions-query-helper [web3 account-address chain done-fn]
|
(defn transactions-query-helper [web3 all-tokens account-address chain done-fn]
|
||||||
(get-transactions
|
(get-transactions
|
||||||
{:account-address account-address
|
{:account-address account-address
|
||||||
:chain chain
|
:chain chain
|
||||||
:chain-tokens (into {} (map (juxt :address identity) (tokens/tokens-for chain)))
|
:chain-tokens (into {} (map (juxt :address identity) (tokens/tokens-for all-tokens chain)))
|
||||||
:web3 web3
|
:web3 web3
|
||||||
:success-fn (fn [transactions]
|
:success-fn (fn [transactions]
|
||||||
#_(log/debug "Transactions received: " (pr-str (keys transactions)))
|
#_(log/debug "Transactions received: " (pr-str (keys transactions)))
|
||||||
|
@ -380,7 +380,7 @@
|
||||||
(log/debug "Unable to get transactions: " http-error)
|
(log/debug "Unable to get transactions: " http-error)
|
||||||
(done-fn))}))
|
(done-fn))}))
|
||||||
|
|
||||||
(defn- sync-now! [{:keys [network-status :account/account app-state network web3] :as opts}]
|
(defn- sync-now! [{:keys [network-status :account/account :wallet/all-tokens app-state network web3] :as opts}]
|
||||||
(when @polling-executor
|
(when @polling-executor
|
||||||
(let [chain (ethereum/network->chain-keyword (get-in account [:networks network]))
|
(let [chain (ethereum/network->chain-keyword (get-in account [:networks network]))
|
||||||
account-address (:address account)]
|
account-address (:address account)]
|
||||||
|
@ -389,11 +389,11 @@
|
||||||
(not= :custom chain))
|
(not= :custom chain))
|
||||||
(async-periodic-run!
|
(async-periodic-run!
|
||||||
@polling-executor
|
@polling-executor
|
||||||
(partial transactions-query-helper web3 account-address chain))))))
|
(partial transactions-query-helper web3 all-tokens account-address chain))))))
|
||||||
|
|
||||||
;; this function handles background syncing of transactions
|
;; this function handles background syncing of transactions
|
||||||
(defn- background-sync [web3 account-address done-fn]
|
(defn- background-sync [web3 account-address done-fn]
|
||||||
(let [{:keys [network network-status :account/account app-state wallet chats]} @re-frame.db/app-db
|
(let [{:keys [network network-status :account/account app-state wallet chats :wallet/all-tokens]} @re-frame.db/app-db
|
||||||
chain (ethereum/network->chain-keyword (get-in account [:networks network]))]
|
chain (ethereum/network->chain-keyword (get-in account [:networks network]))]
|
||||||
(assert (and web3 account-address network network-status account app-state wallet chats)
|
(assert (and web3 account-address network network-status account app-state wallet chats)
|
||||||
"Must have all necessary data to run background transaction sync")
|
"Must have all necessary data to run background transaction sync")
|
||||||
|
@ -407,7 +407,7 @@
|
||||||
(if-not (or (have-unconfirmed-transactions? (vals transaction-map))
|
(if-not (or (have-unconfirmed-transactions? (vals transaction-map))
|
||||||
(not-empty (set/difference chat-transaction-ids transaction-ids)))
|
(not-empty (set/difference chat-transaction-ids transaction-ids)))
|
||||||
(done-fn)
|
(done-fn)
|
||||||
(transactions-query-helper web3 account-address chain done-fn))))))
|
(transactions-query-helper web3 all-tokens account-address chain done-fn))))))
|
||||||
|
|
||||||
(defn- start-sync! [{:keys [:account/account network web3] :as options}]
|
(defn- start-sync! [{:keys [:account/account network web3] :as options}]
|
||||||
(let [account-address (:address account)]
|
(let [account-address (:address account)]
|
||||||
|
|
|
@ -7,9 +7,11 @@
|
||||||
[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.hex :as utils.hex]
|
||||||
|
[status-im.utils.core :as utils.core]
|
||||||
[status-im.utils.money :as money]
|
[status-im.utils.money :as money]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.fx :as fx]
|
||||||
[status-im.ui.screens.wallet.utils :as wallet.utils]))
|
[status-im.ui.screens.wallet.utils :as wallet.utils]
|
||||||
|
[status-im.utils.config :as config]))
|
||||||
|
|
||||||
(def min-gas-price-wei (money/bignumber 1))
|
(def min-gas-price-wei (money/bignumber 1))
|
||||||
|
|
||||||
|
@ -144,9 +146,10 @@
|
||||||
{:dispatch (conj on-error "transaction was cancelled by user")}))))
|
{:dispatch (conj on-error "transaction was cancelled by user")}))))
|
||||||
|
|
||||||
(defn prepare-unconfirmed-transaction [db now hash]
|
(defn prepare-unconfirmed-transaction [db now hash]
|
||||||
(let [transaction (get-in db [:wallet :send-transaction])]
|
(let [transaction (get-in db [:wallet :send-transaction])
|
||||||
|
all-tokens (:wallet/all-tokens db)]
|
||||||
(let [chain (:chain db)
|
(let [chain (:chain db)
|
||||||
token (tokens/symbol->token (keyword chain) (:symbol transaction))]
|
token (tokens/symbol->token all-tokens (keyword chain) (:symbol transaction))]
|
||||||
(-> transaction
|
(-> transaction
|
||||||
(assoc :confirmations "0"
|
(assoc :confirmations "0"
|
||||||
:timestamp (str now)
|
:timestamp (str now)
|
||||||
|
@ -183,16 +186,29 @@
|
||||||
(defn clear-error-message [db error-type]
|
(defn clear-error-message [db error-type]
|
||||||
(update-in db [:wallet :errors] dissoc error-type))
|
(update-in db [:wallet :errors] dissoc error-type))
|
||||||
|
|
||||||
(defn tokens-symbols [v chain]
|
(defn tokens-symbols [visible-token-symbols all-tokens chain]
|
||||||
(set/difference (set v) (set (map :symbol (tokens/nfts-for 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])
|
||||||
|
chain (ethereum/network->chain-keyword network)]
|
||||||
|
(merge
|
||||||
|
{:db (assoc db :wallet/all-tokens
|
||||||
|
(utils.core/map-values #(utils.core/index-by :address %) tokens/all-default-tokens))}
|
||||||
|
(when config/erc20-contract-warnings-enabled?
|
||||||
|
{:wallet/validate-tokens {:web3 (:web3 db)
|
||||||
|
:tokens (get tokens/all-default-tokens chain)}}))))
|
||||||
|
|
||||||
(fx/defn update-wallet
|
(fx/defn update-wallet
|
||||||
[{{:keys [web3 network network-status] {:keys [address settings]} :account/account :as db} :db}]
|
[{{:keys [web3 network network-status] {:keys [address settings]} :account/account :as db} :db}]
|
||||||
(let [network (get-in db [:account/account :networks network])
|
(let [all-tokens (:wallet/all-tokens db)
|
||||||
|
network (get-in db [:account/account :networks network])
|
||||||
chain (ethereum/network->chain-keyword network)
|
chain (ethereum/network->chain-keyword network)
|
||||||
mainnet? (= :mainnet chain)
|
mainnet? (= :mainnet chain)
|
||||||
assets (get-in settings [:wallet :visible-tokens chain])
|
assets (get-in settings [:wallet :visible-tokens chain])
|
||||||
tokens (tokens-symbols (get-in settings [:wallet :visible-tokens chain]) chain)
|
tokens (tokens-symbols (get-in settings [:wallet :visible-tokens chain]) all-tokens chain)
|
||||||
currency-id (or (get-in settings [:wallet :currency]) :usd)
|
currency-id (or (get-in settings [:wallet :currency]) :usd)
|
||||||
currency (get constants/currencies currency-id)]
|
currency (get constants/currencies currency-id)]
|
||||||
(when (not= network-status :offline)
|
(when (not= network-status :offline)
|
||||||
|
@ -204,6 +220,7 @@
|
||||||
:account-id address
|
:account-id address
|
||||||
:symbols assets
|
:symbols assets
|
||||||
:chain chain
|
:chain chain
|
||||||
|
:all-tokens all-tokens
|
||||||
:success-event :update-token-balance-success
|
:success-event :update-token-balance-success
|
||||||
:error-event :update-token-balance-fail}
|
:error-event :update-token-balance-fail}
|
||||||
:get-prices {:from (if mainnet?
|
:get-prices {:from (if mainnet?
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
:app-state "active"
|
:app-state "active"
|
||||||
:wallet.transactions constants/default-wallet-transactions
|
:wallet.transactions constants/default-wallet-transactions
|
||||||
:wallet-selected-asset {}
|
:wallet-selected-asset {}
|
||||||
|
:wallet/all-tokens {}
|
||||||
:prices {}
|
:prices {}
|
||||||
:peers-count 0
|
:peers-count 0
|
||||||
:peers-summary []
|
:peers-summary []
|
||||||
|
@ -243,6 +244,7 @@
|
||||||
:desktop/desktop
|
:desktop/desktop
|
||||||
:dimensions/window
|
:dimensions/window
|
||||||
:dapps/permissions
|
:dapps/permissions
|
||||||
|
:wallet/all-tokens
|
||||||
:ui/contact
|
:ui/contact
|
||||||
:ui/search
|
:ui/search
|
||||||
:ui/chat]
|
:ui/chat]
|
||||||
|
|
|
@ -39,9 +39,9 @@
|
||||||
(defn- extract-details
|
(defn- extract-details
|
||||||
"First try to parse as EIP681 URI, if not assume this is an address directly.
|
"First try to parse as EIP681 URI, if not assume this is an address directly.
|
||||||
Returns a map containing at least the `address` and `chain-id` keys"
|
Returns a map containing at least the `address` and `chain-id` keys"
|
||||||
[s chain-id]
|
[s chain-id all-tokens]
|
||||||
(or (let [m (eip681/parse-uri s)]
|
(or (let [m (eip681/parse-uri s)]
|
||||||
(merge m (eip681/extract-request-details m)))
|
(merge m (eip681/extract-request-details m all-tokens)))
|
||||||
(when (ethereum/address? s)
|
(when (ethereum/address? s)
|
||||||
{:address s :chain-id chain-id})))
|
{:address s :chain-id chain-id})))
|
||||||
|
|
||||||
|
@ -87,9 +87,9 @@
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:wallet/fill-request-from-url
|
:wallet/fill-request-from-url
|
||||||
(fn [{{:keys [network] :as db} :db} [_ data origin]]
|
(fn [{{:keys [network] :wallet/keys [all-tokens] :as db} :db} [_ data origin]]
|
||||||
(let [current-chain-id (get-in constants/default-networks [network :config :NetworkId])
|
(let [current-chain-id (get-in constants/default-networks [network :config :NetworkId])
|
||||||
{:keys [address chain-id] :as details} (extract-details data current-chain-id)
|
{:keys [address chain-id] :as details} (extract-details data current-chain-id all-tokens)
|
||||||
valid-network? (boolean (= current-chain-id chain-id))
|
valid-network? (boolean (= current-chain-id chain-id))
|
||||||
previous-state (get-in db [:wallet :send-transaction])
|
previous-state (get-in db [:wallet :send-transaction])
|
||||||
old-symbol (:symbol previous-state)
|
old-symbol (:symbol previous-state)
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
ids)}))
|
ids)}))
|
||||||
|
|
||||||
;; TODO(andrey) Each HTTP call will return up to 100 kitties. Maybe we need to implement some kind of paging later
|
;; TODO(andrey) Each HTTP call will return up to 100 kitties. Maybe we need to implement some kind of paging later
|
||||||
(defmethod collectibles/load-collectibles-fx ck [_ _ items-number address _]
|
(defmethod collectibles/load-collectibles-fx ck [_ _ _ items-number address _]
|
||||||
{:http-get {:url (str "https://api.cryptokitties.co/kitties?offset=0&limit="
|
{:http-get {:url (str "https://api.cryptokitties.co/kitties?offset=0&limit="
|
||||||
items-number
|
items-number
|
||||||
"&owner_wallet_address="
|
"&owner_wallet_address="
|
||||||
|
|
|
@ -12,19 +12,20 @@
|
||||||
|
|
||||||
(defmethod load-collectible-fx :default [_ _ _] nil)
|
(defmethod load-collectible-fx :default [_ _ _] nil)
|
||||||
|
|
||||||
(defmulti load-collectibles-fx (fn [_ symbol _ _] symbol))
|
(defmulti load-collectibles-fx (fn [_ _ symbol _ _] symbol))
|
||||||
|
|
||||||
(defmethod load-collectibles-fx :default [web3 symbol items-number address chain-id]
|
(defmethod load-collectibles-fx :default [web3 all-tokens symbol items-number address chain-id]
|
||||||
{:load-collectibles-fx [web3 symbol items-number address chain-id]})
|
{:load-collectibles-fx [web3 all-tokens symbol items-number address chain-id]})
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:show-collectibles-list
|
:show-collectibles-list
|
||||||
(fn [{:keys [db]} [_ address {:keys [symbol amount] :as collectible}]]
|
(fn [{:keys [db]} [_ address {:keys [symbol amount] :as collectible}]]
|
||||||
(let [chain-id (get-in constants/default-networks [(:network db) :config :NetworkId])
|
(let [chain-id (get-in constants/default-networks [(:network db) :config :NetworkId])
|
||||||
|
all-tokens (:wallet/all-tokens db)
|
||||||
items-number (money/to-number amount)
|
items-number (money/to-number amount)
|
||||||
loaded-items-number (count (get-in db [:collectibles symbol]))]
|
loaded-items-number (count (get-in db [:collectibles symbol]))]
|
||||||
(merge (when (not= items-number loaded-items-number)
|
(merge (when (not= items-number loaded-items-number)
|
||||||
(load-collectibles-fx (:web3 db) symbol items-number address chain-id))
|
(load-collectibles-fx (:web3 db) all-tokens symbol items-number address chain-id))
|
||||||
{:dispatch [:navigate-to :collectibles-list collectible]}))))
|
{:dispatch [:navigate-to :collectibles-list collectible]}))))
|
||||||
|
|
||||||
(defn load-token [web3 i items-number contract address symbol]
|
(defn load-token [web3 i items-number contract address symbol]
|
||||||
|
@ -36,9 +37,9 @@
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:load-collectibles-fx
|
:load-collectibles-fx
|
||||||
(fn [[web3 symbol items-number address chain-id]]
|
(fn [[web3 all-tokens symbol items-number address chain-id]]
|
||||||
(let [chain (ethereum/chain-id->chain-keyword chain-id)
|
(let [chain (ethereum/chain-id->chain-keyword chain-id)
|
||||||
contract (:address (tokens/symbol->token chain symbol))]
|
contract (:address (tokens/symbol->token all-tokens chain symbol))]
|
||||||
(load-token web3 0 items-number contract address symbol))))
|
(load-token web3 0 items-number contract address symbol))))
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
|
|
|
@ -12,14 +12,15 @@
|
||||||
(def kudos :KDO)
|
(def kudos :KDO)
|
||||||
|
|
||||||
(defmethod collectibles/load-collectible-fx kudos [{db :db} symbol id]
|
(defmethod collectibles/load-collectible-fx kudos [{db :db} symbol id]
|
||||||
(let [chain-id (get-in constants/default-networks [(:network db) :config :NetworkId])]
|
(let [chain-id (get-in constants/default-networks [(:network db) :config :NetworkId])
|
||||||
{:erc721-token-uri [(:web3 db) symbol id chain-id]}))
|
all-tokens (:wallet/all-tokens db)]
|
||||||
|
{:erc721-token-uri [(:web3 db) all-tokens symbol id chain-id]}))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:erc721-token-uri
|
:erc721-token-uri
|
||||||
(fn [[web3 symbol tokenId chain-id]]
|
(fn [[web3 all-tokens symbol tokenId chain-id]]
|
||||||
(let [chain (ethereum/chain-id->chain-keyword chain-id)
|
(let [chain (ethereum/chain-id->chain-keyword chain-id)
|
||||||
contract (:address (tokens/symbol->token chain symbol))]
|
contract (:address (tokens/symbol->token all-tokens chain symbol))]
|
||||||
(erc721/token-uri web3 contract tokenId
|
(erc721/token-uri web3 contract tokenId
|
||||||
#(re-frame/dispatch [:token-uri-success
|
#(re-frame/dispatch [:token-uri-success
|
||||||
tokenId
|
tokenId
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
imageUri
|
imageUri
|
||||||
}}}}"))
|
}}}}"))
|
||||||
|
|
||||||
(defmethod collectibles/load-collectibles-fx superrare [_ _ _ address _]
|
(defmethod collectibles/load-collectibles-fx superrare [_ _ _ _ address _]
|
||||||
{:http-post {:url graphql-url
|
{:http-post {:url graphql-url
|
||||||
:data (types/clj->json {:query (graphql-query (ethereum/naked-address address))})
|
:data (types/clj->json {:query (graphql-query (ethereum/naked-address address))})
|
||||||
:opts {:headers {"Content-Type" "application/json"}}
|
:opts {:headers {"Content-Type" "application/json"}}
|
||||||
|
|
|
@ -154,8 +154,9 @@
|
||||||
|
|
||||||
(views/defview asset-selector [{:keys [disabled? type symbol error]}]
|
(views/defview asset-selector [{:keys [disabled? type symbol error]}]
|
||||||
(views/letsubs [balance [:balance]
|
(views/letsubs [balance [:balance]
|
||||||
network [:network]]
|
network [:network]
|
||||||
(let [{:keys [name icon decimals] :as token} (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
|
all-tokens [:wallet/all-tokens]]
|
||||||
|
(let [{:keys [name icon decimals] :as token} (tokens/asset-for all-tokens (ethereum/network->chain-keyword network) symbol)]
|
||||||
(when name
|
(when name
|
||||||
[react/view
|
[react/view
|
||||||
[cartouche {:disabled? disabled? :on-press #(re-frame/dispatch [:navigate-to (type->view type)])}
|
[cartouche {:disabled? disabled? :on-press #(re-frame/dispatch [:navigate-to (type->view type)])}
|
||||||
|
|
|
@ -11,7 +11,9 @@
|
||||||
[status-im.utils.money :as money]
|
[status-im.utils.money :as money]
|
||||||
[status-im.utils.prices :as prices]
|
[status-im.utils.prices :as prices]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.utils.fx :as fx]))
|
[status-im.utils.fx :as fx]
|
||||||
|
[status-im.i18n :as i18n]
|
||||||
|
[status-im.utils.utils :as utils.utils]))
|
||||||
|
|
||||||
(defn get-balance [{:keys [web3 account-id on-success on-error]}]
|
(defn get-balance [{:keys [web3 account-id on-success on-error]}]
|
||||||
(if (and web3 account-id)
|
(if (and web3 account-id)
|
||||||
|
@ -51,9 +53,9 @@
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:get-tokens-balance
|
:get-tokens-balance
|
||||||
(fn [{:keys [web3 symbols chain account-id success-event error-event]}]
|
(fn [{:keys [web3 symbols all-tokens chain account-id success-event error-event]}]
|
||||||
(doseq [symbol symbols]
|
(doseq [symbol symbols]
|
||||||
(let [contract (:address (tokens/symbol->token chain symbol))]
|
(let [contract (:address (tokens/symbol->token all-tokens chain symbol))]
|
||||||
(get-token-balance {:web3 web3
|
(get-token-balance {:web3 web3
|
||||||
:contract contract
|
:contract contract
|
||||||
:account-id account-id
|
:account-id account-id
|
||||||
|
@ -80,6 +82,51 @@
|
||||||
(fn [{:keys [web3 obj success-event]}]
|
(fn [{:keys [web3 obj success-event]}]
|
||||||
(ethereum/estimate-gas-web3 web3 (clj->js obj) #(re-frame/dispatch [success-event %2]))))
|
(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
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:update-wallet
|
:update-wallet
|
||||||
|
|
|
@ -31,8 +31,9 @@
|
||||||
{:keys [to to-name public-key]} [:wallet.send/transaction]
|
{:keys [to to-name public-key]} [:wallet.send/transaction]
|
||||||
{:keys [amount amount-error amount-text symbol]} [:wallet.request/transaction]
|
{:keys [amount amount-error amount-text symbol]} [:wallet.request/transaction]
|
||||||
network-status [:network-status]
|
network-status [:network-status]
|
||||||
|
all-tokens [:wallet/all-tokens]
|
||||||
scroll (atom nil)]
|
scroll (atom nil)]
|
||||||
(let [{:keys [decimals] :as token} (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
|
(let [{:keys [decimals] :as token} (tokens/asset-for all-tokens (ethereum/network->chain-keyword network) symbol)]
|
||||||
[wallet.components/simple-screen {:avoid-keyboard? true}
|
[wallet.components/simple-screen {:avoid-keyboard? true}
|
||||||
[wallet.components/toolbar (i18n/label :t/new-request)]
|
[wallet.components/toolbar (i18n/label :t/new-request)]
|
||||||
[react/view components.styles/flex
|
[react/view components.styles/flex
|
||||||
|
|
|
@ -27,16 +27,16 @@
|
||||||
(security/safe-unmask-data masked-password)
|
(security/safe-unmask-data masked-password)
|
||||||
on-completed))
|
on-completed))
|
||||||
|
|
||||||
(defn- send-tokens [symbol chain {:keys [from to value gas gasPrice]} on-completed masked-password]
|
(defn- send-tokens [all-tokens symbol chain {:keys [from to value gas gasPrice]} on-completed masked-password]
|
||||||
(let [contract (:address (tokens/symbol->token (keyword chain) symbol))]
|
(let [contract (:address (tokens/symbol->token all-tokens (keyword chain) symbol))]
|
||||||
(erc20/transfer contract from to value gas gasPrice masked-password on-completed)))
|
(erc20/transfer contract from to value gas gasPrice masked-password on-completed)))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::send-transaction
|
::send-transaction
|
||||||
(fn [[params symbol chain on-completed masked-password]]
|
(fn [[params all-tokens symbol chain on-completed masked-password]]
|
||||||
(case symbol
|
(case symbol
|
||||||
:ETH (send-ethers params on-completed masked-password)
|
:ETH (send-ethers params on-completed masked-password)
|
||||||
(send-tokens symbol chain params on-completed masked-password))))
|
(send-tokens all-tokens symbol chain params on-completed masked-password))))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::sign-message
|
::sign-message
|
||||||
|
@ -57,12 +57,14 @@
|
||||||
:wallet/send-transaction
|
:wallet/send-transaction
|
||||||
(fn [{{:keys [chain] :as db} :db} _]
|
(fn [{{:keys [chain] :as db} :db} _]
|
||||||
(let [{:keys [password symbol in-progress?] :as transaction} (get-in db [:wallet :send-transaction])
|
(let [{:keys [password symbol in-progress?] :as transaction} (get-in db [:wallet :send-transaction])
|
||||||
|
all-tokens (:wallet/all-tokens db)
|
||||||
from (get-in db [:account/account :address])]
|
from (get-in db [:account/account :address])]
|
||||||
(when-not in-progress?
|
(when-not in-progress?
|
||||||
{: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 [(models.wallet/prepare-send-transaction from transaction)
|
||||||
|
all-tokens
|
||||||
symbol
|
symbol
|
||||||
chain
|
chain
|
||||||
#(re-frame/dispatch [::transaction-completed (types/json->clj %)])
|
#(re-frame/dispatch [::transaction-completed (types/json->clj %)])
|
||||||
|
|
|
@ -138,12 +138,12 @@
|
||||||
(i18n/label :t/transactions-sign-transaction)
|
(i18n/label :t/transactions-sign-transaction)
|
||||||
[vector-icons/icon :icons/forward {:color (if sign-enabled? colors/white colors/white-light-transparent)}]]]))
|
[vector-icons/icon :icons/forward {:color (if sign-enabled? colors/white colors/white-light-transparent)}]]]))
|
||||||
|
|
||||||
(defn- render-send-transaction-view [{:keys [modal? transaction scroll advanced? network amount-input network-status]}]
|
(defn- render-send-transaction-view [{:keys [modal? transaction scroll advanced? network all-tokens amount-input network-status]}]
|
||||||
(let [{:keys [amount amount-text amount-error asset-error show-password-input? to to-name sufficient-funds?
|
(let [{:keys [amount amount-text amount-error asset-error show-password-input? to to-name sufficient-funds?
|
||||||
sufficient-gas? in-progress? from-chat? symbol]} transaction
|
sufficient-gas? in-progress? from-chat? symbol]} transaction
|
||||||
chain (ethereum/network->chain-keyword network)
|
chain (ethereum/network->chain-keyword network)
|
||||||
native-currency (tokens/native-currency chain)
|
native-currency (tokens/native-currency chain)
|
||||||
{:keys [decimals] :as token} (tokens/asset-for chain symbol)
|
{:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol)
|
||||||
online? (= :online network-status)]
|
online? (= :online network-status)]
|
||||||
[wallet.components/simple-screen {:avoid-keyboard? (not modal?)
|
[wallet.components/simple-screen {:avoid-keyboard? (not modal?)
|
||||||
:status-bar-type (if modal? :modal-wallet :wallet)}
|
:status-bar-type (if modal? :modal-wallet :wallet)}
|
||||||
|
@ -206,12 +206,14 @@
|
||||||
advanced? [:wallet.send/advanced?]
|
advanced? [:wallet.send/advanced?]
|
||||||
network [:account/network]
|
network [:account/network]
|
||||||
scroll (atom nil)
|
scroll (atom nil)
|
||||||
network-status [:network-status]]
|
network-status [:network-status]
|
||||||
|
all-tokens [:wallet/all-tokens]]
|
||||||
[send-transaction-view {:modal? false
|
[send-transaction-view {:modal? false
|
||||||
:transaction transaction
|
:transaction transaction
|
||||||
:scroll scroll
|
:scroll scroll
|
||||||
:advanced? advanced?
|
:advanced? advanced?
|
||||||
:network network
|
:network network
|
||||||
|
:all-tokens all-tokens
|
||||||
:network-status network-status}]))
|
:network-status network-status}]))
|
||||||
|
|
||||||
;; SEND TRANSACTION FROM DAPP
|
;; SEND TRANSACTION FROM DAPP
|
||||||
|
@ -220,13 +222,15 @@
|
||||||
advanced? [:wallet.send/advanced?]
|
advanced? [:wallet.send/advanced?]
|
||||||
network [:account/network]
|
network [:account/network]
|
||||||
scroll (atom nil)
|
scroll (atom nil)
|
||||||
network-status [:network-status]]
|
network-status [:network-status]
|
||||||
|
all-tokens [:wallet/all-tokens]]
|
||||||
(if transaction
|
(if transaction
|
||||||
[send-transaction-view {:modal? true
|
[send-transaction-view {:modal? true
|
||||||
:transaction transaction
|
:transaction transaction
|
||||||
:scroll scroll
|
:scroll scroll
|
||||||
:advanced? advanced?
|
:advanced? advanced?
|
||||||
:network network
|
:network network
|
||||||
|
:all-tokens all-tokens
|
||||||
:network-status network-status}]
|
:network-status network-status}]
|
||||||
[react/view wallet.styles/wallet-modal-container
|
[react/view wallet.styles/wallet-modal-container
|
||||||
[react/view components.styles/flex
|
[react/view components.styles/flex
|
||||||
|
|
|
@ -25,10 +25,10 @@
|
||||||
(wallet.events/update-token-balance-success symbol balance)))
|
(wallet.events/update-token-balance-success symbol balance)))
|
||||||
|
|
||||||
(fx/defn wallet-autoconfig-tokens [{:keys [db]}]
|
(fx/defn wallet-autoconfig-tokens [{:keys [db]}]
|
||||||
(let [{:keys [account/account web3 network-status]} db
|
(let [{:keys [account/account web3 network-status] :wallet/keys [all-tokens]} db
|
||||||
network (get (:networks account) (:network account))
|
network (get (:networks account) (:network account))
|
||||||
chain (ethereum/network->chain-keyword network)
|
chain (ethereum/network->chain-keyword network)
|
||||||
contracts (->> (tokens/tokens-for chain)
|
contracts (->> (tokens/tokens-for all-tokens chain)
|
||||||
(remove :hidden?))]
|
(remove :hidden?))]
|
||||||
(when-not (= network-status :offline)
|
(when-not (= network-status :offline)
|
||||||
(doseq [{:keys [address symbol]} contracts]
|
(doseq [{:keys [address symbol]} contracts]
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
|
|
||||||
(defview manage-assets []
|
(defview manage-assets []
|
||||||
(letsubs [network [:network]
|
(letsubs [network [:network]
|
||||||
visible-tokens [:wallet/visible-tokens-symbols]]
|
visible-tokens [:wallet/visible-tokens-symbols]
|
||||||
|
all-tokens [:wallet/all-tokens]]
|
||||||
[react/view (merge components.styles/flex {:background-color :white})
|
[react/view (merge components.styles/flex {:background-color :white})
|
||||||
[status-bar/status-bar {:type :modal-wallet}]
|
[status-bar/status-bar {:type :modal-wallet}]
|
||||||
[toolbar/toolbar {:style wallet.styles/toolbar}
|
[toolbar/toolbar {:style wallet.styles/toolbar}
|
||||||
|
@ -35,6 +36,6 @@
|
||||||
[toolbar/content-title {:color :white}
|
[toolbar/content-title {:color :white}
|
||||||
(i18n/label :t/wallet-assets)]]
|
(i18n/label :t/wallet-assets)]]
|
||||||
[react/view {:style components.styles/flex}
|
[react/view {:style components.styles/flex}
|
||||||
[list/flat-list {:data (tokens/sorted-tokens-for (ethereum/network->chain-keyword network))
|
[list/flat-list {:data (tokens/sorted-tokens-for all-tokens (ethereum/network->chain-keyword network))
|
||||||
:key-fn (comp str :symbol)
|
:key-fn (comp str :symbol)
|
||||||
:render-fn #(render-token % visible-tokens)}]]]))
|
:render-fn #(render-token % visible-tokens)}]]]))
|
||||||
|
|
|
@ -50,14 +50,18 @@
|
||||||
.toNumber))
|
.toNumber))
|
||||||
acc)) 0 balance))
|
acc)) 0 balance))
|
||||||
|
|
||||||
|
(re-frame/reg-sub :wallet/all-tokens
|
||||||
|
(fn [db] (:wallet/all-tokens db)))
|
||||||
|
|
||||||
(re-frame/reg-sub :portfolio-value
|
(re-frame/reg-sub :portfolio-value
|
||||||
:<- [:balance]
|
:<- [:balance]
|
||||||
:<- [:prices]
|
:<- [:prices]
|
||||||
:<- [:wallet/currency]
|
:<- [:wallet/currency]
|
||||||
:<- [:network]
|
:<- [:network]
|
||||||
(fn [[balance prices currency network] [_ currency-code]]
|
:<- [:wallet/all-tokens]
|
||||||
|
(fn [[balance prices currency network all-tokens] [_ currency-code]]
|
||||||
(if (and balance prices)
|
(if (and balance prices)
|
||||||
(let [assets (tokens/tokens-for (ethereum/network->chain-keyword network))
|
(let [assets (tokens/tokens-for all-tokens (ethereum/network->chain-keyword network))
|
||||||
token->decimals (into {} (map #(vector (:symbol %) (:decimals %)) assets))
|
token->decimals (into {} (map #(vector (:symbol %) (:decimals %)) assets))
|
||||||
balance-total-value
|
balance-total-value
|
||||||
(get-balance-total-value balance
|
(get-balance-total-value balance
|
||||||
|
@ -102,10 +106,11 @@
|
||||||
(re-frame/reg-sub :wallet/visible-assets
|
(re-frame/reg-sub :wallet/visible-assets
|
||||||
:<- [:network]
|
:<- [:network]
|
||||||
:<- [:wallet/visible-tokens-symbols]
|
:<- [:wallet/visible-tokens-symbols]
|
||||||
(fn [[network visible-tokens-symbols]]
|
:<- [:wallet/all-tokens]
|
||||||
|
(fn [[network visible-tokens-symbols all-tokens]]
|
||||||
(let [chain (ethereum/network->chain-keyword network)]
|
(let [chain (ethereum/network->chain-keyword network)]
|
||||||
(conj (filter #(contains? visible-tokens-symbols (:symbol %))
|
(conj (filter #(contains? visible-tokens-symbols (:symbol %))
|
||||||
(tokens/sorted-tokens-for (ethereum/network->chain-keyword network)))
|
(tokens/sorted-tokens-for all-tokens (ethereum/network->chain-keyword network)))
|
||||||
(tokens/native-currency chain)))))
|
(tokens/native-currency chain)))))
|
||||||
|
|
||||||
(re-frame/reg-sub :wallet/visible-assets-with-amount
|
(re-frame/reg-sub :wallet/visible-assets-with-amount
|
||||||
|
|
|
@ -27,13 +27,14 @@
|
||||||
network [:account/network]
|
network [:account/network]
|
||||||
{gas-edit :gas
|
{gas-edit :gas
|
||||||
max-fee :max-fee
|
max-fee :max-fee
|
||||||
gas-price-edit :gas-price} [:wallet/edit]]
|
gas-price-edit :gas-price} [:wallet/edit]
|
||||||
|
all-tokens [:wallet/all-tokens]]
|
||||||
(let [{:keys [amount symbol]} send-transaction
|
(let [{:keys [amount symbol]} send-transaction
|
||||||
gas (:value gas-edit)
|
gas (:value gas-edit)
|
||||||
gas-price (:value gas-price-edit)
|
gas-price (:value gas-price-edit)
|
||||||
chain (ethereum/network->chain-keyword network)
|
chain (ethereum/network->chain-keyword network)
|
||||||
native-currency (tokens/native-currency chain)
|
native-currency (tokens/native-currency chain)
|
||||||
{:keys [decimals] :as token} (tokens/asset-for chain symbol)]
|
{:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol)]
|
||||||
[components/simple-screen {:status-bar-type :modal-wallet}
|
[components/simple-screen {:status-bar-type :modal-wallet}
|
||||||
[toolbar (i18n/label :t/wallet-transaction-fee)]
|
[toolbar (i18n/label :t/wallet-transaction-fee)]
|
||||||
[react/view components.styles/flex
|
[react/view components.styles/flex
|
||||||
|
|
|
@ -50,13 +50,14 @@
|
||||||
(:postponed :pending) (transaction-icon :icons/arrow-right colors/gray-light colors/gray)
|
(:postponed :pending) (transaction-icon :icons/arrow-right colors/gray-light colors/gray)
|
||||||
(throw (str "Unknown transaction type: " k))))
|
(throw (str "Unknown transaction type: " k))))
|
||||||
|
|
||||||
(defn render-transaction [{:keys [hash from-contact to-contact to from type value time-formatted symbol]} network hide-details?]
|
(defn render-transaction [{:keys [hash from-contact to-contact to from type value time-formatted symbol]}
|
||||||
|
network all-tokens hide-details?]
|
||||||
(let [[label contact address
|
(let [[label contact address
|
||||||
contact-accessibility-label
|
contact-accessibility-label
|
||||||
address-accessibility-label] (if (inbound? type)
|
address-accessibility-label] (if (inbound? type)
|
||||||
[(i18n/label :t/from) from-contact from :sender-text :sender-address-text]
|
[(i18n/label :t/from) from-contact from :sender-text :sender-address-text]
|
||||||
[(i18n/label :t/to) to-contact to :recipient-name-text :recipient-address-text])
|
[(i18n/label :t/to) to-contact to :recipient-name-text :recipient-address-text])
|
||||||
{:keys [decimals] :as token} (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
|
{:keys [decimals] :as token} (tokens/asset-for all-tokens (ethereum/network->chain-keyword network) symbol)]
|
||||||
[list/touchable-item #(when-not hide-details? (re-frame/dispatch [:show-transaction-details hash]))
|
[list/touchable-item #(when-not hide-details? (re-frame/dispatch [:show-transaction-details hash]))
|
||||||
[react/view {:accessibility-label :transaction-item}
|
[react/view {:accessibility-label :transaction-item}
|
||||||
[list/item
|
[list/item
|
||||||
|
@ -101,11 +102,12 @@
|
||||||
(defview history-list [& [hide-details?]]
|
(defview history-list [& [hide-details?]]
|
||||||
(letsubs [transactions-history-list [:wallet.transactions/transactions-history-list]
|
(letsubs [transactions-history-list [:wallet.transactions/transactions-history-list]
|
||||||
filter-data [:wallet.transactions/filters]
|
filter-data [:wallet.transactions/filters]
|
||||||
network [:account/network]]
|
network [:account/network]
|
||||||
|
all-tokens [:wallet/all-tokens]]
|
||||||
[react/view components.styles/flex
|
[react/view components.styles/flex
|
||||||
[list/section-list {:sections (map #(update-transactions % filter-data) transactions-history-list)
|
[list/section-list {:sections (map #(update-transactions % filter-data) transactions-history-list)
|
||||||
:key-fn :hash
|
:key-fn :hash
|
||||||
:render-fn #(render-transaction % network hide-details?)
|
:render-fn #(render-transaction % network all-tokens hide-details?)
|
||||||
:empty-component [react/i18n-text {:style styles/empty-text
|
:empty-component [react/i18n-text {:style styles/empty-text
|
||||||
:key :transactions-history-empty}]
|
:key :transactions-history-empty}]
|
||||||
:on-refresh #(re-frame/dispatch [:update-transactions])
|
:on-refresh #(re-frame/dispatch [:update-transactions])
|
||||||
|
@ -163,8 +165,8 @@
|
||||||
(-> amount (money/token->unit (:decimals token)) money/to-fixed str))
|
(-> amount (money/token->unit (:decimals token)) money/to-fixed str))
|
||||||
"..."))
|
"..."))
|
||||||
|
|
||||||
(defn details-header [network {:keys [value date type symbol token]}]
|
(defn details-header [network all-tokens {:keys [value date type symbol token]}]
|
||||||
(let [asset (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
|
(let [asset (tokens/asset-for all-tokens (ethereum/network->chain-keyword network) symbol)]
|
||||||
[react/view {:style styles/details-header}
|
[react/view {:style styles/details-header}
|
||||||
[react/view {:style styles/details-header-icon}
|
[react/view {:style styles/details-header-icon}
|
||||||
[list/item-icon (transaction-type->icon type)]]
|
[list/item-icon (transaction-type->icon type)]]
|
||||||
|
@ -245,7 +247,8 @@
|
||||||
(letsubs [{:keys [hash url type] :as transaction} [:wallet.transactions/transaction-details]
|
(letsubs [{:keys [hash url type] :as transaction} [:wallet.transactions/transaction-details]
|
||||||
confirmations [:wallet.transactions.details/confirmations]
|
confirmations [:wallet.transactions.details/confirmations]
|
||||||
confirmations-progress [:wallet.transactions.details/confirmations-progress]
|
confirmations-progress [:wallet.transactions.details/confirmations-progress]
|
||||||
network [:account/network]]
|
network [:account/network]
|
||||||
|
all-tokens [:wallet/all-tokens]]
|
||||||
[react/view {:style components.styles/flex}
|
[react/view {:style components.styles/flex}
|
||||||
[status-bar/status-bar]
|
[status-bar/status-bar]
|
||||||
[toolbar/toolbar {}
|
[toolbar/toolbar {}
|
||||||
|
@ -253,7 +256,7 @@
|
||||||
[toolbar/content-title (i18n/label :t/transaction-details)]
|
[toolbar/content-title (i18n/label :t/transaction-details)]
|
||||||
(when transaction [toolbar/actions (details-action hash url)])]
|
(when transaction [toolbar/actions (details-action hash url)])]
|
||||||
[react/scroll-view {:style components.styles/main-container}
|
[react/scroll-view {:style components.styles/main-container}
|
||||||
[details-header network transaction]
|
[details-header network all-tokens transaction]
|
||||||
[details-confirmations confirmations confirmations-progress type]
|
[details-confirmations confirmations confirmations-progress type]
|
||||||
[react/view {:style styles/details-separator}]
|
[react/view {:style styles/details-separator}]
|
||||||
[details-list transaction]]]))
|
[details-list transaction]]]))
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
(def extensions-enabled? (enabled? (get-config :EXTENSIONS 0)))
|
(def extensions-enabled? (enabled? (get-config :EXTENSIONS 0)))
|
||||||
(def hardwallet-enabled? (enabled? (get-config :HARDWALLET_ENABLED 0)))
|
(def hardwallet-enabled? (enabled? (get-config :HARDWALLET_ENABLED 0)))
|
||||||
(def dev-build? (enabled? (get-config :DEV_BUILD 0)))
|
(def dev-build? (enabled? (get-config :DEV_BUILD 0)))
|
||||||
|
(def erc20-contract-warnings-enabled? (enabled? (get-config :ERC20_CONTRACT_WARNINGS)))
|
||||||
|
|
||||||
;; CONFIG VALUES
|
;; CONFIG VALUES
|
||||||
(def log-level
|
(def log-level
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
|
|
||||||
(defn map-values
|
(defn map-values
|
||||||
"Efficiently apply function to all map values"
|
"Efficiently apply function to all map values"
|
||||||
[m f]
|
[f m]
|
||||||
(into {}
|
(into {}
|
||||||
(map (fn [[k v]]
|
(map (fn [[k v]]
|
||||||
[k (f v)]))
|
[k (f v)]))
|
||||||
|
@ -57,3 +57,9 @@
|
||||||
(if (every? map? maps)
|
(if (every? map? maps)
|
||||||
(apply merge-with deep-merge maps)
|
(apply merge-with deep-merge maps)
|
||||||
(last maps)))
|
(last maps)))
|
||||||
|
|
||||||
|
(defn index-by
|
||||||
|
"Given a collection and a unique key function, returns a map that indexes the collection.
|
||||||
|
Similar to group-by except that the map values are single objects (depends on key uniqueness)."
|
||||||
|
[key coll]
|
||||||
|
(into {} (map #(vector (key %) %) coll)))
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
n (money/bignumber (string/replace s "ETH" ""))]
|
n (money/bignumber (string/replace s "ETH" ""))]
|
||||||
(if eth? (.times n 1e18) n))))
|
(if eth? (.times n 1e18) n))))
|
||||||
|
|
||||||
(defn extract-request-details [{:keys [value address chain-id function-name function-arguments]}]
|
(defn extract-request-details [{:keys [value address chain-id function-name function-arguments]} all-tokens]
|
||||||
"Return a map encapsulating request details (with keys `value`, `address` and `symbol`) from a parsed URI.
|
"Return a map encapsulating request details (with keys `value`, `address` and `symbol`) from a parsed URI.
|
||||||
Supports ethereum and erc20 token."
|
Supports ethereum and erc20 token."
|
||||||
(when address
|
(when address
|
||||||
|
@ -76,7 +76,7 @@
|
||||||
:address address}
|
:address address}
|
||||||
"transfer"
|
"transfer"
|
||||||
{:value (money/bignumber (:uint256 function-arguments))
|
{:value (money/bignumber (:uint256 function-arguments))
|
||||||
:symbol (:symbol (tokens/address->token (ethereum/chain-id->chain-keyword chain-id) address))
|
:symbol (:symbol (tokens/address->token all-tokens (ethereum/chain-id->chain-keyword chain-id) address))
|
||||||
:address (:address function-arguments)}
|
:address (:address function-arguments)}
|
||||||
nil)))
|
nil)))
|
||||||
|
|
||||||
|
@ -104,8 +104,8 @@
|
||||||
|
|
||||||
(defn generate-erc20-uri
|
(defn generate-erc20-uri
|
||||||
"Generate a EIP 681 URI encapsulating ERC20 token transfer"
|
"Generate a EIP 681 URI encapsulating ERC20 token transfer"
|
||||||
[address {:keys [symbol value chain-id] :as m}]
|
[address {:keys [symbol value chain-id] :as m} all-tokens]
|
||||||
(when-let [token (tokens/symbol->token (if chain-id (ethereum/chain-id->chain-keyword chain-id) :mainnet) symbol)]
|
(when-let [token (tokens/symbol->token all-tokens (if chain-id (ethereum/chain-id->chain-keyword chain-id) :mainnet) symbol)]
|
||||||
(generate-uri (:address token)
|
(generate-uri (:address token)
|
||||||
(merge (dissoc m :value :symbol)
|
(merge (dissoc m :value :symbol)
|
||||||
{:function-name "transfer"
|
{:function-name "transfer"
|
||||||
|
|
|
@ -18,27 +18,99 @@
|
||||||
(:require [status-im.utils.ethereum.core :as ethereum]
|
(:require [status-im.utils.ethereum.core :as ethereum]
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.utils.security :as security]
|
[status-im.utils.security :as security]
|
||||||
|
[status-im.js-dependencies :as dependencies]
|
||||||
[status-im.utils.types :as types])
|
[status-im.utils.types :as types])
|
||||||
(:refer-clojure :exclude [name symbol]))
|
(:refer-clojure :exclude [name symbol]))
|
||||||
|
|
||||||
|
(def utils dependencies/web3-utils)
|
||||||
|
|
||||||
|
(def abi
|
||||||
|
(clj->js
|
||||||
|
[{:constant true
|
||||||
|
:inputs []
|
||||||
|
:name "name"
|
||||||
|
:outputs [{:name ""
|
||||||
|
:type "string"}]
|
||||||
|
:payable false
|
||||||
|
:stateMutability "view"
|
||||||
|
:type "function"}
|
||||||
|
{:constant true
|
||||||
|
:inputs []
|
||||||
|
:name "symbol"
|
||||||
|
:outputs [{:name ""
|
||||||
|
:type "string"}]
|
||||||
|
:payable false
|
||||||
|
:stateMutability "view"
|
||||||
|
:type "function"}
|
||||||
|
{:constant true
|
||||||
|
:inputs []
|
||||||
|
:name "decimals"
|
||||||
|
:outputs [{:name ""
|
||||||
|
:type "uint8"}]
|
||||||
|
:payable false
|
||||||
|
:stateMutability "view"
|
||||||
|
:type "function"}
|
||||||
|
{:constant true
|
||||||
|
:inputs [{:name "_who"
|
||||||
|
:type "address"}]
|
||||||
|
:name "balanceOf"
|
||||||
|
:outputs [{:name ""
|
||||||
|
:type "uint256"}]
|
||||||
|
:payable false
|
||||||
|
:stateMutability "view"
|
||||||
|
:type "function"}
|
||||||
|
{:constant true
|
||||||
|
:inputs []
|
||||||
|
:name "totalSupply"
|
||||||
|
:outputs [{:name ""
|
||||||
|
:type "uint256"}],
|
||||||
|
:payable false
|
||||||
|
:stateMutability "view"
|
||||||
|
:type "function"}
|
||||||
|
{:constant false
|
||||||
|
:inputs [{:name "_to"
|
||||||
|
:type "address"}
|
||||||
|
{:name "_value"
|
||||||
|
:type "uint256"}]
|
||||||
|
:name "transfer"
|
||||||
|
:outputs [{:name ""
|
||||||
|
:type "bool"}],
|
||||||
|
:payable false
|
||||||
|
:stateMutability "nonpayable"
|
||||||
|
:type "function"}
|
||||||
|
{:anonymous false
|
||||||
|
:inputs [{:indexed true
|
||||||
|
:name "from"
|
||||||
|
:type "address"},
|
||||||
|
{:indexed true
|
||||||
|
:name "to"
|
||||||
|
:type "address"},
|
||||||
|
{:indexed false
|
||||||
|
:name "value"
|
||||||
|
:type "uint256"}]
|
||||||
|
:name "Transfer"
|
||||||
|
:type "event"}]))
|
||||||
|
|
||||||
|
(defn get-instance* [web3 contract]
|
||||||
|
(.at (.contract (.-eth web3) abi) contract))
|
||||||
|
|
||||||
|
(def get-instance
|
||||||
|
(memoize get-instance*))
|
||||||
|
|
||||||
(defn name [web3 contract cb]
|
(defn name [web3 contract cb]
|
||||||
(ethereum/call web3 (ethereum/call-params contract "name()") cb))
|
(.name (get-instance web3 contract) cb))
|
||||||
|
|
||||||
(defn symbol [web3 contract cb]
|
(defn symbol [web3 contract cb]
|
||||||
(ethereum/call web3 (ethereum/call-params contract "symbol()") cb))
|
(.symbol (get-instance web3 contract) cb))
|
||||||
|
|
||||||
(defn decimals [web3 contract cb]
|
(defn decimals [web3 contract cb]
|
||||||
(ethereum/call web3 (ethereum/call-params contract "decimals()") cb))
|
(.decimals (get-instance web3 contract) cb))
|
||||||
|
|
||||||
(defn total-supply [web3 contract cb]
|
(defn total-supply [web3 contract cb]
|
||||||
(ethereum/call web3
|
(.totalSupply (get-instance web3 contract) cb))
|
||||||
(ethereum/call-params contract "totalSupply()")
|
|
||||||
#(cb %1 (ethereum/hex->bignumber %2))))
|
|
||||||
|
|
||||||
(defn balance-of [web3 contract address cb]
|
(defn balance-of [web3 contract address cb]
|
||||||
(ethereum/call web3
|
(.balanceOf (get-instance web3 contract) address cb))
|
||||||
(ethereum/call-params contract "balanceOf(address)" (ethereum/normalized-address address))
|
|
||||||
#(cb %1 (ethereum/hex->bignumber %2))))
|
|
||||||
|
|
||||||
(defn transfer [contract from to value gas gas-price masked-password on-completed]
|
(defn transfer [contract from to value gas gas-price masked-password on-completed]
|
||||||
(status/send-transaction (types/clj->json
|
(status/send-transaction (types/clj->json
|
||||||
|
|
|
@ -45,9 +45,21 @@
|
||||||
(defn ethereum? [symbol]
|
(defn ethereum? [symbol]
|
||||||
(native-currency-symbols symbol))
|
(native-currency-symbols symbol))
|
||||||
|
|
||||||
;; symbol are used as global identifier (per network) so they must be unique
|
;; NOTE(goranjovic) - fields description:
|
||||||
|
;;
|
||||||
|
;; - address - token contract address
|
||||||
|
;; - symbol - token identifier, must be unique within network
|
||||||
|
;; - name - token display name
|
||||||
|
;; - decimals - the maximum number of decimals (raw balance must be divided by 10^decimals to get the actual amount)
|
||||||
|
;; - nft? - set to true when token is an ERC-781 collectible
|
||||||
|
;; - hidden? - when true, token is not displayed in any asset selection screens, but will be displayed properly in
|
||||||
|
;; transaction history (setting this field is a form of "soft" token removal).
|
||||||
|
;; - skip-decimals-check? - some tokens do not include the decimals field, which is compliant with ERC-20 since it is
|
||||||
|
;;; and optional field. In that case we are explicitly skipping this step in order not to raise a false error.
|
||||||
|
;;; We have this explicit flag for decimals and not for name and symbol because we can't tell apart unset decimals
|
||||||
|
;;; from 0 decimals case.
|
||||||
|
|
||||||
(def all
|
(def all-default-tokens
|
||||||
{:mainnet
|
{:mainnet
|
||||||
(resolve-icons :mainnet
|
(resolve-icons :mainnet
|
||||||
[{:symbol :DAI
|
[{:symbol :DAI
|
||||||
|
@ -83,9 +95,9 @@
|
||||||
:address "0xB97048628DB6B661D4C2aA833e95Dbe1A905B280"
|
:address "0xB97048628DB6B661D4C2aA833e95Dbe1A905B280"
|
||||||
:decimals 18}
|
:decimals 18}
|
||||||
{:symbol :VRS
|
{:symbol :VRS
|
||||||
:name "VEROS"
|
:name "Veros"
|
||||||
:address "0xedbaf3c5100302dcdda53269322f3730b1f0416d"
|
:address "0x92E78dAe1315067a8819EFD6dCA432de9DCdE2e9"
|
||||||
:decimals 5}
|
:decimals 6}
|
||||||
{:symbol :GNT
|
{:symbol :GNT
|
||||||
:name "Golem Network Token"
|
:name "Golem Network Token"
|
||||||
:address "0xa74476443119A942dE498590Fe1f2454d7D4aC0d"
|
:address "0xa74476443119A942dE498590Fe1f2454d7D4aC0d"
|
||||||
|
@ -109,7 +121,8 @@
|
||||||
{:symbol :DGD
|
{:symbol :DGD
|
||||||
:name "Digix DAO"
|
:name "Digix DAO"
|
||||||
:address "0xe0b7927c4af23765cb51314a0e0521a9645f0e2a"
|
:address "0xe0b7927c4af23765cb51314a0e0521a9645f0e2a"
|
||||||
:decimals 9}
|
:decimals 9
|
||||||
|
:skip-decimals-check? true}
|
||||||
{:symbol :AE
|
{:symbol :AE
|
||||||
:name "Aeternity"
|
:name "Aeternity"
|
||||||
:address "0x5ca9a71b1d01849c0a95490cc00559717fcf0d1d"
|
:address "0x5ca9a71b1d01849c0a95490cc00559717fcf0d1d"
|
||||||
|
@ -118,8 +131,8 @@
|
||||||
:name "Tronix"
|
:name "Tronix"
|
||||||
:address "0xf230b790e05390fc8295f4d3f60332c93bed42e2"
|
:address "0xf230b790e05390fc8295f4d3f60332c93bed42e2"
|
||||||
:decimals 6}
|
:decimals 6}
|
||||||
{:symbol :BQX
|
{:symbol :ETHOS
|
||||||
:name "Bitquence"
|
:name "Ethos"
|
||||||
:address "0x5af2be193a6abca9c8817001f45744777db30756"
|
:address "0x5af2be193a6abca9c8817001f45744777db30756"
|
||||||
:decimals 8}
|
:decimals 8}
|
||||||
{:symbol :RDN
|
{:symbol :RDN
|
||||||
|
@ -127,7 +140,7 @@
|
||||||
:address "0x255aa6df07540cb5d3d297f0d0d4d84cb52bc8e6"
|
:address "0x255aa6df07540cb5d3d297f0d0d4d84cb52bc8e6"
|
||||||
:decimals 18}
|
:decimals 18}
|
||||||
{:symbol :SNT
|
{:symbol :SNT
|
||||||
:name "Status Network"
|
:name "Status Network Token"
|
||||||
:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
|
:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
|
||||||
:decimals 18}
|
:decimals 18}
|
||||||
{:symbol :SNGLS
|
{:symbol :SNGLS
|
||||||
|
@ -205,13 +218,14 @@
|
||||||
{:symbol :LRC
|
{:symbol :LRC
|
||||||
:name "loopring"
|
:name "loopring"
|
||||||
:address "0xEF68e7C694F40c8202821eDF525dE3782458639f"
|
:address "0xEF68e7C694F40c8202821eDF525dE3782458639f"
|
||||||
:decimals 18}
|
:decimals 18
|
||||||
|
:skip-decimals-check? true}
|
||||||
{:symbol :ZSC
|
{:symbol :ZSC
|
||||||
:name "Zeus Shield Coin"
|
:name "Zeus Shield Coin"
|
||||||
:address "0x7A41e0517a5ecA4FdbC7FbebA4D4c47B9fF6DC63"
|
:address "0x7A41e0517a5ecA4FdbC7FbebA4D4c47B9fF6DC63"
|
||||||
:decimals 18}
|
:decimals 18}
|
||||||
{:symbol :DATA
|
{:symbol :DATA
|
||||||
:name "DATAcoin"
|
:name "Streamr DATAcoin"
|
||||||
:address "0x0cf0ee63788a0849fe5297f3407f701e122cc023"
|
:address "0x0cf0ee63788a0849fe5297f3407f701e122cc023"
|
||||||
:decimals 18}
|
:decimals 18}
|
||||||
{:symbol :RCN
|
{:symbol :RCN
|
||||||
|
@ -271,7 +285,7 @@
|
||||||
:address "0x12480e24eb5bec1a9d4369cab6a80cad3c0a377a"
|
:address "0x12480e24eb5bec1a9d4369cab6a80cad3c0a377a"
|
||||||
:decimals 2}
|
:decimals 2}
|
||||||
{:symbol :MANA
|
{:symbol :MANA
|
||||||
:name "Decentraland"
|
:name "Decentraland MANA"
|
||||||
:address "0x0f5d2fb29fb7d3cfee444a200298f468908cc942"
|
:address "0x0f5d2fb29fb7d3cfee444a200298f468908cc942"
|
||||||
:decimals 18}
|
:decimals 18}
|
||||||
{:symbol :AST
|
{:symbol :AST
|
||||||
|
@ -283,7 +297,7 @@
|
||||||
:address "0x48f775efbe4f5ece6e0df2f7b5932df56823b990"
|
:address "0x48f775efbe4f5ece6e0df2f7b5932df56823b990"
|
||||||
:decimals 0}
|
:decimals 0}
|
||||||
{:symbol :1ST
|
{:symbol :1ST
|
||||||
:name "Firstblood"
|
:name "FirstBlood Token"
|
||||||
:address "0xaf30d2a7e90d7dc361c8c4585e9bb7d2f6f15bc7"
|
:address "0xaf30d2a7e90d7dc361c8c4585e9bb7d2f6f15bc7"
|
||||||
:decimals 18}
|
:decimals 18}
|
||||||
{:symbol :CFI
|
{:symbol :CFI
|
||||||
|
@ -343,7 +357,7 @@
|
||||||
:address "0xced4e93198734ddaff8492d525bd258d49eb388e"
|
:address "0xced4e93198734ddaff8492d525bd258d49eb388e"
|
||||||
:decimals 18}
|
:decimals 18}
|
||||||
{:symbol :CSNO
|
{:symbol :CSNO
|
||||||
:name "BitDice CSNO"
|
:name "BitDice"
|
||||||
:address "0x29d75277ac7f0335b2165d0895e8725cbf658d73"
|
:address "0x29d75277ac7f0335b2165d0895e8725cbf658d73"
|
||||||
:decimals 8}
|
:decimals 8}
|
||||||
{:symbol :COB
|
{:symbol :COB
|
||||||
|
@ -375,11 +389,11 @@
|
||||||
:address "0x4DF812F6064def1e5e029f1ca858777CC98D2D81"
|
:address "0x4DF812F6064def1e5e029f1ca858777CC98D2D81"
|
||||||
:decimals 8}
|
:decimals 8}
|
||||||
{:symbol :VIB
|
{:symbol :VIB
|
||||||
:name "VIB"
|
:name "Vibe"
|
||||||
:address "0x2c974b2d0ba1716e644c1fc59982a89ddd2ff724"
|
:address "0x2c974b2d0ba1716e644c1fc59982a89ddd2ff724"
|
||||||
:decimals 18}
|
:decimals 18}
|
||||||
{:symbol :PRG
|
{:symbol :PRG
|
||||||
:name "ParagonCoin"
|
:name "PRG"
|
||||||
:address "0x7728dFEF5aBd468669EB7f9b48A7f70a501eD29D"
|
:address "0x7728dFEF5aBd468669EB7f9b48A7f70a501eD29D"
|
||||||
:decimals 6}
|
:decimals 6}
|
||||||
{:symbol :DPY
|
{:symbol :DPY
|
||||||
|
@ -395,7 +409,7 @@
|
||||||
:address "0x08f5a9235b08173b7569f83645d2c7fb55e8ccd8"
|
:address "0x08f5a9235b08173b7569f83645d2c7fb55e8ccd8"
|
||||||
:decimals 8}
|
:decimals 8}
|
||||||
{:symbol :DRT
|
{:symbol :DRT
|
||||||
:name "Domraider"
|
:name "DomRaiderToken"
|
||||||
:address "0x9af4f26941677c706cfecf6d3379ff01bb85d5ab"
|
:address "0x9af4f26941677c706cfecf6d3379ff01bb85d5ab"
|
||||||
:decimals 8}
|
:decimals 8}
|
||||||
{:symbol :SPANK
|
{:symbol :SPANK
|
||||||
|
@ -418,13 +432,13 @@
|
||||||
:name "Simple Token"
|
:name "Simple Token"
|
||||||
:address "0x2c4e8f2d746113d0696ce89b35f0d8bf88e0aeca"
|
:address "0x2c4e8f2d746113d0696ce89b35f0d8bf88e0aeca"
|
||||||
:decimals 18}
|
:decimals 18}
|
||||||
;; NOTE(goranjovic) : the following three tokens are removed from the Manage Assets list
|
;; NOTE(goranjovic): the following three tokens are removed from the Manage Assets list
|
||||||
;; and automatically removed from user's selection by a migration. However, we still need
|
;; and automatically removed from user's selection by a migration. However, we still need
|
||||||
;; them listed here in order to correctly display any previous transactions the user had
|
;; them listed here in order to correctly display any previous transactions the user had
|
||||||
;; in their history prior to the upgrade. So, we're just hiding them, not actually deleting from the
|
;; in their history prior to the upgrade. So, we're just hiding them, not actually deleting from the
|
||||||
;; app.
|
;; app.
|
||||||
{:symbol :CTR
|
{:symbol :Centra
|
||||||
:name "Centra"
|
:name "Centra token"
|
||||||
:address "0x96A65609a7B84E8842732DEB08f56C3E21aC6f8a"
|
:address "0x96A65609a7B84E8842732DEB08f56C3E21aC6f8a"
|
||||||
:decimals 18
|
:decimals 18
|
||||||
:hidden? true}
|
:hidden? true}
|
||||||
|
@ -438,13 +452,14 @@
|
||||||
:address "0x9B11EFcAAA1890f6eE52C6bB7CF8153aC5d74139"
|
:address "0x9B11EFcAAA1890f6eE52C6bB7CF8153aC5d74139"
|
||||||
:decimals 8
|
:decimals 8
|
||||||
:hidden? true}
|
:hidden? true}
|
||||||
|
;; NOTE(goranjovic): the following tokens are collectibles
|
||||||
{:symbol :CK
|
{:symbol :CK
|
||||||
:nft? true
|
:nft? true
|
||||||
:name "CryptoKitties"
|
:name "CryptoKitties"
|
||||||
:address "0x06012c8cf97bead5deae237070f9587f8e7a266d"}
|
:address "0x06012c8cf97bead5deae237070f9587f8e7a266d"}
|
||||||
{:symbol :EMONA
|
{:symbol :EMONA
|
||||||
:nft? true
|
:nft? true
|
||||||
:name "Etheremon"
|
:name "EtheremonAsset"
|
||||||
:address "0xB2c0782ae4A299f7358758B2D15dA9bF29E1DD99"}
|
:address "0xB2c0782ae4A299f7358758B2D15dA9bF29E1DD99"}
|
||||||
{:symbol :STRK
|
{:symbol :STRK
|
||||||
:nft? true
|
:nft? true
|
||||||
|
@ -452,7 +467,7 @@
|
||||||
:address "0xdcaad9fd9a74144d226dbf94ce6162ca9f09ed7e"}
|
:address "0xdcaad9fd9a74144d226dbf94ce6162ca9f09ed7e"}
|
||||||
{:symbol :SUPR
|
{:symbol :SUPR
|
||||||
:nft? true
|
:nft? true
|
||||||
:name "SuperRare"
|
:name "SupeRare"
|
||||||
:address "0x41a322b28d0ff354040e2cbc676f0320d8c8850d"}
|
:address "0x41a322b28d0ff354040e2cbc676f0320d8c8850d"}
|
||||||
{:symbol :KDO
|
{:symbol :KDO
|
||||||
:nft? true
|
:nft? true
|
||||||
|
@ -469,7 +484,7 @@
|
||||||
:symbol :HND
|
:symbol :HND
|
||||||
:decimals 0
|
:decimals 0
|
||||||
:address "0xdee43a267e8726efd60c2e7d5b81552dcd4fa35c"}
|
:address "0xdee43a267e8726efd60c2e7d5b81552dcd4fa35c"}
|
||||||
{:name "Lucky XS Test"
|
{:name "Lucky Test Token"
|
||||||
:symbol :LXS
|
:symbol :LXS
|
||||||
:decimals 2
|
:decimals 2
|
||||||
:address "0x703d7dc0bc8e314d65436adf985dda51e09ad43b"}
|
:address "0x703d7dc0bc8e314d65436adf985dda51e09ad43b"}
|
||||||
|
@ -502,32 +517,28 @@
|
||||||
(defn tokens-for
|
(defn tokens-for
|
||||||
"makes sure all addresses are lower-case
|
"makes sure all addresses are lower-case
|
||||||
TODO: token list should be speced and not accept non-lower-cased addresses"
|
TODO: token list should be speced and not accept non-lower-cased addresses"
|
||||||
[chain]
|
[all-tokens chain]
|
||||||
(mapv #(update % :address string/lower-case) (get all chain)))
|
(mapv #(update % :address string/lower-case) (vals (get all-tokens chain))))
|
||||||
|
|
||||||
(defn all-assets-for [chain]
|
(defn nfts-for [all-tokens chain]
|
||||||
(concat [(native-currency chain)]
|
(filter :nft? (tokens-for all-tokens chain)))
|
||||||
(tokens-for chain)))
|
|
||||||
|
|
||||||
(defn nfts-for [chain]
|
(defn sorted-tokens-for [all-tokens chain]
|
||||||
(filter :nft? (tokens-for chain)))
|
(->> (tokens-for all-tokens chain)
|
||||||
|
|
||||||
(defn sorted-tokens-for [chain]
|
|
||||||
(->> (tokens-for chain)
|
|
||||||
(filter #(not (:hidden? %)))
|
(filter #(not (:hidden? %)))
|
||||||
(sort #(compare (string/lower-case (:name %1))
|
(sort #(compare (string/lower-case (:name %1))
|
||||||
(string/lower-case (:name %2))))))
|
(string/lower-case (:name %2))))))
|
||||||
|
|
||||||
(defn symbol->token [chain symbol]
|
(defn symbol->token [all-tokens chain symbol]
|
||||||
(some #(when (= symbol (:symbol %)) %) (tokens-for chain)))
|
(some #(when (= symbol (:symbol %)) %) (tokens-for all-tokens chain)))
|
||||||
|
|
||||||
(defn address->token [chain address]
|
(defn address->token [all-tokens chain address]
|
||||||
(some #(when (= (string/lower-case address)
|
(some #(when (= (string/lower-case address)
|
||||||
(string/lower-case (:address %))) %) (tokens-for chain)))
|
(string/lower-case (:address %))) %) (tokens-for all-tokens chain)))
|
||||||
|
|
||||||
(defn asset-for [chain symbol]
|
(defn asset-for [all-tokens chain symbol]
|
||||||
(let [native-coin (native-currency chain)]
|
(let [native-coin (native-currency chain)]
|
||||||
(if (or (= (:symbol-display native-coin) symbol)
|
(if (or (= (:symbol-display native-coin) symbol)
|
||||||
(= (:symbol native-coin) symbol))
|
(= (:symbol native-coin) symbol))
|
||||||
native-coin
|
native-coin
|
||||||
(symbol->token chain symbol))))
|
(symbol->token all-tokens chain symbol))))
|
||||||
|
|
|
@ -10,7 +10,11 @@
|
||||||
:current-chat-id "recipient"
|
:current-chat-id "recipient"
|
||||||
:contacts/contacts {"recipient" {:name "Recipient"
|
:contacts/contacts {"recipient" {:name "Recipient"
|
||||||
:address "0xAA"
|
:address "0xAA"
|
||||||
:public-key "0xBB"}}}})
|
:public-key "0xBB"}}
|
||||||
|
:wallet/all-tokens {:mainnet {"0x744d70fdbe2ba4cf95131626614a1763df805b9e" {:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
|
||||||
|
:name "Status Network Token"
|
||||||
|
:symbol :SNT
|
||||||
|
:decimals 18}}}}})
|
||||||
|
|
||||||
;; testing the `/send` command
|
;; testing the `/send` command
|
||||||
|
|
||||||
|
|
|
@ -29,16 +29,26 @@
|
||||||
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1 :function-name "transfer" :gas "100" :function-arguments {:address "0x8e23ee67d1332ad560396262c48ffbb01f93d052" :uint256 "1"}}
|
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1 :function-name "transfer" :gas "100" :function-arguments {:address "0x8e23ee67d1332ad560396262c48ffbb01f93d052" :uint256 "1"}}
|
||||||
(eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer?address=0x8e23ee67d1332ad560396262c48ffbb01f93d052&uint256=1&gas=100"))))
|
(eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer?address=0x8e23ee67d1332ad560396262c48ffbb01f93d052&uint256=1&gas=100"))))
|
||||||
|
|
||||||
|
(def all-tokens
|
||||||
|
{:mainnet {"0x744d70fdbe2ba4cf95131626614a1763df805b9e" {:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
|
||||||
|
:name "Status Network Token"
|
||||||
|
:symbol :SNT
|
||||||
|
:decimals 18}}
|
||||||
|
:testnet {"0xc55cF4B03948D7EBc8b9E8BAD92643703811d162" {:address "0xc55cF4B03948D7EBc8b9E8BAD92643703811d162"
|
||||||
|
:name "Status Test Token"
|
||||||
|
:symbol :STT
|
||||||
|
:decimals 18}}})
|
||||||
|
|
||||||
(deftest generate-erc20-uri
|
(deftest generate-erc20-uri
|
||||||
(is (= nil (eip681/generate-erc20-uri nil nil)))
|
(is (= nil (eip681/generate-erc20-uri nil nil all-tokens)))
|
||||||
(is (= "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
|
(is (= "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
|
||||||
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :SNT :value 5})))
|
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :SNT :value 5} all-tokens)))
|
||||||
(is (= "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7&gas=10000&gasPrice=10000"
|
(is (= "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7&gas=10000&gasPrice=10000"
|
||||||
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :SNT :value 5 :gas 10000 :gasPrice 10000})))
|
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :SNT :value 5 :gas 10000 :gasPrice 10000} all-tokens)))
|
||||||
(is (= "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
|
(is (= "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
|
||||||
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :SNT :chain-id 1 :value 5})))
|
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :SNT :chain-id 1 :value 5} all-tokens)))
|
||||||
(is (= "ethereum:0xc55cf4b03948d7ebc8b9e8bad92643703811d162@3/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
|
(is (= "ethereum:0xc55cf4b03948d7ebc8b9e8bad92643703811d162@3/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
|
||||||
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :STT :chain-id 3 :value 5}))))
|
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :STT :chain-id 3 :value 5} all-tokens))))
|
||||||
|
|
||||||
(deftest generate-uri
|
(deftest generate-uri
|
||||||
(is (= nil (eip681/generate-uri nil nil)))
|
(is (= nil (eip681/generate-uri nil nil)))
|
||||||
|
@ -73,13 +83,17 @@
|
||||||
(is (.equals (money/bignumber "111122223333441239") (eip681/parse-eth-value "111122223333441239"))))
|
(is (.equals (money/bignumber "111122223333441239") (eip681/parse-eth-value "111122223333441239"))))
|
||||||
|
|
||||||
(deftest extract-request-details
|
(deftest extract-request-details
|
||||||
(let [{:keys [value symbol address]} (eip681/extract-request-details {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1ETH"})]
|
(let [{:keys [value symbol address]} (eip681/extract-request-details {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1ETH"} {})]
|
||||||
(is (.equals (money/ether->wei (money/bignumber 1)) value))
|
(is (.equals (money/ether->wei (money/bignumber 1)) value))
|
||||||
(is (= :ETH symbol))
|
(is (= :ETH symbol))
|
||||||
(is (= "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" address)))
|
(is (= "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" address)))
|
||||||
(is (nil? (eip681/extract-request-details {:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e" :chain-id 1 :function-name "unknown"})))
|
(is (nil? (eip681/extract-request-details {:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e" :chain-id 1 :function-name "unknown"} {})))
|
||||||
(let [{:keys [value symbol address]} (eip681/extract-request-details {:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e" :chain-id 1
|
(let [{:keys [value symbol address]} (eip681/extract-request-details {:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e" :chain-id 1
|
||||||
:function-name "transfer" :function-arguments {:uint256 1000 :address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"}})]
|
:function-name "transfer" :function-arguments {:uint256 1000 :address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"}}
|
||||||
|
{:mainnet {"0x744d70fdbe2ba4cf95131626614a1763df805b9e" {:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
|
||||||
|
:name "Status Network Token"
|
||||||
|
:symbol :SNT
|
||||||
|
:decimals 18}}})]
|
||||||
(is (.equals (money/bignumber 1000) value))
|
(is (.equals (money/bignumber 1000) value))
|
||||||
(is (= :SNT symbol))
|
(is (= :SNT symbol))
|
||||||
(is (= "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" address))))
|
(is (= "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" address))))
|
||||||
|
|
|
@ -30,9 +30,9 @@
|
||||||
(is (= {:a 0} (u/update-if-present {:a 0} :b inc))))
|
(is (= {:a 0} (u/update-if-present {:a 0} :b inc))))
|
||||||
|
|
||||||
(deftest map-values-test
|
(deftest map-values-test
|
||||||
(is (= {} (u/map-values {} inc)))
|
(is (= {} (u/map-values inc {})))
|
||||||
(is (= {:a 1} (u/map-values {:a 0} inc)))
|
(is (= {:a 1} (u/map-values inc {:a 0})))
|
||||||
(is (= {:a 1 :b 2} (u/map-values {:a 0 :b 1} inc))))
|
(is (= {:a 1 :b 2} (u/map-values inc {:a 0 :b 1}))))
|
||||||
|
|
||||||
(deftest deep-merge-test
|
(deftest deep-merge-test
|
||||||
(is (= {} (u/deep-merge {} {})))
|
(is (= {} (u/deep-merge {} {})))
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
"validation-amount-invalid-number": "Amount is not a valid number",
|
"validation-amount-invalid-number": "Amount is not a valid number",
|
||||||
"transaction-details": "Transaction details",
|
"transaction-details": "Transaction details",
|
||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
|
"warning": "Warning",
|
||||||
"public-chat": "Public chat",
|
"public-chat": "Public chat",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
"devices": "Devices",
|
"devices": "Devices",
|
||||||
|
@ -350,6 +351,9 @@
|
||||||
"sharing-copy-to-clipboard": "Copy to clipboard",
|
"sharing-copy-to-clipboard": "Copy to clipboard",
|
||||||
"your-wallets": "Your wallets",
|
"your-wallets": "Your wallets",
|
||||||
"phone-international": "International 2",
|
"phone-international": "International 2",
|
||||||
|
"token-auto-validate-name-error": "Wrong name for token {{symbol}} at address {{address}} - set to {{expected}} but detected as {{actual}}",
|
||||||
|
"token-auto-validate-symbol-error": "Wrong symbol for token {{symbol}} at address {{address}} - set to {{expected}} but detected as {{actual}}",
|
||||||
|
"token-auto-validate-decimals-error": "Wrong decimals for token {{symbol}} at address {{address}} - set to {{expected}} but detected as {{actual}}",
|
||||||
"error-unable-to-get-token-balance": "Unable to get token balance",
|
"error-unable-to-get-token-balance": "Unable to get token balance",
|
||||||
"error-cant-send-transaction-offline": "Can't send transaction in offline mode",
|
"error-cant-send-transaction-offline": "Can't send transaction in offline mode",
|
||||||
"error-cant-sign-message-offline": "Can't sign message in offline mode",
|
"error-cant-sign-message-offline": "Can't sign message in offline mode",
|
||||||
|
|
Loading…
Reference in New Issue