[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:
parent
8c349a3038
commit
f5c18ae7a9
|
@ -1,3 +1,3 @@
|
|||
## DO NOT EDIT THIS FILE BY HAND. USE `scripts/update-status-go.sh <tag>` instead
|
||||
|
||||
0cj202bj2rwfrw327gibj8hj8i94ciyp3hkq2hck9l6711qlhpnb
|
||||
0049i6znvl45hc651bqyzwgmzlv0fp40maggfjsrv13q5avd0g6d
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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}]
|
||||
|
|
|
@ -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}}))
|
||||
|
|
|
@ -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))
|
|
@ -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)))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"))))
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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])}))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)]
|
||||
|
|
Loading…
Reference in New Issue