qr testing mode, fixed qr pure address and EIP681 issues

Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
This commit is contained in:
Andrey Shovkoplyas 2020-04-03 15:29:41 +02:00
parent e813d1e4e4
commit 45dae49fc0
No known key found for this signature in database
GPG Key ID: EAAB7C8622D860A4
20 changed files with 303 additions and 321 deletions

1
.env
View File

@ -23,3 +23,4 @@ MOBILE_UI_FOR_DESKTOP=1
STATUS_GO_PROTOCOL=0
STATUS_GO_ENABLE_NIMBUS=0
KEYCARD_TEST_MENU=0
QR_READ_TEST_MENU=1

View File

@ -23,3 +23,4 @@ BLANK_PREVIEW=0
TOOLTIP_EVENTS=1
COMMANDS_ENABLED=1
KEYCARD_TEST_MENU=1
QR_READ_TEST_MENU=1

View File

@ -25,7 +25,7 @@
(def key-value-format (str "([^" parameter-separator key-value-separator "]+)"))
(def query-pattern (re-pattern (str key-value-format key-value-separator key-value-format)))
(def valid-native-arguments #{:value :gas :gasPrice})
(def valid-native-arguments #{:value :gas :gasPrice :gasLimit})
(defn- parse-query [s]
(into {} (for [[_ k v] (re-seq query-pattern (or s ""))]
@ -51,6 +51,8 @@
Invalid URI will be parsed as `nil`."
[s]
(when (string? s)
(if (ethereum/address? s)
{:address s}
(let [[_ authority-path query] (re-find uri-pattern s)]
(when authority-path
(let [[_ raw-address chain-id function-name] (re-find authority-path-pattern authority-path)]
@ -70,7 +72,7 @@
:chain-id (if chain-id
(js/parseInt chain-id)
(ethereum/chain-keyword->chain-id :mainnet))}
arguments)))))))))))
arguments))))))))))))
(defn parse-eth-value [s]
"Takes a map as returned by `parse-uri` and returns value as BigNumber"
@ -79,10 +81,11 @@
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]} all-tokens]
(defn extract-request-details [{:keys [value address function-name function-arguments] :as details} 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
(merge details
(case function-name
nil
{:value (parse-eth-value value)
@ -90,9 +93,9 @@
:address address}
"transfer"
{:value (money/bignumber (:uint256 function-arguments))
:symbol (:symbol (tokens/address->token all-tokens (ethereum/chain-id->chain-keyword chain-id) address))
:symbol (:symbol (tokens/address->token all-tokens address))
:address (:address function-arguments)}
nil)))
nil))))
(defn- generate-query-string [m]
(string/join parameter-separator
@ -118,8 +121,8 @@
(defn generate-erc20-uri
"Generate a EIP 681 URI encapsulating ERC20 token transfer"
[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)]
[address {:keys [symbol value] :as m} all-tokens]
(when-let [token (tokens/symbol->token all-tokens symbol)]
(generate-uri (:address token)
(merge (dissoc m :value :symbol)
{:function-name "transfer"

View File

@ -27,7 +27,10 @@
"In react-native arguments to require must be static strings.
Resolve all icons at compilation time so no variable is used."
[network tokens]
(mapv #(assoc-in % [:icon :source] (token->icon network %)) tokens))
(mapv #(-> %
(assoc-in [:icon :source] (token->icon network %))
(update :address string/lower-case))
tokens))
(defn network->icon [network]
(let [s (str "./resources/images/tokens/" (name network) "/0-native.png")

View File

@ -1,10 +1,5 @@
(ns status-im.ethereum.subscriptions
(:require [re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.ethereum.eip55 :as eip55]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.ethereum.tokens :as tokens]
(:require [status-im.ethereum.eip55 :as eip55]
[status-im.wallet.db :as wallet]
[status-im.ethereum.transactions.core :as transactions]
[status-im.utils.fx :as fx]
@ -26,10 +21,6 @@
(fx/defn new-block
[{:keys [db] :as cofx} historical? block-number accounts transactions-per-account]
(let [{:keys [:wallet/all-tokens]} db
chain (ethereum/chain-keyword db)
chain-tokens (into {} (map (juxt :address identity)
(tokens/tokens-for all-tokens chain)))]
(log/debug "[wallet-subs] new-block"
"accounts" accounts
"block" block-number
@ -43,11 +34,11 @@
;; from/to one of the multiaccount accounts
(not-empty accounts)
(assoc :transactions/get-transfers
{:chain-tokens chain-tokens
{:chain-tokens (:wallet/all-tokens db)
:addresses accounts
:before-block block-number
:historical? historical?}))
(transactions/check-watched-transactions))))
(transactions/check-watched-transactions)))
(fx/defn reorg
[{:keys [db] :as cofx} {:keys [blockNumber accounts]}]
@ -68,16 +59,12 @@
(log/debug "[wallet-subs] recent-history-fetching-ended"
"accounts" accounts
"block" blockNumber)
(let [{:keys [:wallet/all-tokens]} db
chain (ethereum/chain-keyword db)
chain-tokens (into {} (map (juxt :address identity)
(tokens/tokens-for all-tokens chain)))]
{:db (-> db
(update-in [:wallet :accounts]
wallet/remove-transactions-since-block blockNumber)
(transactions/update-fetching-status accounts :recent? false))
:transactions/get-transfers
{:chain-tokens chain-tokens
{:chain-tokens (:wallet/all-tokens db)
:addresses (reduce
(fn [v address]
(let [normalized-address
@ -89,7 +76,7 @@
accounts)
:before-block blockNumber
:limit 20
:historical? true}}))
:historical? true}})
(fx/defn new-wallet-event
[cofx {:keys [type blockNumber accounts newTransactions] :as event}]

View File

@ -543,35 +543,24 @@
:custom []})
;; TODO all these should be improved, we don't need to recalculate this each time, it can be done only once
(defn tokens-for
"makes sure all addresses are lower-case
TODO: token list should be speced and not accept non-lower-cased addresses"
[all-tokens chain]
(mapv #(update % :address string/lower-case) (vals (get all-tokens chain))))
(defn nfts-for [all-tokens]
(filter :nft? (vals all-tokens)))
(defn nfts-for [all-tokens chain]
(filter :nft? (tokens-for all-tokens chain)))
(defn token-for [chain all-tokens token]
(some #(when (= token (name (:symbol %))) %) (tokens-for all-tokens chain)))
(defn sorted-tokens-for [all-tokens chain]
(->> (tokens-for all-tokens chain)
(defn sorted-tokens-for [all-tokens]
(->> (vals all-tokens)
(filter #(not (:hidden? %)))
(sort #(compare (string/lower-case (:name %1))
(string/lower-case (:name %2))))))
(defn symbol->token [all-tokens chain symbol]
(some #(when (= symbol (:symbol %)) %) (tokens-for all-tokens chain)))
(defn symbol->token [all-tokens symbol]
(some #(when (= symbol (:symbol %)) %) (vals all-tokens)))
(defn address->token [all-tokens chain address]
(some #(when (= (string/lower-case address)
(string/lower-case (:address %))) %) (tokens-for all-tokens chain)))
(defn address->token [all-tokens address]
(get all-tokens (string/lower-case address)))
(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 all-tokens chain symbol))))
(symbol->token all-tokens symbol))))

View File

@ -275,20 +275,13 @@
(fx/defn fetch-more-tx
{:events [:transactions/fetch-more]}
[{:keys [db] :as cofx} address]
(let [all-tokens (:wallet/all-tokens db)
chain (ethereum/chain-keyword db)
chain-tokens (into
{}
(map (juxt :address identity)
(tokens/tokens-for
all-tokens chain)))
min-known-block (or (get-min-known-block db address)
(let [min-known-block (or (get-min-known-block db address)
(:ethereum/current-block db))
min-block-transfers-count (or (min-block-transfers-count db address) 0)]
(fx/merge
cofx
{:transactions/get-transfers
{:chain-tokens chain-tokens
{:chain-tokens (:wallet/all-tokens db)
:addresses [address]
:before-block min-known-block
:historical? true

View File

@ -106,8 +106,7 @@
(fx/defn prepare-unconfirmed-transaction
[{:keys [db now]} hash {:keys [value gasPrice gas data to from]} symbol amount]
(let [all-tokens (:wallet/all-tokens db)
token (tokens/symbol->token all-tokens (ethereum/chain-keyword db) symbol)]
(let [token (tokens/symbol->token (:wallet/all-tokens db) symbol)]
{:db (assoc-in db [:wallet :accounts from :transactions hash]
{:timestamp (str now)
:to to
@ -133,7 +132,7 @@
:approve-and-call))
(defn get-transfer-token [db to data]
(let [{:keys [symbol decimals] :as token} (tokens/address->token (:wallet/all-tokens db) (ethereum/chain-keyword db) to)]
(let [{:keys [symbol decimals] :as token} (tokens/address->token (:wallet/all-tokens db) to)]
(when (and token data (string? data))
(when-let [type (get-method-type data)]
(let [[address value _] (abi-spec/decode

View File

@ -1118,18 +1118,21 @@
0))
acc)) 0 balance))
(re-frame/reg-sub
:wallet/token->decimals
:<- [:wallet/all-tokens]
(fn [all-tokens]
(into {} (map #(vector (:symbol %) (:decimals %)) (vals all-tokens)))))
(re-frame/reg-sub
:portfolio-value
:<- [:balances]
:<- [:prices]
:<- [:wallet/currency]
:<- [:ethereum/chain-keyword]
:<- [:wallet/all-tokens]
(fn [[balances prices currency chain all-tokens]]
:<- [:wallet/token->decimals]
(fn [[balances prices currency token->decimals]]
(if (and balances prices)
(let [assets (tokens/tokens-for all-tokens chain)
token->decimals (into {} (map #(vector (:symbol %) (:decimals %)) assets))
currency-key (-> currency :code keyword)
(let [currency-key (-> currency :code keyword)
balance-total-value (apply + (map #(get-balance-total-value % prices currency-key token->decimals) balances))]
(if (pos? balance-total-value)
(-> balance-total-value
@ -1145,13 +1148,10 @@
[(re-frame/subscribe [:balance address])
(re-frame/subscribe [:prices])
(re-frame/subscribe [:wallet/currency])
(re-frame/subscribe [:ethereum/chain-keyword])
(re-frame/subscribe [:wallet/all-tokens])])
(fn [[balance prices currency chain all-tokens]]
(re-frame/subscribe [:wallet/token->decimals])])
(fn [[balance prices currency token->decimals]]
(if (and balance prices)
(let [assets (tokens/tokens-for all-tokens chain)
token->decimals (into {} (map #(vector (:symbol %) (:decimals %)) assets))
currency-key (-> currency :code keyword)
(let [currency-key (-> currency :code keyword)
balance-total-value (get-balance-total-value balance prices currency-key token->decimals)]
(if (pos? balance-total-value)
(-> balance-total-value
@ -1162,22 +1162,14 @@
"...")))
(re-frame/reg-sub
:wallet/chain-tokens
:wallet/sorted-tokens
:<- [:wallet/all-tokens]
:<- [:ethereum/chain-keyword]
(fn [[all-tokens chain]]
(get all-tokens chain)))
(re-frame/reg-sub
:wallet/sorted-chain-tokens
:<- [:wallet/all-tokens]
:<- [:ethereum/chain-keyword]
(fn [[all-tokens chain]]
(tokens/sorted-tokens-for all-tokens chain)))
(fn [all-tokens]
(tokens/sorted-tokens-for all-tokens)))
(re-frame/reg-sub
:wallet/grouped-chain-tokens
:<- [:wallet/sorted-chain-tokens]
:<- [:wallet/sorted-tokens]
:<- [:wallet/visible-tokens-symbols]
(fn [[all-tokens visible-tokens]]
(let [vt-set (set visible-tokens)]
@ -1228,10 +1220,9 @@
:wallet/visible-assets
:<- [:ethereum/chain-keyword]
:<- [:wallet/visible-tokens-symbols]
:<- [:wallet/all-tokens]
(fn [[chain visible-tokens-symbols all-tokens]]
(conj (filter #(contains? visible-tokens-symbols (:symbol %))
(tokens/sorted-tokens-for all-tokens chain))
:<- [:wallet/sorted-tokens]
(fn [[chain visible-tokens-symbols all-tokens-sorted]]
(conj (filter #(contains? visible-tokens-symbols (:symbol %)) all-tokens-sorted)
(tokens/native-currency chain))))
(re-frame/reg-sub

View File

@ -146,7 +146,7 @@
[contract value]
(let [{:keys [symbol icon decimals color] :as token}
(if (seq contract)
(get @(re-frame/subscribe [:wallet/chain-tokens])
(get @(re-frame/subscribe [:wallet/all-tokens])
contract
transactions/default-erc20-token)
@(re-frame/subscribe [:ethereum/native-currency]))

View File

@ -6,7 +6,9 @@
[status-im.ui.components.react :as react]
[status-im.ui.components.toolbar.view :as topbar]
[status-im.ui.screens.qr-scanner.styles :as styles]
[status-im.ui.components.colors :as colors]))
[status-im.ui.components.colors :as colors]
[status-im.utils.config :as config]
[status-im.ui.components.button :as button]))
(defn- topbar [camera-flashlight {:keys [title] :as opts}]
[topbar/toolbar
@ -23,6 +25,25 @@
:icon-opts {:color colors/white}
:handler #(re-frame/dispatch [:wallet/toggle-flashlight])}]]])
(defn qr-test-view [opts]
(let [text-value (atom "")]
[react/safe-area-view {:style {:flex 1
:background-color colors/black-persist}}
[topbar nil opts]
[react/view {:flex 1
:align-items :center
:justify-content :center}
[react/text-input {:multiline true
:style {:color colors/white-persist}
:on-change-text #(reset! text-value %)}]
[react/view {:flex-direction :row}
[button/button
{:label "Cancel"
:on-press #(re-frame/dispatch [:qr-scanner.callback/scan-qr-code-cancel opts])}]
[button/button
{:label "OK"
:on-press #(re-frame/dispatch [:qr-scanner.callback/scan-qr-code-success opts @text-value])}]]]]))
(defn corner [border1 border2 corner]
[react/view (assoc {:border-color colors/white-persist :width 60 :height 60} border1 5 border2 5 corner 32)])
@ -44,6 +65,8 @@
{:keys [height width]} [:dimensions/window]
camera-flashlight [:wallet.send/camera-flashlight]
opts [:get-screen-params]]
(if config/qr-test-menu-enabled?
[qr-test-view opts]
[react/safe-area-view {:style {:flex 1
:background-color colors/black-persist}}
[topbar camera-flashlight opts]
@ -55,4 +78,4 @@
:onBarCodeRead #(when-not @read-once?
(reset! read-once? true)
(on-barcode-read opts %))}]]
[viewfinder (int (* 2 (/ (min height width) 3)))]]))
[viewfinder (int (* 2 (/ (min height width) 3)))]])))

View File

@ -37,7 +37,8 @@
(defn- request-camera-permissions []
(let [options {:handler :wallet.send/qr-scanner-result
:cancel-handler :wallet.send/qr-scanner-cancel}]
:cancel-handler :wallet.send/qr-scanner-cancel
:modal-opened? true}]
(re-frame/dispatch
[:request-permissions
{:permissions [:camera]

View File

@ -40,6 +40,7 @@
(def waku-enabled? (enabled? (get-config :WAKU_ENABLED "0")))
(def commands-enabled? (enabled? (get-config :COMMANDS_ENABLED "0")))
(def keycard-test-menu-enabled? (enabled? (get-config :KEYCARD_TEST_MENU "0")))
(def qr-test-menu-enabled? (enabled? (get-config :QR_READ_TEST_MENU "0")))
;; CONFIG VALUES
(def log-level

View File

@ -102,7 +102,7 @@
(fx/defn handle-eip681 [cofx url]
(fx/merge cofx
(choose-recipient/resolve-ens-addresses url)
(choose-recipient/parse-eip681-uri-and-resolve-ens url)
(navigation/navigate-to-cofx :wallet nil)))
(defn handle-not-found [full-url]

View File

@ -271,8 +271,7 @@
(fx/defn view-only-qr-scanner-result
{:events [:wallet.add-new/qr-scanner-result]}
[{db :db :as cofx} data _]
(let [address (or (when (ethereum/address? data) data)
(:address (eip681/parse-uri data)))]
(let [address (:address (eip681/parse-uri data))]
(fx/merge cofx
(merge {:db (-> db
(assoc-in [:add-account :scanned-address] address)

View File

@ -1,6 +1,5 @@
(ns status-im.wallet.choose-recipient.core
(:require [re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.contact.db :as contact.db]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.eip55 :as eip55]
@ -23,51 +22,6 @@
(defn- find-address-name [db address]
(:name (contact.db/find-contact-by-address (:contacts/contacts db) address)))
(defn- fill-request-details [db {:keys [address name value symbol gas gasPrice public-key from-chat?]} request?]
{:pre [(not (nil? address))]}
(let [name (or name (find-address-name db address))
;;TODO request isn't implemented
data-path (if request?
:wallet/prepare-transaction
:wallet/prepare-transaction)]
(update db data-path
(fn [{old-symbol :symbol :as old-transaction}]
(let [symbol-changed? (not= old-symbol symbol)]
(cond-> (assoc old-transaction
:to address :to-name name :public-key public-key
:gas (money/bignumber gas)
:gas-price (money/bignumber gasPrice))
value (assoc :amount value)
symbol (assoc :symbol symbol)
from-chat? (assoc :from-chat? from-chat?)))))))
;;TODO request isn't implemented
(fx/defn fill-request-from-contact
{:events [:wallet/fill-request-from-contact]}
[{db :db} {:keys [address name public-key]} request?]
{:db (fill-request-details db {:address address :name name :public-key public-key} request?)
:dispatch [:navigate-back]})
(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"
[m chain-id all-tokens]
(or (merge m (eip681/extract-request-details m all-tokens))
(when (ethereum/address? m)
{:address m :chain-id chain-id})))
;; NOTE(janherich) - whenever changing assets, we want to clear the previusly set amount/amount-text
(defn changed-asset [{:keys [db] :as fx} old-symbol new-symbol]
(-> fx
(assoc-in [:db :wallet/prepare-transaction :amount] nil)
(assoc-in [:db :wallet/prepare-transaction :amount-text] nil)
(assoc-in [:db :wallet/prepare-transaction :asset-error]
(i18n/label :t/changed-asset-warning {:old old-symbol :new new-symbol}))))
(defn changed-amount-warning [fx old-amount new-amount]
(assoc-in fx [:db :wallet/prepare-transaction :amount-error]
(i18n/label :t/changed-amount-warning {:old old-amount :new new-amount})))
(defn use-default-eth-gas [fx]
(assoc-in fx [:db :wallet :send-transaction :gas]
ethereum/default-transaction-gas))
@ -115,41 +69,51 @@
:else
{:ui/show-error (i18n/label :t/wallet-invalid-address {:data recipient})})))
(defn- fill-prepare-transaction-details
[db
{:keys [address name value symbol gas gasPrice gasLimit]
:or {symbol :ETH}}
all-tokens]
(assoc db :wallet/prepare-transaction
(cond-> {:to address
:to-name (or name (find-address-name db address))
:from (ethereum/get-default-account
(get db :multiaccount/accounts))}
gas (assoc :gas (money/bignumber gas))
gasLimit (assoc :gas (money/bignumber gasLimit))
gasPrice (assoc :gasPrice (money/bignumber gasPrice))
value (assoc :amount-text
(if (= :ETH symbol)
(str (money/internal->formatted value symbol (get all-tokens symbol)))
(str value)))
symbol (assoc :symbol symbol))))
(fx/defn request-uri-parsed
{:events [:wallet/request-uri-parsed]}
[{{:networks/keys [networks current-network] :wallet/keys [all-tokens] :as db} :db} data uri]
(let [current-chain-id (get-in networks [current-network :config :NetworkId])
{: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 db :wallet/prepare-transaction)
old-symbol (:symbol previous-state)
new-symbol (:symbol details)
old-amount (:amount previous-state)
new-amount (:value details)
symbol-changed? (and old-symbol new-symbol (not= old-symbol new-symbol))
amount-changed? (and old-amount new-amount (not= old-amount new-amount))]
(cond-> {:db db}
(and address valid-network?) (update :db #(fill-request-details % details false))
symbol-changed? (changed-asset old-symbol new-symbol)
amount-changed? (changed-amount-warning old-amount new-amount)
(not (:from previous-state))
(update :db assoc-in [:wallet/prepare-transaction :from]
(ethereum/get-default-account (get db :multiaccount/accounts)))
(not old-symbol)
(update :db assoc-in [:wallet/prepare-transaction :symbol] (or new-symbol :ETH))
(not address) (assoc :ui/show-error (i18n/label :t/wallet-invalid-address {:data uri}))
(and address (not valid-network?))
(assoc :ui/show-error (i18n/label :t/wallet-invalid-chain-id
{:data uri :chain current-chain-id})))))
[{{:networks/keys [networks current-network]
:wallet/keys [all-tokens] :as db} :db}
{:keys [chain-id] :as data}
uri]
(let [{:keys [address] :as details}
(eip681/extract-request-details data all-tokens)]
(if address
(if (:wallet/prepare-transaction db)
{:db (update db :wallet/prepare-transaction assoc
:to address :to-name (find-address-name db address))}
(let [current-chain-id (get-in networks [current-network :config :NetworkId])]
(merge {:db (fill-prepare-transaction-details db details all-tokens)}
(when (and chain-id (not= current-chain-id chain-id))
{:ui/show-error (i18n/label :t/wallet-invalid-chain-id
{:data uri :chain current-chain-id})}))))
{:ui/show-error (i18n/label :t/wallet-invalid-address {:data uri})})))
(fx/defn qr-scanner-cancel
{:events [:wallet.send/qr-scanner-cancel]}
[{db :db} _]
{:db (assoc-in db [:wallet/prepare-transaction :modal-opened?] false)})
(fx/defn resolve-ens-addresses
{:events [:wallet.send/resolve-ens-addresses :wallet.send/qr-code-request-scanned]}
[{{:networks/keys [current-network] :wallet/keys [all-tokens] :as db} :db :as cofx} uri]
(fx/defn parse-eip681-uri-and-resolve-ens
[{db :db :as cofx} uri]
(if-let [message (eip681/parse-uri uri)]
;; first we get a vector of ens-names to resolve and a vector of paths of
;; these names
@ -163,8 +127,9 @@
acc)))
{:paths [] :ens-names []}
[[:address] [:function-arguments :address]])]
(println "message" message)
(if (empty? ens-names)
;; if there is no ens-names, we dispatch request-uri-parsed immediately
;; if there are no ens-names, we dispatch request-uri-parsed immediately
(request-uri-parsed cofx message uri)
{::resolve-addresses
{:registry (get ens/ens-registries (ethereum/chain-keyword db))
@ -173,7 +138,7 @@
(fn [addresses]
(re-frame/dispatch
[:wallet/request-uri-parsed
;; we replace the ens-names at their path in the message by their
;; we replace ens-names at their path in the message by their
;; actual address
(reduce (fn [message [path address]]
(assoc-in message path address))
@ -185,6 +150,8 @@
{:events [:wallet.send/qr-scanner-result]}
[{db :db :as cofx} data opts]
(fx/merge cofx
{:db (assoc-in db [:wallet/prepare-transaction :modal-opened?] false)}
(navigation/navigate-back)
(resolve-ens-addresses data)))
(parse-eip681-uri-and-resolve-ens data)
(fn [{:keys [db]}]
(when (get-in db [:wallet/prepare-transaction :modal-opened?])
{:db (assoc-in db [:wallet/prepare-transaction :modal-opened?] false)}))))

View File

@ -19,8 +19,8 @@
(defmulti load-collectibles-fx (fn [_ symbol _ _ _] symbol))
(defmethod load-collectibles-fx :default [all-tokens symbol items-number address chain]
{:load-collectibles-fx [all-tokens symbol items-number address chain]})
(defmethod load-collectibles-fx :default [all-tokens symbol items-number address]
{:load-collectibles-fx [all-tokens symbol items-number address]})
(defn load-token [i items-number contract address symbol]
(when (< i items-number)
@ -31,21 +31,18 @@
(re-frame/reg-fx
:load-collectibles-fx
(fn [[all-tokens symbol items-number address chain]]
(let [contract (:address (tokens/symbol->token all-tokens chain symbol))]
(fn [[all-tokens symbol items-number address]]
(let [contract (:address (tokens/symbol->token all-tokens symbol))]
(load-token 0 items-number contract address symbol))))
(handlers/register-handler-fx
:show-collectibles-list
(fn [{:keys [db]} [_ {:keys [symbol amount] :as collectible} address]]
(let [{:networks/keys [current-network networks]} db
chain (ethereum/chain-id->chain-keyword
(get-in networks [current-network :config :NetworkId]))
all-tokens (:wallet/all-tokens db)
(let [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 all-tokens symbol items-number address chain))
(load-collectibles-fx all-tokens symbol items-number address))
{:dispatch [:navigate-to :collectibles-list collectible]}))))
;; Crypto Kitties
@ -101,16 +98,12 @@
(def kudos :KDO)
(defmethod load-collectible-fx kudos [{db :db} symbol id]
(let [{:networks/keys [current-network networks]} db
chain-id (get-in networks [current-network :config :NetworkId])
all-tokens (:wallet/all-tokens db)]
{:erc721-token-uri [all-tokens symbol id chain-id]}))
{:erc721-token-uri [(:wallet/all-tokens db) symbol id]})
(re-frame/reg-fx
:erc721-token-uri
(fn [[all-tokens symbol tokenId chain-id]]
(let [chain (ethereum/chain-id->chain-keyword chain-id)
contract (:address (tokens/symbol->token all-tokens chain symbol))]
(fn [[all-tokens symbol tokenId]]
(let [contract (:address (tokens/symbol->token all-tokens symbol))]
(erc721/token-uri contract
tokenId
#(re-frame/dispatch [:token-uri-success

View File

@ -200,9 +200,9 @@
(update-in db [:wallet :errors] dissoc error-type))
(defn tokens-symbols
[visible-token-symbols all-tokens chain]
[visible-token-symbols all-tokens]
(set/difference (set visible-token-symbols)
(set (map :symbol (tokens/nfts-for all-tokens chain)))))
(set (map :symbol (tokens/nfts-for all-tokens)))))
(defn rpc->token [tokens]
(reduce (fn [acc {:keys [address] :as token}]
@ -213,21 +213,14 @@
tokens))
(fx/defn initialize-tokens
[{:keys [db] :as cofx} custom-tokens]
(let [chain (ethereum/chain-keyword db)
custom-tokens {chain (rpc->token custom-tokens)}
;;TODO why do we need all tokens ? chain can be changed only through relogin
all-tokens (merge-with
merge
(utils.core/map-values #(utils.core/index-by :address %)
tokens/all-default-tokens)
custom-tokens)]
(fx/merge
cofx
[{:keys [db]} custom-tokens]
(let [default-tokens (utils.core/index-by :address (get tokens/all-default-tokens
(ethereum/chain-keyword db)))
all-tokens (merge default-tokens (rpc->token custom-tokens))]
(merge
{:db (assoc db :wallet/all-tokens all-tokens)}
(when config/erc20-contract-warnings-enabled?
{:wallet/validate-tokens (get tokens/all-default-tokens chain)})))))
{:wallet/validate-tokens default-tokens}))))
(fx/defn update-balances
[{{:keys [network-status :wallet/all-tokens
@ -239,7 +232,7 @@
assets (get visible-tokens chain)
init? (or (empty? assets)
(= assets (constants/default-visible-tokens chain)))
tokens (->> (tokens/tokens-for all-tokens chain)
tokens (->> (vals all-tokens)
(remove #(or (:hidden? %)
;;if not init remove not visible tokens
(and (not init?)
@ -269,7 +262,7 @@
(let [chain (ethereum/chain-keyword db)
mainnet? (= :mainnet chain)
assets (get visible-tokens chain #{})
tokens (tokens-symbols assets all-tokens chain)
tokens (tokens-symbols assets all-tokens)
currency (get constants/currencies currency)]
(when (not= network-status :offline)
{:wallet/get-prices
@ -446,7 +439,7 @@
chain (ethereum/network->chain-keyword current-network)
{:keys [symbol decimals]}
(if (seq contract)
(get (get all-tokens chain) contract)
(get all-tokens contract)
(tokens/native-currency chain))
amount-text (str (money/internal->formatted value symbol decimals))]
{:db (assoc db :wallet/prepare-transaction
@ -608,7 +601,8 @@
{:events [:wallet.send/qr-scanner-allowed]}
[{:keys [db] :as cofx} options]
(fx/merge cofx
{:db (assoc-in db [:wallet/prepare-transaction :modal-opened?] true)}
(when (:modal-opened? options)
{:db (assoc-in db [:wallet/prepare-transaction :modal-opened?] true)})
(bottom-sheet/hide-bottom-sheet)
(navigation/navigate-to-cofx :qr-scanner options)))

View File

@ -85,10 +85,9 @@
(string/trim %)]))))
(defn field-exists?
[{:wallet/keys [all-tokens] :as db} field-key field-value]
(let [chain-key (ethereum/chain-keyword db)]
[{:wallet/keys [all-tokens]} field-key field-value]
(some #(= field-value (get % field-key))
(vals (get all-tokens chain-key)))))
(vals all-tokens)))
(fx/defn total-supply-result
[{:keys [db]} contract total-supply]
@ -100,10 +99,8 @@
:error (i18n/label :t/wrong-contract)})}))
(defn token-in-list?
[{:wallet/keys [all-tokens] :as db} contract]
(let [chain-key (ethereum/chain-keyword db)
addresses (set (map string/lower-case (keys (get all-tokens chain-key))))]
(not (nil? (get addresses (string/lower-case contract))))))
[{:wallet/keys [all-tokens]} contract]
(not (nil? (get all-tokens (string/lower-case contract)))))
(fx/defn contract-address-is-changed
[{:keys [db]} contract]
@ -177,7 +174,7 @@
:decimals (int decimals)
:color (rand-nth colors/chat-colors)}]
(fx/merge cofx
{:db (assoc-in db [:wallet/all-tokens chain-key contract]
{:db (assoc-in db [:wallet/all-tokens contract]
(assoc new-token :custom? true))
::json-rpc/call [{:method "wallet_addCustomToken"
:params [new-token]
@ -191,7 +188,7 @@
[{:keys [db] :as cofx} {:keys [address] :as token} navigate-back?]
(let [chain-key (ethereum/chain-keyword db)]
(fx/merge cofx
{:db (update-in db [:wallet/all-tokens chain-key] dissoc address)
{:db (update db :wallet/all-tokens dissoc address)
::json-rpc/call [{:method "wallet_deleteCustomToken"
:params [address]
:on-success #()}]}

View File

@ -16,34 +16,73 @@
(is (= nil (eip681/parse-uri "ethereum:pay-gimme.ether?value=1e18")))
(is (= nil (eip681/parse-uri "ethereum:pay-snt.thetoken.ether/transfer?address=gimme.eth&uint256=1&gas=100")))
(is (= nil (eip681/parse-uri "ethereum:pay-snt.thetoken.eth/transfer?address=gimme.ether&uint256=1&gas=100")))
(is (= {:address "gimme.eth" :value "1e18" :chain-id 1} (eip681/parse-uri "ethereum:pay-gimme.eth?value=1e18")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1e18" :chain-id 1} (eip681/parse-uri "ethereum:pay-0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1e18")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7", :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?unknown=1")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7", :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "2.014e18" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=2.014e18")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "-1e18" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=-1e18")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "+1E18" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=+1E18")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1E18" :gas "100" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1E18&gas=100")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "NOT_NUMBER" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=NOT_NUMBER")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1ETH" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1ETH")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1e18" :gas "5000" :chain-id 1} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7@1?value=1e18&gas=5000")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1e18" :gas "5000" :chain-id 3} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7@3?value=1e18&gas=5000")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1 :function-name "transfer"} (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1 :function-name "transfer" :function-arguments {:address "0x8e23ee67d1332ad560396262c48ffbb01f93d052" :uint256 "1"}}
(eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer?address=0x8e23ee67d1332ad560396262c48ffbb01f93d052&uint256=1")))
(is (= {:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1 :function-name "transfer" :gas "100" :function-arguments {:address "0x8e23ee67d1332ad560396262c48ffbb01f93d052" :uint256 "1"}}
(eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer?address=0x8e23ee67d1332ad560396262c48ffbb01f93d052&uint256=1&gas=100")))
(is (= {:address "snt.thetoken.eth" :chain-id 1 :function-name "transfer" :gas "100" :function-arguments {:address "gimme.eth" :uint256 "1"}}
(eip681/parse-uri "ethereum:pay-snt.thetoken.eth/transfer?address=gimme.eth&uint256=1&gas=100"))))
(is (= (eip681/parse-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"}))
(is (= (eip681/parse-uri "ethereum:pay-gimme.eth?value=1e18")
{:address "gimme.eth" :value "1e18" :chain-id 1}))
(is (= (eip681/parse-uri "ethereum:pay-0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1e18")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1e18" :chain-id 1}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1" :chain-id 1}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?unknown=1")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7", :chain-id 1}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7", :chain-id 1}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=2.014e18")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "2.014e18" :chain-id 1}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=-1e18")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "-1e18" :chain-id 1}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=+1E18")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "+1E18" :chain-id 1}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1E18&gas=100")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1E18" :gas "100" :chain-id 1}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=NOT_NUMBER")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "NOT_NUMBER" :chain-id 1}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7?value=1ETH")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1ETH" :chain-id 1}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7@1?value=1e18&gas=5000")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1e18" :gas "5000" :chain-id 1}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7@3?value=1e18&gas=5000")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :value "1e18" :gas "5000" :chain-id 3}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1 :function-name "transfer"}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer?address=0x8e23ee67d1332ad560396262c48ffbb01f93d052&uint256=1")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1
:function-name "transfer" :function-arguments {:address "0x8e23ee67d1332ad560396262c48ffbb01f93d052" :uint256 "1"}}))
(is (= (eip681/parse-uri "ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer?address=0x8e23ee67d1332ad560396262c48ffbb01f93d052&uint256=1&gas=100")
{:address "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" :chain-id 1 :gas "100"
:function-name "transfer" :function-arguments {:address "0x8e23ee67d1332ad560396262c48ffbb01f93d052" :uint256 "1"}}))
(is (= (eip681/parse-uri "ethereum:pay-snt.thetoken.eth/transfer?address=gimme.eth&uint256=1&gas=100")
{:address "snt.thetoken.eth" :chain-id 1 :gas "100"
:function-name "transfer" :function-arguments {:address "gimme.eth" :uint256 "1"}})))
(def all-tokens
{:mainnet {"0x744d70fdbe2ba4cf95131626614a1763df805b9e" {:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
:name "Status Network Token"
:symbol :SNT
:decimals 18}}
:testnet {"0xc55cF4B03948D7EBc8b9E8BAD92643703811d162" {:address "0xc55cF4B03948D7EBc8b9E8BAD92643703811d162"
:testnet {"0xc55cf4b03948d7ebc8b9e8bad92643703811d162" {:address "0xc55cf4b03948d7ebc8b9e8bad92643703811d162"
:name "Status Test Token"
:symbol :STT
:decimals 18}}})
@ -51,13 +90,13 @@
(deftest generate-erc20-uri
(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} all-tokens)))
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :SNT :value 5} (:mainnet 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} all-tokens)))
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :SNT :value 5 :gas 10000 :gasPrice 10000} (:mainnet all-tokens))))
(is (= "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :SNT :chain-id 1 :value 5} all-tokens)))
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :SNT :chain-id 1 :value 5} (:mainnet all-tokens))))
(is (= "ethereum:0xc55cf4b03948d7ebc8b9e8bad92643703811d162@3/transfer?uint256=5&address=0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7"
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :STT :chain-id 3 :value 5} all-tokens))))
(eip681/generate-erc20-uri "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" {:symbol :STT :chain-id 3 :value 5} (:testnet all-tokens)))))
(deftest generate-uri
(is (= nil (eip681/generate-uri nil nil)))
@ -96,13 +135,14 @@
(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 (= (eip681/extract-request-details {:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e" :chain-id 1 :function-name "unknown"}
{: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"}}
{:mainnet {"0x744d70fdbe2ba4cf95131626614a1763df805b9e" {:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
{"0x744d70fdbe2ba4cf95131626614a1763df805b9e" {:address "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
:name "Status Network Token"
:symbol :SNT
:decimals 18}}})]
:decimals 18}})]
(is (.equals (money/bignumber 1000) value))
(is (= :SNT symbol))
(is (= "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" address))))