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:
Goran Jovic 2018-11-01 17:54:58 +01:00
parent 58dc06267c
commit 72e7ae2fff
No known key found for this signature in database
GPG Key ID: D429D1A9B2EB8A8E
37 changed files with 409 additions and 171 deletions

1
.env
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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))))

View File

@ -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}])

View File

@ -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)))))

View File

@ -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)))

View File

@ -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)]

View File

@ -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?

View File

@ -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]

View File

@ -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)

View File

@ -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="

View File

@ -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

View File

@ -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

View File

@ -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"}}

View File

@ -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)])}

View File

@ -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

View File

@ -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

View File

@ -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 %)])

View File

@ -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

View File

@ -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]

View File

@ -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)}]]]))

View File

@ -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

View File

@ -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

View File

@ -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]]]))

View File

@ -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

View File

@ -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)))

View File

@ -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"

View File

@ -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

View File

@ -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))))

View File

@ -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

View File

@ -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))))

View File

@ -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 {} {})))

View File

@ -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",