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
PFS_ENCRYPTION_ENABLED=0
DEV_BUILD=1
ERC20_CONTRACT_WARNINGS=1

View File

@ -10,3 +10,4 @@ DEBUG_WEBVIEW=1
GROUP_CHATS_ENABLED=1
EXTENSIONS=1
PFS_ENCRYPTION_ENABLED=0
ERC20_CONTRACT_WARNINGS=1

View File

@ -14,3 +14,4 @@ CACHED_WEBVIEWS_ENABLED=1
EXTENSIONS=1
PFS_ENCRYPTION_ENABLED=0
PAIRING_ENABLED=1
ERC20_CONTRACT_WARNINGS=1

View File

@ -13,3 +13,4 @@ PAIRING_ENABLED=1
MAINNET_WARNING_ENABLED=1
EXTENSIONS=1
PFS_ENCRYPTION_ENABLED=0
ERC20_CONTRACT_WARNINGS=1

View File

@ -11,3 +11,4 @@ GROUP_CHATS_ENABLED=0
MAINNET_WARNING_ENABLED=1
EXTENSIONS=1
PFS_ENCRYPTION_ENABLED=0
ERC20_CONTRACT_WARNINGS=1

View File

@ -13,3 +13,4 @@ GROUP_CHATS_ENABLED=0
MAINNET_WARNING_ENABLED=1
EXTENSIONS=1
PFS_ENCRYPTION_ENABLED=0
ERC20_CONTRACT_WARNINGS=0

View File

@ -87,12 +87,10 @@
(defn personal-send-request-short-preview
[label-key {:keys [content]}]
(let [{:keys [amount asset network]} (:params content)
token (when (and network asset)
(tokens/asset-for (keyword network) (keyword asset)))]
(let [{:keys [amount coin]} (:params content)]
[chat-preview/text {}
(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
[{:id :asset
@ -146,15 +144,16 @@
;;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
;; if we were to update all balances.
(defn- allowed-assets [{:account/keys [account] :keys [chain]}]
(let [chain-keyword (keyword chain)
(defn- allowed-assets [{:account/keys [account] :keys [chain] :as db}]
(let [all-tokens (:wallet/all-tokens db)
chain-keyword (keyword chain)
{:keys [symbol symbol-display decimals]} (tokens/native-currency chain-keyword)
visible-tokens (get-in account [:settings :wallet :visible-tokens chain-keyword])]
(into {(name (or symbol-display symbol)) decimals}
(comp (filter #(and (not (:nft? %))
(contains? visible-tokens (:symbol %))))
(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]}]
(let [asset-decimals (get (allowed-assets db) asset)]
@ -210,11 +209,12 @@
(defview send-preview
[{: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
recipient-name (get-in content [:params :bot-db :public :recipient])
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
[react/view transactions-styles/command-send-amount-row
@ -258,6 +258,12 @@
(defn- inject-network-info [parameters {:keys [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]}]
(let [currency (-> db
currency-settings.subs/get-currency
@ -305,7 +311,8 @@
sender-account (:account/account db)
chain (keyword (:chain db))
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)
next-view-id (if (:wallet-set-up-passed? sender-account)
:wallet-send-transaction-modal
@ -330,10 +337,14 @@
(navigation/navigate-to-cofx next-view-id {}))))
protocol/EnhancedParameters
(enhance-send-parameters [_ parameters cofx]
(-> (inject-network-info parameters cofx)
(-> parameters
(inject-network-info cofx)
(inject-coin-info cofx)
(inject-price-info cofx)))
(enhance-receive-parameters [_ parameters cofx]
(inject-price-info parameters cofx)))
(-> parameters
(inject-coin-info cofx)
(inject-price-info cofx))))
;; `/request` command
@ -465,7 +476,11 @@
(request-preview command-message))
protocol/EnhancedParameters
(enhance-send-parameters [_ parameters cofx]
(-> (inject-network-info parameters cofx)
(-> parameters
(inject-network-info cofx)
(inject-coin-info cofx)
(inject-price-info 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
account/v15])
(def v17 v16)
;; put schemas ordered by version
(def schemas [{:schema v1
:schemaVersion 1
@ -112,4 +114,7 @@
:migration migrations/v15}
{:schema v16
: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]
(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]
(fx/merge cofx
(models.wallet/initialize-tokens)
(models.wallet/update-wallet)
(transactions/start-sync)))

View File

@ -360,11 +360,11 @@
(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
{:account-address account-address
: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
:success-fn (fn [transactions]
#_(log/debug "Transactions received: " (pr-str (keys transactions)))
@ -380,7 +380,7 @@
(log/debug "Unable to get transactions: " http-error)
(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
(let [chain (ethereum/network->chain-keyword (get-in account [:networks network]))
account-address (:address account)]
@ -389,11 +389,11 @@
(not= :custom chain))
(async-periodic-run!
@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
(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]))]
(assert (and web3 account-address network network-status account app-state wallet chats)
"Must have all necessary data to run background transaction sync")
@ -407,7 +407,7 @@
(if-not (or (have-unconfirmed-transactions? (vals transaction-map))
(not-empty (set/difference chat-transaction-ids transaction-ids)))
(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}]
(let [account-address (:address account)]

View File

@ -7,9 +7,11 @@
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.ethereum.tokens :as tokens]
[status-im.utils.hex :as utils.hex]
[status-im.utils.core :as utils.core]
[status-im.utils.money :as money]
[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))
@ -144,9 +146,10 @@
{:dispatch (conj on-error "transaction was cancelled by user")}))))
(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)
token (tokens/symbol->token (keyword chain) (:symbol transaction))]
token (tokens/symbol->token all-tokens (keyword chain) (:symbol transaction))]
(-> transaction
(assoc :confirmations "0"
:timestamp (str now)
@ -183,16 +186,29 @@
(defn clear-error-message [db error-type]
(update-in db [:wallet :errors] dissoc error-type))
(defn tokens-symbols [v chain]
(set/difference (set v) (set (map :symbol (tokens/nfts-for chain)))))
(defn tokens-symbols [visible-token-symbols all-tokens chain]
(set/difference (set visible-token-symbols) (set (map :symbol (tokens/nfts-for all-tokens chain)))))
(fx/defn initialize-tokens
[{:keys [db]}]
(let [network-id (get-in db [:account/account :network])
network (get-in db [:account/account :networks network-id])
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
[{{: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)
mainnet? (= :mainnet 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 (get constants/currencies currency-id)]
(when (not= network-status :offline)
@ -204,6 +220,7 @@
:account-id address
:symbols assets
:chain chain
:all-tokens all-tokens
:success-event :update-token-balance-success
:error-event :update-token-balance-fail}
:get-prices {:from (if mainnet?

View File

@ -37,6 +37,7 @@
:app-state "active"
:wallet.transactions constants/default-wallet-transactions
:wallet-selected-asset {}
:wallet/all-tokens {}
:prices {}
:peers-count 0
:peers-summary []
@ -243,6 +244,7 @@
:desktop/desktop
:dimensions/window
:dapps/permissions
:wallet/all-tokens
:ui/contact
:ui/search
:ui/chat]

View File

@ -39,9 +39,9 @@
(defn- extract-details
"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"
[s chain-id]
[s chain-id all-tokens]
(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)
{:address s :chain-id chain-id})))
@ -87,9 +87,9 @@
(handlers/register-handler-fx
: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])
{: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))
previous-state (get-in db [:wallet :send-transaction])
old-symbol (:symbol previous-state)

View File

@ -18,7 +18,7 @@
ids)}))
;; 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="
items-number
"&owner_wallet_address="

View File

@ -12,19 +12,20 @@
(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]
{:load-collectibles-fx [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 all-tokens symbol items-number address chain-id]})
(handlers/register-handler-fx
:show-collectibles-list
(fn [{:keys [db]} [_ address {:keys [symbol amount] :as collectible}]]
(let [chain-id (get-in constants/default-networks [(:network db) :config :NetworkId])
all-tokens (:wallet/all-tokens db)
items-number (money/to-number amount)
loaded-items-number (count (get-in db [:collectibles symbol]))]
(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]}))))
(defn load-token [web3 i items-number contract address symbol]
@ -36,9 +37,9 @@
(re-frame/reg-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)
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))))
(handlers/register-handler-fx

View File

@ -12,14 +12,15 @@
(def kudos :KDO)
(defmethod collectibles/load-collectible-fx kudos [{db :db} symbol id]
(let [chain-id (get-in constants/default-networks [(:network db) :config :NetworkId])]
{:erc721-token-uri [(:web3 db) symbol id chain-id]}))
(let [chain-id (get-in constants/default-networks [(:network db) :config :NetworkId])
all-tokens (:wallet/all-tokens db)]
{:erc721-token-uri [(:web3 db) all-tokens symbol id chain-id]}))
(re-frame/reg-fx
: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)
contract (:address (tokens/symbol->token chain symbol))]
contract (:address (tokens/symbol->token all-tokens chain symbol))]
(erc721/token-uri web3 contract tokenId
#(re-frame/dispatch [:token-uri-success
tokenId

View File

@ -29,7 +29,7 @@
imageUri
}}}}"))
(defmethod collectibles/load-collectibles-fx superrare [_ _ _ address _]
(defmethod collectibles/load-collectibles-fx superrare [_ _ _ _ address _]
{:http-post {:url graphql-url
:data (types/clj->json {:query (graphql-query (ethereum/naked-address address))})
:opts {:headers {"Content-Type" "application/json"}}

View File

@ -154,8 +154,9 @@
(views/defview asset-selector [{:keys [disabled? type symbol error]}]
(views/letsubs [balance [:balance]
network [:network]]
(let [{:keys [name icon decimals] :as token} (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
network [:network]
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
[react/view
[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.prices :as prices]
[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]}]
(if (and web3 account-id)
@ -51,9 +53,9 @@
(re-frame/reg-fx
: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]
(let [contract (:address (tokens/symbol->token chain symbol))]
(let [contract (:address (tokens/symbol->token all-tokens chain symbol))]
(get-token-balance {:web3 web3
:contract contract
:account-id account-id
@ -80,6 +82,51 @@
(fn [{:keys [web3 obj success-event]}]
(ethereum/estimate-gas-web3 web3 (clj->js obj) #(re-frame/dispatch [success-event %2]))))
(defn- validate-token-name! [web3 {:keys [address symbol name]}]
(erc20/name web3 address #(when (and (seq %2) ;;NOTE(goranjovic): skipping check if field not set in contract
(not= name %2))
(let [message (i18n/label :t/token-auto-validate-name-error
{:symbol symbol
:expected name
:actual %2
:address address})]
(log/warn message)
(utils.utils/show-popup (i18n/label :t/warning) message)))))
(defn- validate-token-symbol! [web3 {:keys [address symbol]}]
(erc20/symbol web3 address #(when (and (seq %2) ;;NOTE(goranjovic): skipping check if field not set in contract
(not= (clojure.core/name symbol) %2))
(let [message (i18n/label :t/token-auto-validate-symbol-error
{:symbol symbol
:expected (clojure.core/name symbol)
:actual %2
:address address})]
(log/warn message)
(utils.utils/show-popup (i18n/label :t/warning) message)))))
(defn- validate-token-decimals! [web3 {:keys [address symbol decimals nft? skip-decimals-check?]}]
;;NOTE(goranjovic): only skipping check if skip-decimals-check? flag is present because we can't differentiate
;;between unset decimals and 0 decimals.
(when-not skip-decimals-check?
(erc20/decimals web3 address #(when (and %2
(not nft?)
(not= decimals (int %2)))
(let [message (i18n/label :t/token-auto-validate-decimals-error
{:symbol symbol
:expected decimals
:actual %2
:address address})]
(log/warn message)
(utils.utils/show-popup (i18n/label :t/warning) message))))))
(re-frame/reg-fx
:wallet/validate-tokens
(fn [{:keys [web3 tokens]}]
(doseq [token tokens]
(validate-token-decimals! web3 token)
(validate-token-symbol! web3 token)
(validate-token-name! web3 token))))
;; Handlers
(handlers/register-handler-fx
:update-wallet

View File

@ -31,8 +31,9 @@
{:keys [to to-name public-key]} [:wallet.send/transaction]
{:keys [amount amount-error amount-text symbol]} [:wallet.request/transaction]
network-status [:network-status]
all-tokens [:wallet/all-tokens]
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/toolbar (i18n/label :t/new-request)]
[react/view components.styles/flex

View File

@ -27,16 +27,16 @@
(security/safe-unmask-data masked-password)
on-completed))
(defn- send-tokens [symbol chain {:keys [from to value gas gasPrice]} on-completed masked-password]
(let [contract (:address (tokens/symbol->token (keyword chain) symbol))]
(defn- send-tokens [all-tokens symbol chain {:keys [from to value gas gasPrice]} on-completed masked-password]
(let [contract (:address (tokens/symbol->token all-tokens (keyword chain) symbol))]
(erc20/transfer contract from to value gas gasPrice masked-password on-completed)))
(re-frame/reg-fx
::send-transaction
(fn [[params symbol chain on-completed masked-password]]
(fn [[params all-tokens symbol chain on-completed masked-password]]
(case symbol
: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
::sign-message
@ -57,12 +57,14 @@
:wallet/send-transaction
(fn [{{:keys [chain] :as db} :db} _]
(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])]
(when-not in-progress?
{:db (-> db
(assoc-in [:wallet :send-transaction :wrong-password?] false)
(assoc-in [:wallet :send-transaction :in-progress?] true))
::send-transaction [(models.wallet/prepare-send-transaction from transaction)
all-tokens
symbol
chain
#(re-frame/dispatch [::transaction-completed (types/json->clj %)])

View File

@ -138,12 +138,12 @@
(i18n/label :t/transactions-sign-transaction)
[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?
sufficient-gas? in-progress? from-chat? symbol]} transaction
chain (ethereum/network->chain-keyword network)
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)]
[wallet.components/simple-screen {:avoid-keyboard? (not modal?)
:status-bar-type (if modal? :modal-wallet :wallet)}
@ -206,12 +206,14 @@
advanced? [:wallet.send/advanced?]
network [:account/network]
scroll (atom nil)
network-status [:network-status]]
network-status [:network-status]
all-tokens [:wallet/all-tokens]]
[send-transaction-view {:modal? false
:transaction transaction
:scroll scroll
:advanced? advanced?
:network network
:all-tokens all-tokens
:network-status network-status}]))
;; SEND TRANSACTION FROM DAPP
@ -220,13 +222,15 @@
advanced? [:wallet.send/advanced?]
network [:account/network]
scroll (atom nil)
network-status [:network-status]]
network-status [:network-status]
all-tokens [:wallet/all-tokens]]
(if transaction
[send-transaction-view {:modal? true
:transaction transaction
:scroll scroll
:advanced? advanced?
:network network
:all-tokens all-tokens
:network-status network-status}]
[react/view wallet.styles/wallet-modal-container
[react/view components.styles/flex

View File

@ -25,10 +25,10 @@
(wallet.events/update-token-balance-success symbol balance)))
(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))
chain (ethereum/network->chain-keyword network)
contracts (->> (tokens/tokens-for chain)
contracts (->> (tokens/tokens-for all-tokens chain)
(remove :hidden?))]
(when-not (= network-status :offline)
(doseq [{:keys [address symbol]} contracts]

View File

@ -23,7 +23,8 @@
(defview manage-assets []
(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})
[status-bar/status-bar {:type :modal-wallet}]
[toolbar/toolbar {:style wallet.styles/toolbar}
@ -35,6 +36,6 @@
[toolbar/content-title {:color :white}
(i18n/label :t/wallet-assets)]]
[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)
:render-fn #(render-token % visible-tokens)}]]]))

View File

@ -50,14 +50,18 @@
.toNumber))
acc)) 0 balance))
(re-frame/reg-sub :wallet/all-tokens
(fn [db] (:wallet/all-tokens db)))
(re-frame/reg-sub :portfolio-value
:<- [:balance]
:<- [:prices]
:<- [:wallet/currency]
:<- [:network]
(fn [[balance prices currency network] [_ currency-code]]
:<- [:wallet/all-tokens]
(fn [[balance prices currency network all-tokens] [_ currency-code]]
(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))
balance-total-value
(get-balance-total-value balance
@ -102,10 +106,11 @@
(re-frame/reg-sub :wallet/visible-assets
:<- [:network]
:<- [: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)]
(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)))))
(re-frame/reg-sub :wallet/visible-assets-with-amount

View File

@ -27,13 +27,14 @@
network [:account/network]
{gas-edit :gas
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
gas (:value gas-edit)
gas-price (:value gas-price-edit)
chain (ethereum/network->chain-keyword network)
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}
[toolbar (i18n/label :t/wallet-transaction-fee)]
[react/view components.styles/flex

View File

@ -50,13 +50,14 @@
(:postponed :pending) (transaction-icon :icons/arrow-right colors/gray-light colors/gray)
(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
contact-accessibility-label
address-accessibility-label] (if (inbound? type)
[(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])
{: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]))
[react/view {:accessibility-label :transaction-item}
[list/item
@ -101,11 +102,12 @@
(defview history-list [& [hide-details?]]
(letsubs [transactions-history-list [:wallet.transactions/transactions-history-list]
filter-data [:wallet.transactions/filters]
network [:account/network]]
network [:account/network]
all-tokens [:wallet/all-tokens]]
[react/view components.styles/flex
[list/section-list {:sections (map #(update-transactions % filter-data) transactions-history-list)
: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
:key :transactions-history-empty}]
:on-refresh #(re-frame/dispatch [:update-transactions])
@ -163,8 +165,8 @@
(-> amount (money/token->unit (:decimals token)) money/to-fixed str))
"..."))
(defn details-header [network {:keys [value date type symbol token]}]
(let [asset (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
(defn details-header [network all-tokens {:keys [value date type symbol token]}]
(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-icon}
[list/item-icon (transaction-type->icon type)]]
@ -245,7 +247,8 @@
(letsubs [{:keys [hash url type] :as transaction} [:wallet.transactions/transaction-details]
confirmations [:wallet.transactions.details/confirmations]
confirmations-progress [:wallet.transactions.details/confirmations-progress]
network [:account/network]]
network [:account/network]
all-tokens [:wallet/all-tokens]]
[react/view {:style components.styles/flex}
[status-bar/status-bar]
[toolbar/toolbar {}
@ -253,7 +256,7 @@
[toolbar/content-title (i18n/label :t/transaction-details)]
(when transaction [toolbar/actions (details-action hash url)])]
[react/scroll-view {:style components.styles/main-container}
[details-header network transaction]
[details-header network all-tokens transaction]
[details-confirmations confirmations confirmations-progress type]
[react/view {:style styles/details-separator}]
[details-list transaction]]]))

View File

@ -31,6 +31,7 @@
(def extensions-enabled? (enabled? (get-config :EXTENSIONS 0)))
(def hardwallet-enabled? (enabled? (get-config :HARDWALLET_ENABLED 0)))
(def dev-build? (enabled? (get-config :DEV_BUILD 0)))
(def erc20-contract-warnings-enabled? (enabled? (get-config :ERC20_CONTRACT_WARNINGS)))
;; CONFIG VALUES
(def log-level

View File

@ -45,7 +45,7 @@
(defn map-values
"Efficiently apply function to all map values"
[m f]
[f m]
(into {}
(map (fn [[k v]]
[k (f v)]))
@ -57,3 +57,9 @@
(if (every? map? maps)
(apply merge-with deep-merge 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" ""))]
(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.
Supports ethereum and erc20 token."
(when address
@ -76,7 +76,7 @@
:address address}
"transfer"
{: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)}
nil)))
@ -104,8 +104,8 @@
(defn generate-erc20-uri
"Generate a EIP 681 URI encapsulating ERC20 token transfer"
[address {:keys [symbol value chain-id] :as m}]
(when-let [token (tokens/symbol->token (if chain-id (ethereum/chain-id->chain-keyword chain-id) :mainnet) symbol)]
[address {:keys [symbol value chain-id] :as m} all-tokens]
(when-let [token (tokens/symbol->token all-tokens (if chain-id (ethereum/chain-id->chain-keyword chain-id) :mainnet) symbol)]
(generate-uri (:address token)
(merge (dissoc m :value :symbol)
{:function-name "transfer"

View File

@ -18,27 +18,99 @@
(:require [status-im.utils.ethereum.core :as ethereum]
[status-im.native-module.core :as status]
[status-im.utils.security :as security]
[status-im.js-dependencies :as dependencies]
[status-im.utils.types :as types])
(: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]
(ethereum/call web3 (ethereum/call-params contract "name()") cb))
(.name (get-instance 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]
(ethereum/call web3 (ethereum/call-params contract "decimals()") cb))
(.decimals (get-instance web3 contract) cb))
(defn total-supply [web3 contract cb]
(ethereum/call web3
(ethereum/call-params contract "totalSupply()")
#(cb %1 (ethereum/hex->bignumber %2))))
(.totalSupply (get-instance web3 contract) cb))
(defn balance-of [web3 contract address cb]
(ethereum/call web3
(ethereum/call-params contract "balanceOf(address)" (ethereum/normalized-address address))
#(cb %1 (ethereum/hex->bignumber %2))))
(.balanceOf (get-instance web3 contract) address cb))
(defn transfer [contract from to value gas gas-price masked-password on-completed]
(status/send-transaction (types/clj->json

View File

@ -45,9 +45,21 @@
(defn ethereum? [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
(resolve-icons :mainnet
[{:symbol :DAI
@ -83,9 +95,9 @@
:address "0xB97048628DB6B661D4C2aA833e95Dbe1A905B280"
:decimals 18}
{:symbol :VRS
:name "VEROS"
:address "0xedbaf3c5100302dcdda53269322f3730b1f0416d"
:decimals 5}
:name "Veros"
:address "0x92E78dAe1315067a8819EFD6dCA432de9DCdE2e9"
:decimals 6}
{:symbol :GNT
:name "Golem Network Token"
:address "0xa74476443119A942dE498590Fe1f2454d7D4aC0d"
@ -109,7 +121,8 @@
{:symbol :DGD
:name "Digix DAO"
:address "0xe0b7927c4af23765cb51314a0e0521a9645f0e2a"
:decimals 9}
:decimals 9
:skip-decimals-check? true}
{:symbol :AE
:name "Aeternity"
:address "0x5ca9a71b1d01849c0a95490cc00559717fcf0d1d"
@ -118,8 +131,8 @@
:name "Tronix"
:address "0xf230b790e05390fc8295f4d3f60332c93bed42e2"
:decimals 6}
{:symbol :BQX
:name "Bitquence"
{:symbol :ETHOS
:name "Ethos"
:address "0x5af2be193a6abca9c8817001f45744777db30756"
:decimals 8}
{:symbol :RDN
@ -127,7 +140,7 @@
:address "0x255aa6df07540cb5d3d297f0d0d4d84cb52bc8e6"
:decimals 18}
{:symbol :SNT
:name "Status Network"
:name "Status Network Token"
:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
:decimals 18}
{:symbol :SNGLS
@ -205,13 +218,14 @@
{:symbol :LRC
:name "loopring"
:address "0xEF68e7C694F40c8202821eDF525dE3782458639f"
:decimals 18}
:decimals 18
:skip-decimals-check? true}
{:symbol :ZSC
:name "Zeus Shield Coin"
:address "0x7A41e0517a5ecA4FdbC7FbebA4D4c47B9fF6DC63"
:decimals 18}
{:symbol :DATA
:name "DATAcoin"
:name "Streamr DATAcoin"
:address "0x0cf0ee63788a0849fe5297f3407f701e122cc023"
:decimals 18}
{:symbol :RCN
@ -271,7 +285,7 @@
:address "0x12480e24eb5bec1a9d4369cab6a80cad3c0a377a"
:decimals 2}
{:symbol :MANA
:name "Decentraland"
:name "Decentraland MANA"
:address "0x0f5d2fb29fb7d3cfee444a200298f468908cc942"
:decimals 18}
{:symbol :AST
@ -283,7 +297,7 @@
:address "0x48f775efbe4f5ece6e0df2f7b5932df56823b990"
:decimals 0}
{:symbol :1ST
:name "Firstblood"
:name "FirstBlood Token"
:address "0xaf30d2a7e90d7dc361c8c4585e9bb7d2f6f15bc7"
:decimals 18}
{:symbol :CFI
@ -343,7 +357,7 @@
:address "0xced4e93198734ddaff8492d525bd258d49eb388e"
:decimals 18}
{:symbol :CSNO
:name "BitDice CSNO"
:name "BitDice"
:address "0x29d75277ac7f0335b2165d0895e8725cbf658d73"
:decimals 8}
{:symbol :COB
@ -375,11 +389,11 @@
:address "0x4DF812F6064def1e5e029f1ca858777CC98D2D81"
:decimals 8}
{:symbol :VIB
:name "VIB"
:name "Vibe"
:address "0x2c974b2d0ba1716e644c1fc59982a89ddd2ff724"
:decimals 18}
{:symbol :PRG
:name "ParagonCoin"
:name "PRG"
:address "0x7728dFEF5aBd468669EB7f9b48A7f70a501eD29D"
:decimals 6}
{:symbol :DPY
@ -395,7 +409,7 @@
:address "0x08f5a9235b08173b7569f83645d2c7fb55e8ccd8"
:decimals 8}
{:symbol :DRT
:name "Domraider"
:name "DomRaiderToken"
:address "0x9af4f26941677c706cfecf6d3379ff01bb85d5ab"
:decimals 8}
{:symbol :SPANK
@ -423,8 +437,8 @@
;; 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
;; app.
{:symbol :CTR
:name "Centra"
{:symbol :Centra
:name "Centra token"
:address "0x96A65609a7B84E8842732DEB08f56C3E21aC6f8a"
:decimals 18
:hidden? true}
@ -438,13 +452,14 @@
:address "0x9B11EFcAAA1890f6eE52C6bB7CF8153aC5d74139"
:decimals 8
:hidden? true}
;; NOTE(goranjovic): the following tokens are collectibles
{:symbol :CK
:nft? true
:name "CryptoKitties"
:address "0x06012c8cf97bead5deae237070f9587f8e7a266d"}
{:symbol :EMONA
:nft? true
:name "Etheremon"
:name "EtheremonAsset"
:address "0xB2c0782ae4A299f7358758B2D15dA9bF29E1DD99"}
{:symbol :STRK
:nft? true
@ -452,7 +467,7 @@
:address "0xdcaad9fd9a74144d226dbf94ce6162ca9f09ed7e"}
{:symbol :SUPR
:nft? true
:name "SuperRare"
:name "SupeRare"
:address "0x41a322b28d0ff354040e2cbc676f0320d8c8850d"}
{:symbol :KDO
:nft? true
@ -469,7 +484,7 @@
:symbol :HND
:decimals 0
:address "0xdee43a267e8726efd60c2e7d5b81552dcd4fa35c"}
{:name "Lucky XS Test"
{:name "Lucky Test Token"
:symbol :LXS
:decimals 2
:address "0x703d7dc0bc8e314d65436adf985dda51e09ad43b"}
@ -502,32 +517,28 @@
(defn tokens-for
"makes sure all addresses are lower-case
TODO: token list should be speced and not accept non-lower-cased addresses"
[chain]
(mapv #(update % :address string/lower-case) (get all chain)))
[all-tokens chain]
(mapv #(update % :address string/lower-case) (vals (get all-tokens chain))))
(defn all-assets-for [chain]
(concat [(native-currency chain)]
(tokens-for chain)))
(defn nfts-for [all-tokens chain]
(filter :nft? (tokens-for all-tokens chain)))
(defn nfts-for [chain]
(filter :nft? (tokens-for chain)))
(defn sorted-tokens-for [chain]
(->> (tokens-for chain)
(defn sorted-tokens-for [all-tokens chain]
(->> (tokens-for all-tokens chain)
(filter #(not (:hidden? %)))
(sort #(compare (string/lower-case (:name %1))
(string/lower-case (:name %2))))))
(defn symbol->token [chain symbol]
(some #(when (= symbol (:symbol %)) %) (tokens-for chain)))
(defn symbol->token [all-tokens chain symbol]
(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)
(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)]
(if (or (= (:symbol-display native-coin) symbol)
(= (:symbol native-coin) symbol))
native-coin
(symbol->token chain symbol))))
(symbol->token all-tokens chain symbol))))

View File

@ -10,7 +10,11 @@
:current-chat-id "recipient"
:contacts/contacts {"recipient" {:name "Recipient"
: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

View File

@ -29,16 +29,26 @@
(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"))))
(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
(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"
(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"
(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"
(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"
(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
(is (= nil (eip681/generate-uri nil nil)))
@ -73,13 +83,17 @@
(is (.equals (money/bignumber "111122223333441239") (eip681/parse-eth-value "111122223333441239"))))
(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 (= :ETH symbol))
(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
: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 (= :SNT symbol))
(is (= "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" address))))

View File

@ -30,9 +30,9 @@
(is (= {:a 0} (u/update-if-present {:a 0} :b inc))))
(deftest map-values-test
(is (= {} (u/map-values {} inc)))
(is (= {:a 1} (u/map-values {:a 0} inc)))
(is (= {:a 1 :b 2} (u/map-values {:a 0 :b 1} inc))))
(is (= {} (u/map-values inc {})))
(is (= {:a 1} (u/map-values inc {:a 0})))
(is (= {:a 1 :b 2} (u/map-values inc {:a 0 :b 1}))))
(deftest deep-merge-test
(is (= {} (u/deep-merge {} {})))

View File

@ -2,6 +2,7 @@
"validation-amount-invalid-number": "Amount is not a valid number",
"transaction-details": "Transaction details",
"confirm": "Confirm",
"warning": "Warning",
"public-chat": "Public chat",
"description": "Description",
"devices": "Devices",
@ -350,6 +351,9 @@
"sharing-copy-to-clipboard": "Copy to clipboard",
"your-wallets": "Your wallets",
"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-cant-send-transaction-offline": "Can't send transaction in offline mode",
"error-cant-sign-message-offline": "Can't sign message in offline mode",