[feature] use subscriptions for tokens

- removes fetching of last 100000 blocks of token transfers from
the wallet pull loop
- fetches the last 100000 blocks of token transfers at startup
- replaces pulling by subscriptions to ethlogs for token transfers
This commit is contained in:
yenda 2019-05-09 21:51:41 +02:00
parent 8c349a3038
commit f5c18ae7a9
No known key found for this signature in database
GPG Key ID: 0095623C0069DCE6
14 changed files with 249 additions and 266 deletions

View File

@ -1,3 +1,3 @@
## DO NOT EDIT THIS FILE BY HAND. USE `scripts/update-status-go.sh <tag>` instead
0cj202bj2rwfrw327gibj8hj8i94ciyp3hkq2hck9l6711qlhpnb
0049i6znvl45hc651bqyzwgmzlv0fp40maggfjsrv13q5avd0g6d

View File

@ -1,3 +1,3 @@
## DO NOT EDIT THIS FILE BY HAND. USE `scripts/update-status-go.sh <tag>` instead
v0.25.0-beta.0
v0.25.0-beta.1

View File

@ -4,9 +4,9 @@
[status-im.chaos-mode.core :as chaos-mode]
[status-im.data-store.core :as data-store]
[status-im.ethereum.subscriptions :as ethereum.subscriptions]
[status-im.ethereum.transactions.core :as transactions]
[status-im.fleet.core :as fleet]
[status-im.i18n :as i18n]
[status-im.models.transactions :as transactions]
[status-im.models.wallet :as models.wallet]
[status-im.native-module.core :as status]
[status-im.node.core :as node]

View File

@ -1,12 +1,12 @@
(ns status-im.accounts.logout.core
(:require [re-frame.core :as re-frame]
[status-im.chaos-mode.core :as chaos-mode]
[status-im.ethereum.transactions.core :as transactions]
[status-im.i18n :as i18n]
[status-im.transport.core :as transport]
[status-im.utils.fx :as fx]
[status-im.models.transactions :as transactions]
[status-im.node.core :as node]
[status-im.init.core :as init]
[status-im.chaos-mode.core :as chaos-mode]))
[status-im.node.core :as node]
[status-im.transport.core :as transport]
[status-im.utils.fx :as fx]))
(fx/defn logout
[{:keys [db] :as cofx}]

View File

@ -1,32 +1,76 @@
(ns status-im.ethereum.subscriptions
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.ethereum.decode :as decode]
[status-im.native-module.core :as status]
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.ethereum.tokens :as tokens]
[status-im.utils.fx :as fx]
[status-im.utils.types :as types]
[taoensso.timbre :as log]))
(defn get-block-by-hash [block-hash callback]
;; NOTE: this is the safe block range that can be
;; queried from infura rpc gateway without getting timeouts
;; determined experimentally by @goranjovic
(def block-query-limit 100000)
(defn get-latest-block [callback]
(status/call-private-rpc
(.stringify js/JSON (clj->js {:jsonrpc "2.0"
:id 1
:method "eth_getBlockByHash"
:params [block-hash false]}))
(types/json->clj {:jsonrpc "2.0"
:id 1
:method "eth_blockNumber"
:params []})
(fn [response]
(if (string/blank? response)
(log/warn :web3-response-error)
(callback (-> (.parse js/JSON response)
(js->clj :keywordize-keys true)
:result
:number
decode/uint))))))
(defn get-block-by-hash [block-hash callback]
(status/call-private-rpc
(types/json->clj {:jsonrpc "2.0"
:id 1
:method "eth_getBlockByHash"
:params [block-hash false]})
(fn [response]
(if (string/blank? response)
(log/warn :web3-response-error)
(callback (-> (.parse js/JSON response)
(js->clj :keywordize-keys true)
:result
(update :number decode/uint)
(update :timestamp decode/uint)))))))
(defn- get-token-transfer-logs
[from-block {:keys [chain-tokens direction from to]} callback]
(status/call-private-rpc
(types/json->clj {:jsonrpc "2.0"
:id 2
:method "eth_getLogs"
:params
[{:address (keys chain-tokens)
:fromBlock from-block
:topics [constants/event-transfer-hash from to]}]})
(fn [response]
(if (string/blank? response)
(log/warn :web3-response-error)
(callback (-> (.parse js/JSON response)
(js->clj :keywordize-keys true)
:result))))))
(fx/defn handle-signal
[cofx {:keys [subscription_id data] :as event}]
(if-let [handler (get-in cofx [:db :ethereum/subscriptions subscription_id])]
(handler data)
(log/warn ::unknown-subscription :event event)))
(fx/defn handle-error
[cofx {:keys [subscription_id data] :as event}]
(log/error ::error event))
(fx/defn register-subscription
[{:keys [db]} id handler]
{:db (assoc-in db [:ethereum/subscriptions id] handler)})
@ -38,10 +82,10 @@
(defn subscribe-signal
[filter params callback]
(status/call-private-rpc
(.stringify js/JSON (clj->js {:jsonrpc "2.0"
:id 1
:method "eth_subscribeSignal"
:params [filter, params]}))
(types/clj->json {:jsonrpc "2.0"
:id 1
:method "eth_subscribeSignal"
:params [filter params]})
(fn [response]
(if (string/blank? response)
(log/error ::subscription-unknown-error :filter filter :params params)
@ -54,6 +98,100 @@
result
callback])))))))
(defn- add-padding [address]
{:pre [(string? address)]}
(str "0x000000000000000000000000" (subs address 2)))
(defn- remove-padding [topic]
{:pre [(string? topic)]}
(str "0x" (subs topic 26)))
(defn- parse-transaction-entries [timestamp chain-tokens direction transfers]
{:pre [(integer? timestamp)
(map? chain-tokens)
(every? (fn [[k v]] (and (string? k) (map? v))) chain-tokens)
(keyword? direction)
(every? map? transfers)]}
(into {}
(keep identity
(for [transfer transfers]
(when-let [token (->> transfer :address (get chain-tokens))]
(when-not (:nft? token)
[(:transactionHash transfer)
{:block (str (-> transfer :blockNumber ethereum/hex->bignumber))
:hash (:transactionHash transfer)
:symbol (:symbol token)
:from (some-> transfer :topics second remove-padding)
:to (some-> transfer :topics last remove-padding)
:value (-> transfer :data ethereum/hex->bignumber)
:type direction
:gas-price nil
:nonce nil
:data nil
:gas-limit nil
:timestamp (str (* timestamp 1000))
:gas-used nil
;; NOTE(goranjovic) - metadata on the type of token: contains name, symbol, decimas, address.
:token token
;; NOTE(goranjovic) - if an event has been emitted, we can say there was no error
:error? false
;; NOTE(goranjovic) - just a flag we need when we merge this entry with the existing entry in
;; the app, e.g. transaction info with gas details, or a previous transfer entry with old
;; confirmations count.
:transfer true}]))))))
(letfn [(combine-entries [transaction token-transfer]
(merge transaction (select-keys token-transfer [:symbol :from :to :value :type :token :transfer])))
(tx-and-transfer? [tx1 tx2]
(and (not (:transfer tx1)) (:transfer tx2)))
(both-transfer?
[tx1 tx2]
(and (:transfer tx1) (:transfer tx2)))]
(defn- dedupe-transactions [tx1 tx2]
(cond (tx-and-transfer? tx1 tx2) (combine-entries tx1 tx2)
(tx-and-transfer? tx2 tx1) (combine-entries tx2 tx1)
:else tx2)))
(fx/defn new-transactions
[{:keys [db]} transactions]
{:db (update-in db
[:wallet :transactions]
#(merge-with dedupe-transactions % transactions))})
(defn transactions-handler
[{:keys [chain-tokens from to direction]}]
(fn [transfers]
(let [transfers-by-block (group-by :blockHash transfers)]
(doseq [[block-hash block-transfers] transfers-by-block]
(get-block-by-hash
block-hash
(fn [{:keys [timestamp]}]
(let [transactions (parse-transaction-entries timestamp
chain-tokens
direction
block-transfers)]
(when (not-empty transactions)
(re-frame/dispatch [:ethereum.signal/new-transactions
transactions])))))))))
;; Here we are querying event logs for Transfer events.
;;
;; The parameters are as follows:
;; - address - token smart contract address
;; - fromBlock - we need to specify it, since default is latest
;; - topics[0] - hash code of the Transfer event signature
;; - topics[1] - address of token sender with leading zeroes padding up to 32 bytes
;; - topics[2] - address of token sender with leading zeroes padding up to 32 bytes
(defn new-token-transaction-filter
[{:keys [chain-tokens from to] :as args}]
(subscribe-signal
"eth_newFilter"
[{:fromBlock "latest"
:toBlock "latest"
:address (keys chain-tokens)
:topics [constants/event-transfer-hash from to]}]
(transactions-handler args)))
(defn new-block-filter
[]
(subscribe-signal
@ -61,15 +199,50 @@
(fn [[block-hash]]
(get-block-by-hash
block-hash
(fn [block-number]
(when block-number
(fn [block]
(when-let [block-number (:number block)]
(re-frame/dispatch [:ethereum.signal/new-block
block-number])))))))
(defn get-from-block
[current-block-number]
(-> current-block-number
(- block-query-limit)
(max 0)
ethereum/int->hex))
(re-frame/reg-fx
:ethereum.subscriptions/new-block-filter
:ethereum.subscriptions/token-transactions
(fn [{:keys [address] :as args}]
(let [inbound-args (merge args
{:direction :inbound
:to address})
outbound-args (merge args
{:direction :outbound
:from address})]
;; fetch 2 weeks of history until transactions are persisted
(get-latest-block
(fn [current-block-number]
(let [from-block (get-from-block current-block-number)]
(get-token-transfer-logs from-block inbound-args
(transactions-handler inbound-args))
(get-token-transfer-logs from-block outbound-args
(transactions-handler outbound-args)))))
;; start inbound and outbound token transaction subscriptions
(new-token-transaction-filter inbound-args)
(new-token-transaction-filter outbound-args))))
(re-frame/reg-fx
:ethereum.subscriptions/new-block
new-block-filter)
(fx/defn initialize
[cofx]
{:ethereum.subscriptions/new-block-filter nil})
[{:keys [db] :as cofx}]
(let [{:keys [:account/account :wallet/all-tokens network]} db
chain (ethereum/network->chain-keyword (get-in account [:networks network]))
chain-tokens (into {} (map (juxt :address identity)
(tokens/tokens-for all-tokens chain)))
padded-address (add-padding (ethereum/normalized-address (:address account)))]
{:ethereum.subscriptions/new-block nil
:ethereum.subscriptions/token-transactions {:chain-tokens chain-tokens
:address padded-address}}))

View File

@ -1,166 +1,19 @@
(ns status-im.models.transactions
(ns status-im.ethereum.transactions.core
(:require [clojure.set :as set]
[cljs.core.async :as async]
[clojure.string :as string]
[re-frame.core :as re-frame]
re-frame.db
[status-im.utils.async :as async-util]
[status-im.utils.ethereum.core :as ethereum]
[status-im.constants :as constants]
[status-im.native-module.core :as status]
[status-im.utils.ethereum.tokens :as tokens]
[status-im.utils.fx :as fx]
[status-im.utils.http :as http]
[status-im.utils.types :as types]
[taoensso.timbre :as log]
[status-im.utils.fx :as fx]
[re-frame.core :as re-frame]
[re-frame.db]
[status-im.utils.config :as config])
(:require-macros
[cljs.core.async.macros :refer [go-loop go]]))
[taoensso.timbre :as log]))
(def sync-interval-ms 15000)
(def sync-timeout-ms 20000)
(def confirmations-count-threshold 12)
(def block-query-limit 100000)
;; ----------------------------------------------------------------------------
;; token transfer event logs from eth-node
;; ----------------------------------------------------------------------------
(defn- parse-json [s]
{:pre [(string? s)]}
(try
(let [res (-> s
js/JSON.parse
(js->clj :keywordize-keys true))]
(if (= (:error res) "")
{:result true}
res))
(catch :default e
{:error (.-message e)})))
(defn- add-padding [address]
{:pre [(string? address)]}
(str "0x000000000000000000000000" (subs address 2)))
(defn- remove-padding [topic]
{:pre [(string? topic)]}
(str "0x" (subs topic 26)))
(defn- parse-transaction-entries [current-block-number block-info chain-tokens direction transfers]
{:pre [(integer? current-block-number) (map? block-info)
(map? chain-tokens) (every? (fn [[k v]] (and (string? k) (map? v))) chain-tokens)
(keyword? direction)
(every? map? transfers)]}
(into {}
(keep identity
(for [transfer transfers]
(when-let [token (->> transfer :address (get chain-tokens))]
(when-not (:nft? token)
[(:transactionHash transfer)
{:block (-> block-info :number str)
:hash (:transactionHash transfer)
:symbol (:symbol token)
:from (some-> transfer :topics second remove-padding)
:to (some-> transfer :topics last remove-padding)
:value (-> transfer :data ethereum/hex->bignumber)
:type direction
:confirmations (str (- current-block-number (-> transfer :blockNumber ethereum/hex->int)))
:gas-price nil
:nonce nil
:data nil
:gas-limit nil
:timestamp (-> block-info :timestamp (* 1000) str)
:gas-used nil
;; NOTE(goranjovic) - metadata on the type of token: contains name, symbol, decimas, address.
:token token
;; NOTE(goranjovic) - if an event has been emitted, we can say there was no error
:error? false
;; NOTE(goranjovic) - just a flag we need when we merge this entry with the existing entry in
;; the app, e.g. transaction info with gas details, or a previous transfer entry with old
;; confirmations count.
:transfer true}]))))))
(defn- add-block-info [web3 current-block-number chain-tokens direction result success-fn]
{:pre [web3 (integer? current-block-number) (map? chain-tokens) (keyword? direction)
(every? map? result)
(fn? success-fn)]}
(let [transfers-by-block (group-by :blockNumber result)]
(doseq [[block-number transfers] transfers-by-block]
(ethereum/get-block-info web3 (ethereum/hex->int block-number)
(fn [block-info]
(if-not (map? block-info)
(log/error "Request for block info failed")
(success-fn (parse-transaction-entries current-block-number
block-info
chain-tokens
direction
transfers))))))))
(defn- response-handler [web3 current-block-number chain-tokens direction error-fn success-fn]
(fn handle-response
([response]
#_(log/debug "Token transaction logs recieved --" (pr-str response))
(let [{:keys [error result]} (parse-json response)]
(handle-response error result)))
([error result]
(if error
(error-fn error)
(add-block-info web3 current-block-number chain-tokens direction result success-fn)))))
(defn- limited-from-block [current-block-number latest-block-checked]
{:pre [(integer? current-block-number)]
;; needs to be a positive etherium hex
:post [(string? %) (string/starts-with? % "0x")]}
(if latest-block-checked
(-> latest-block-checked (- confirmations-count-threshold) ethereum/int->hex)
(-> current-block-number (- block-query-limit) (max 0) ethereum/int->hex)))
;; Here we are querying event logs for Transfer events.
;;
;; The parameters are as follows:
;; - address - token smart contract address
;; - fromBlock - we need to specify it, since default is latest
;; - topics[0] - hash code of the Transfer event signature
;; - topics[1] - address of token sender with leading zeroes padding up to 32 bytes
;; - topics[2] - address of token sender with leading zeroes padding up to 32 bytes
;;
(defonce latest-block-checked (atom nil))
(defn- get-token-transfer-logs
;; NOTE(goranjovic): here we use direct JSON-RPC calls to get event logs because of web3 event issues with infura
;; we still use web3 to get other data, such as block info
[web3 current-block-number from-block chain-tokens direction address cb]
{:pre [web3 (integer? current-block-number) (map? chain-tokens) (keyword? direction) (string? address) (fn? cb)]}
(let [[from to] (if (= :inbound direction)
[nil (add-padding (ethereum/normalized-address address))]
[(add-padding (ethereum/normalized-address address)) nil])
args {:jsonrpc "2.0"
:id 2
:method constants/web3-get-logs
:params [{:address (keys chain-tokens)
:fromBlock from-block
:topics [constants/event-transfer-hash from to]}]}
payload (.stringify js/JSON (clj->js args))]
(status/call-private-rpc payload
(response-handler web3 current-block-number chain-tokens direction ethereum/handle-error cb))))
(defn- get-token-transactions
[web3 chain-tokens address cb]
{:pre [web3 (map? chain-tokens) (string? address) (fn? cb)]}
(ethereum/get-block-number web3
(fn [current-block-number]
(let [from-block (limited-from-block current-block-number @latest-block-checked)]
(reset! latest-block-checked current-block-number)
(get-token-transfer-logs web3 current-block-number from-block chain-tokens :inbound address cb)
(get-token-transfer-logs web3 current-block-number from-block chain-tokens :outbound address cb)))))
;; --------------------------------------------------------------------------
;; etherscan transactions
@ -199,8 +52,7 @@
(defn- format-transaction [account
{:keys [value timeStamp blockNumber hash from to
gas gasPrice gasUsed nonce confirmations
input isError]}]
gas gasPrice gasUsed nonce input isError]}]
(let [inbound? (= (str "0x" account) to)
error? (= "1" isError)]
{:value value
@ -218,7 +70,6 @@
:gas-price gasPrice
:gas-used gasUsed
:nonce nonce
:confirmations confirmations
:data input}))
(defn- format-transactions-response [response account]
@ -249,11 +100,7 @@
account-address
success-fn
error-fn
chaos-mode?)
(get-token-transactions web3
chain-tokens
account-address
success-fn))
chaos-mode?))
;; -----------------------------------------------------------------------------
;; Helpers functions that help determine if a background sync should execute
@ -302,21 +149,8 @@
(map :tx-hash)
set))))
;; Seq[transaction] -> truthy
(defn- have-unconfirmed-transactions?
"Detects if some of the transactions have less than 12 confirmations"
[transactions]
{:pre [(every? string? (map :confirmations transactions))]}
(->> transactions
(map :confirmations)
(map int)
(some #(< % confirmations-count-threshold))))
(letfn [(combine-entries [transaction token-transfer]
(merge transaction (select-keys token-transfer [:symbol :from :to :value :type :token :transfer])))
(update-confirmations [tx1 tx2]
(assoc tx1 :confirmations (str (max (int (:confirmations tx1))
(int (:confirmations tx2))))))
(tx-and-transfer? [tx1 tx2]
(and (not (:transfer tx1)) (:transfer tx2)))
(both-transfer?
@ -325,7 +159,6 @@
(defn- dedupe-transactions [tx1 tx2]
(cond (tx-and-transfer? tx1 tx2) (combine-entries tx1 tx2)
(tx-and-transfer? tx2 tx1) (combine-entries tx2 tx1)
(both-transfer? tx1 tx2) (update-confirmations tx1 tx2)
:else tx2)))
;; ----------------------------------------------------------------------------
@ -382,14 +215,11 @@
transaction-map (:transactions wallet)
transaction-ids (set (keys transaction-map))
chaos-mode? (get-in account [:settings :chaos-mode?])]
(if-not (or @latest-block-checked
(have-unconfirmed-transactions? (vals transaction-map))
(not-empty (set/difference chat-transaction-ids transaction-ids)))
(if-not (not-empty (set/difference chat-transaction-ids transaction-ids))
(done-fn)
(transactions-query-helper web3 all-tokens account-address chain done-fn chaos-mode?))))))
(defn- start-sync! [{:keys [:account/account network web3] :as options}]
(reset! latest-block-checked nil)
(let [account-address (:address account)]
(when @polling-executor
(async-util/async-periodic-stop! @polling-executor))

View File

@ -2054,17 +2054,6 @@
(fn [cofx _]
(bottom-sheet/hide-bottom-sheet cofx)))
;; ethereum subscriptions events
(handlers/register-handler-fx
:ethereum.callback/subscription-success
(fn [cofx [_ id handler]]
(ethereum.subscriptions/register-subscription cofx id handler)))
(handlers/register-handler-fx
:ethereum.signal/new-block
(fn [cofx [_ block-number]]
(ethereum.subscriptions/new-block cofx block-number)))
;;custom tokens
(handlers/register-handler-fx
@ -2120,4 +2109,21 @@
(fx/merge cofx
(custom-tokens/remove-custom-token token)
(when navigate-back?
(navigation/navigate-back)))))
(navigation/navigate-back)))))
;; ethereum subscriptions events
(handlers/register-handler-fx
:ethereum.callback/subscription-success
(fn [cofx [_ id handler]]
(ethereum.subscriptions/register-subscription cofx id handler)))
(handlers/register-handler-fx
:ethereum.signal/new-block
(fn [cofx [_ block-number]]
(ethereum.subscriptions/new-block cofx block-number)))
(handlers/register-handler-fx
:ethereum.signal/new-transactions
(fn [cofx [_ transactions]]
(ethereum.subscriptions/new-transactions cofx transactions)))

View File

@ -1,37 +1,28 @@
(ns status-im.init.core
(:require [re-frame.core :as re-frame]
[status-im.chat.models.loading :as chat-loading]
[status-im.accounts.core :as accounts.core]
[status-im.accounts.login.core :as accounts.login]
[status-im.accounts.update.core :as accounts.update]
[status-im.constants :as constants]
[status-im.react-native.js-dependencies :as rn-dependencies]
[status-im.browser.core :as browser]
[status-im.chat.models :as chat-model]
[status-im.contact.core :as contact]
[status-im.data-store.core :as data-store]
[status-im.data-store.realm.core :as realm]
[status-im.extensions.registry :as extensions.registry]
[status-im.i18n :as i18n]
[status-im.browser.core :as browser]
[status-im.contact.core :as contact]
[status-im.models.dev-server :as models.dev-server]
[status-im.protocol.core :as protocol]
[status-im.pairing.core :as pairing]
[status-im.models.transactions :as transactions]
[status-im.models.wallet :as models.wallet]
[status-im.native-module.core :as status]
[status-im.node.core :as node]
[status-im.notifications.core :as notifications]
[status-im.pairing.core :as pairing]
[status-im.react-native.js-dependencies :as rn-dependencies]
[status-im.stickers.core :as stickers]
[status-im.ui.screens.db :refer [app-db]]
[status-im.ui.screens.navigation :as navigation]
[status-im.utils.config :as config]
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.fx :as fx]
[status-im.utils.keychain.core :as keychain]
[status-im.utils.platform :as platform]
[status-im.utils.utils :as utils]
[taoensso.timbre :as log]
[status-im.utils.fx :as fx]
[status-im.chat.models :as chat-model]
[status-im.accounts.db :as accounts.db]
[status-im.stickers.core :as stickers]))
[taoensso.timbre :as log]))
(defn init-store!
"Try to decrypt the database, move on if successful otherwise go back to

View File

@ -74,4 +74,5 @@
"messages.decrypt.failed" (contact-recovery/handle-contact-recovery-fx cofx (:sender event))
"discovery.summary" (summary cofx event)
"subscriptions.data" (ethereum.subscriptions/handle-signal cofx event)
"subscriptions.error" (ethereum.subscriptions/handle-error cofx event)
(log/debug "Event " type " not handled"))))

View File

@ -10,9 +10,9 @@
[status-im.chat.db :as chat.db]
[status-im.constants :as constants]
[status-im.contact.db :as contact.db]
[status-im.ethereum.transactions.core :as transactions]
[status-im.fleet.core :as fleet]
[status-im.i18n :as i18n]
[status-im.models.transactions :as transactions]
[status-im.models.wallet :as models.wallet]
[status-im.ui.components.bottom-bar.styles :as tabs.styles]
[status-im.ui.components.toolbar.styles :as toolbar.styles]

View File

@ -1,19 +1,19 @@
(ns status-im.ui.screens.wallet.events
(:require [re-frame.core :as re-frame]
[status-im.models.transactions :as wallet.transactions]
[status-im.ethereum.transactions.core :as transactions]
[status-im.i18n :as i18n]
[status-im.models.wallet :as models]
[status-im.ui.screens.navigation :as navigation]
status-im.ui.screens.wallet.navigation
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.ethereum.erc20 :as erc20]
[status-im.utils.ethereum.tokens :as tokens]
[status-im.utils.fx :as fx]
[status-im.utils.handlers :as handlers]
[status-im.utils.money :as money]
[status-im.utils.prices :as prices]
[taoensso.timbre :as log]
[status-im.utils.fx :as fx]
[status-im.i18n :as i18n]
[status-im.utils.utils :as utils.utils]))
[status-im.utils.utils :as utils.utils]
[taoensso.timbre :as log]))
(defn get-balance [{:keys [web3 account-id on-success on-error]}]
(if (and web3 account-id)
@ -146,7 +146,7 @@
(handlers/register-handler-fx
:update-transactions
(fn [{:keys [db]} _]
{::wallet.transactions/sync-transactions-now
{::transactions/sync-transactions-now
(select-keys db [:network-status :account/account :wallet/all-tokens
:app-state :network :web3])}))

View File

@ -1,13 +1,11 @@
(ns status-im.ui.screens.wallet.send.events
(:require [re-frame.core :as re-frame]
[status-im.chat.commands.sending :as commands-sending]
[status-im.chat.models.message :as models.message]
[status-im.chat.models :as chat.models]
[status-im.constants :as constants]
[status-im.i18n :as i18n]
[status-im.models.transactions :as wallet.transactions]
[status-im.models.wallet :as models.wallet]
[status-im.native-module.core :as status]
[status-im.transport.utils :as transport.utils]
[status-im.ui.screens.navigation :as navigation]
[status-im.ui.screens.wallet.db :as wallet.db]
[status-im.utils.ethereum.core :as ethereum]
@ -18,10 +16,7 @@
[status-im.utils.money :as money]
[status-im.utils.security :as security]
[status-im.utils.types :as types]
[status-im.utils.utils :as utils]
[status-im.utils.config :as config]
[status-im.transport.utils :as transport.utils]
[status-im.hardwallet.core :as hardwallet]))
[status-im.utils.utils :as utils]))
;;;; FX

View File

@ -2,11 +2,11 @@
"The main purpose of these tests is to signal that some steps of the sign in
flow has been changed. Such changes should be reflected in both these tests
and documents which describe the whole \"sign in\" flow."
(:require [cljs.test :refer-macros [deftest is are testing]]
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.accounts.login.core :as login.core]
[status-im.events :as events]
[status-im.test.sign-in.data :as data]
[status-im.signals.core :as signals]))
[status-im.signals.core :as signals]
[status-im.test.sign-in.data :as data]))
(deftest on-password-input-submitted
(testing
@ -205,7 +205,7 @@
(is (contains? efx :web3/get-syncing))
(is (contains? efx :get-tokens-balance))
(is (contains? efx :get-prices))
(is (contains? efx :status-im.models.transactions/start-sync-transactions))))))
(is (contains? efx :status-im.ethereum.transactions.core/start-sync-transactions))))))
(deftest login-failed
(testing

View File

@ -1,21 +1,8 @@
(ns status-im.test.wallet.transactions
(:require [cljs.test :refer-macros [deftest is testing async run-tests]]
[cljs.core.async.impl.protocols :refer [closed?]]
[status-im.utils.datetime :as time]
[status-im.utils.http :as http]
[status-im.models.transactions :as transactions]
[goog.Uri :as goog-uri]))
(deftest have-unconfirmed-transactions
(is (transactions/have-unconfirmed-transactions?
[{:confirmations "0"}]))
(is (transactions/have-unconfirmed-transactions?
[{:confirmations "11"}]))
(is (transactions/have-unconfirmed-transactions?
[{:confirmations "200"}
{:confirmations "0"}]))
(is (not (transactions/have-unconfirmed-transactions?
[{:confirmations "12"}]))))
(:require [cljs.test :refer-macros [deftest is]]
[goog.Uri :as goog-uri]
[status-im.ethereum.transactions.core :as transactions]
[status-im.utils.http :as http]))
(deftest chat-map->transaction-ids
(is (= #{} (transactions/chat-map->transaction-ids "testnet_rpc" {})))
@ -222,7 +209,7 @@
(deftest etherscan-transactions
(let [ky-set #{:block :hash :symbol :gas-price :value :gas-limit :type
:confirmations :gas-used :from :timestamp :nonce :to :data}]
:gas-used :from :timestamp :nonce :to :data}]
(with-redefs [http/get (fn [url success-fn error-fn]
(success-fn mock-etherscan-success-response))]
(let [result (atom nil)]