feature #6509 - validating token config against their contracts; moved token info from compile time list to app-db; fixed any discrepancies in existing info
Signed-off-by: Goran Jovic <goranjovic@gmail.com>
This commit is contained in:
parent
58dc06267c
commit
72e7ae2fff
1
.env
1
.env
|
@ -15,3 +15,4 @@ EXTENSIONS=1
|
|||
HARDWALLET_ENABLED=0
|
||||
PFS_ENCRYPTION_ENABLED=0
|
||||
DEV_BUILD=1
|
||||
ERC20_CONTRACT_WARNINGS=1
|
||||
|
|
1
.env.e2e
1
.env.e2e
|
@ -10,3 +10,4 @@ DEBUG_WEBVIEW=1
|
|||
GROUP_CHATS_ENABLED=1
|
||||
EXTENSIONS=1
|
||||
PFS_ENCRYPTION_ENABLED=0
|
||||
ERC20_CONTRACT_WARNINGS=1
|
||||
|
|
|
@ -14,3 +14,4 @@ CACHED_WEBVIEWS_ENABLED=1
|
|||
EXTENSIONS=1
|
||||
PFS_ENCRYPTION_ENABLED=0
|
||||
PAIRING_ENABLED=1
|
||||
ERC20_CONTRACT_WARNINGS=1
|
||||
|
|
|
@ -13,3 +13,4 @@ PAIRING_ENABLED=1
|
|||
MAINNET_WARNING_ENABLED=1
|
||||
EXTENSIONS=1
|
||||
PFS_ENCRYPTION_ENABLED=0
|
||||
ERC20_CONTRACT_WARNINGS=1
|
||||
|
|
|
@ -11,3 +11,4 @@ GROUP_CHATS_ENABLED=0
|
|||
MAINNET_WARNING_ENABLED=1
|
||||
EXTENSIONS=1
|
||||
PFS_ENCRYPTION_ENABLED=0
|
||||
ERC20_CONTRACT_WARNINGS=1
|
||||
|
|
|
@ -13,3 +13,4 @@ GROUP_CHATS_ENABLED=0
|
|||
MAINNET_WARNING_ENABLED=1
|
||||
EXTENSIONS=1
|
||||
PFS_ENCRYPTION_ENABLED=0
|
||||
ERC20_CONTRACT_WARNINGS=0
|
||||
|
|
|
@ -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))))
|
||||
|
|
|
@ -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}])
|
||||
|
|
|
@ -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)))))
|
||||
|
|
|
@ -180,6 +180,7 @@
|
|||
|
||||
(defn initialize-wallet [cofx]
|
||||
(fx/merge cofx
|
||||
(models.wallet/initialize-tokens)
|
||||
(models.wallet/update-wallet)
|
||||
(transactions/start-sync)))
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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="
|
||||
|
|
|
@ -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])
|
||||
(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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"}}
|
||||
|
|
|
@ -153,9 +153,10 @@
|
|||
(throw (str "Unknown type: " k))))
|
||||
|
||||
(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)]
|
||||
(views/letsubs [balance [:balance]
|
||||
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)])}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -30,9 +30,10 @@
|
|||
(views/letsubs [network [:account/network]
|
||||
{:keys [to to-name public-key]} [:wallet.send/transaction]
|
||||
{:keys [amount amount-error amount-text symbol]} [:wallet.request/transaction]
|
||||
network-status [:network-status]
|
||||
scroll (atom nil)]
|
||||
(let [{:keys [decimals] :as token} (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
|
||||
network-status [:network-status]
|
||||
all-tokens [:wallet/all-tokens]
|
||||
scroll (atom nil)]
|
||||
(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
|
||||
|
|
|
@ -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])
|
||||
from (get-in db [:account/account :address])]
|
||||
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 %)])
|
||||
|
|
|
@ -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)}
|
||||
|
@ -202,31 +202,35 @@
|
|||
|
||||
;; SEND TRANSACTION FROM WALLET (CHAT)
|
||||
(defview send-transaction []
|
||||
(letsubs [transaction [:wallet.send/transaction]
|
||||
advanced? [:wallet.send/advanced?]
|
||||
network [:account/network]
|
||||
scroll (atom nil)
|
||||
network-status [:network-status]]
|
||||
[send-transaction-view {:modal? false
|
||||
:transaction transaction
|
||||
:scroll scroll
|
||||
:advanced? advanced?
|
||||
:network network
|
||||
(letsubs [transaction [:wallet.send/transaction]
|
||||
advanced? [:wallet.send/advanced?]
|
||||
network [:account/network]
|
||||
scroll (atom nil)
|
||||
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
|
||||
(defview send-transaction-modal []
|
||||
(letsubs [transaction [:wallet.send/transaction]
|
||||
advanced? [:wallet.send/advanced?]
|
||||
network [:account/network]
|
||||
scroll (atom nil)
|
||||
network-status [:network-status]]
|
||||
(letsubs [transaction [:wallet.send/transaction]
|
||||
advanced? [:wallet.send/advanced?]
|
||||
network [:account/network]
|
||||
scroll (atom nil)
|
||||
network-status [:network-status]
|
||||
all-tokens [:wallet/all-tokens]]
|
||||
(if transaction
|
||||
[send-transaction-view {:modal? true
|
||||
:transaction transaction
|
||||
:scroll scroll
|
||||
:advanced? advanced?
|
||||
:network network
|
||||
[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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)}]]]))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]]]))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
@ -106,10 +118,11 @@
|
|||
:name "Kyber Network Crystal"
|
||||
:address "0xdd974d5c2e2928dea5f71b9825b8b646686bd200"
|
||||
:decimals 18}
|
||||
{:symbol :DGD
|
||||
:name "Digix DAO"
|
||||
:address "0xe0b7927c4af23765cb51314a0e0521a9645f0e2a"
|
||||
:decimals 9}
|
||||
{:symbol :DGD
|
||||
:name "Digix DAO"
|
||||
:address "0xe0b7927c4af23765cb51314a0e0521a9645f0e2a"
|
||||
: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
|
||||
|
@ -202,16 +215,17 @@
|
|||
:name "Monaco"
|
||||
:address "0xb63b606ac810a52cca15e44bb630fd42d8d1d83d"
|
||||
:decimals 8}
|
||||
{:symbol :LRC
|
||||
:name "loopring"
|
||||
:address "0xEF68e7C694F40c8202821eDF525dE3782458639f"
|
||||
:decimals 18}
|
||||
{:symbol :LRC
|
||||
:name "loopring"
|
||||
:address "0xEF68e7C694F40c8202821eDF525dE3782458639f"
|
||||
: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
|
||||
|
@ -418,13 +432,13 @@
|
|||
:name "Simple Token"
|
||||
:address "0x2c4e8f2d746113d0696ce89b35f0d8bf88e0aeca"
|
||||
: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
|
||||
;; 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"}
|
||||
|
@ -497,37 +512,33 @@
|
|||
:name "KudosToken"
|
||||
:address "0x93bb0afbd0627bbd3a6c72bc318341d3a22e254a"}])
|
||||
|
||||
:custom []})
|
||||
:custom []})
|
||||
|
||||
(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))))
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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))))
|
||||
|
|
|
@ -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 {} {})))
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue