diff --git a/resources/icons/exclamation_mark.svg b/resources/icons/exclamation_mark.svg
index d0e7dd1c8f..47919eff22 100644
--- a/resources/icons/exclamation_mark.svg
+++ b/resources/icons/exclamation_mark.svg
@@ -1,3 +1,6 @@
-
+
\ No newline at end of file
diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs
index 34366daab6..c1d25bce46 100644
--- a/src/status_im/constants.cljs
+++ b/src/status_im/constants.cljs
@@ -33,6 +33,7 @@
{:type [{:id :inbound :label (i18n/label :t/incoming) :checked? true}
{:id :outbound :label (i18n/label :t/outgoing) :checked? true}
{:id :pending :label (i18n/label :t/pending) :checked? true}
+ {:id :failed :label (i18n/label :t/failed) :checked? true}
;; TODO(jeluard) Restore once we support postponing transaction
#_{:id :postponed :label (i18n/label :t/postponed) :checked? true}]}})
diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs
index 1d74a9018f..8eda46e9aa 100644
--- a/src/status_im/translations/en.cljs
+++ b/src/status_im/translations/en.cljs
@@ -405,6 +405,7 @@
:incoming "Incoming"
:outgoing "Outgoing"
:pending "Pending"
+ :failed "Failed"
:postponed "Postponed"
;;webview
diff --git a/src/status_im/ui/components/colors.cljs b/src/status_im/ui/components/colors.cljs
index 234949059f..179b2ec164 100644
--- a/src/status_im/ui/components/colors.cljs
+++ b/src/status_im/ui/components/colors.cljs
@@ -24,6 +24,7 @@
(def text-light-gray "#212121") ;; Used for labels (home items)
(def cyan "#7adcfb") ;; Used by wallet transaction filtering icon
(def photo-border-color "#ccd3d6")
+(def green "#44d058") ;; icon for successful inboud transaction
(def chat-colors ["#fa6565"
"#7cda00"
diff --git a/src/status_im/ui/components/icons/vector_icons.cljs b/src/status_im/ui/components/icons/vector_icons.cljs
index 87c8f8a907..b0f031a236 100644
--- a/src/status_im/ui/components/icons/vector_icons.cljs
+++ b/src/status_im/ui/components/icons/vector_icons.cljs
@@ -52,7 +52,7 @@
:icons/delete (components.svg/slurp-svg "./resources/icons/delete.svg")
:icons/dots-horizontal (components.svg/slurp-svg "./resources/icons/dots_horizontal.svg")
:icons/dots-vertical (components.svg/slurp-svg "./resources/icons/dots_vertical.svg")
- :icons/exclamation_mark (components.svg/slurp-svg "./resources/icons/exclamation_mark.svg")
+ :icons/exclamation-mark (components.svg/slurp-svg "./resources/icons/exclamation_mark.svg")
:icons/filter (components.svg/slurp-svg "./resources/icons/filter.svg")
:icons/fullscreen (components.svg/slurp-svg "./resources/icons/fullscreen.svg")
:icons/group-big (components.svg/slurp-svg "./resources/icons/group_big.svg")
diff --git a/src/status_im/ui/screens/wallet/transactions/styles.cljs b/src/status_im/ui/screens/wallet/transactions/styles.cljs
index 6735efb694..06a0fb32d8 100644
--- a/src/status_im/ui/screens/wallet/transactions/styles.cljs
+++ b/src/status_im/ui/screens/wallet/transactions/styles.cljs
@@ -50,6 +50,9 @@
:ios {:padding-top 13}
:android {:padding-top 14}})
+(def amount-text
+ {:color colors/text})
+
(def tx-amount
{:flex-grow 1
:flex-shrink 1
@@ -185,13 +188,17 @@
:margin-vertical 10
:height 2})
-(defn progress-bar-done [done]
+(defn progress-bar-done [done failed?]
{:flex done
- :background-color colors/blue})
+ :background-color (if failed?
+ colors/red
+ colors/blue)})
-(defn progress-bar-todo [todo]
+(defn progress-bar-todo [todo failed?]
{:flex todo
- :background-color colors/blue
+ :background-color (if failed?
+ colors/red
+ colors/blue)
:opacity 0.30})
(def details-confirmations-count
@@ -199,6 +206,11 @@
:font-size 15
:margin-vertical 2})
+(def details-failed
+ {:color colors/red
+ :font-size 15
+ :margin-vertical 2})
+
(def details-confirmations-helper-text
{:color colors/gray
:font-size 14
diff --git a/src/status_im/ui/screens/wallet/transactions/subs.cljs b/src/status_im/ui/screens/wallet/transactions/subs.cljs
index b641535448..8cbd71b223 100644
--- a/src/status_im/ui/screens/wallet/transactions/subs.cljs
+++ b/src/status_im/ui/screens/wallet/transactions/subs.cljs
@@ -78,16 +78,24 @@
(fn [{:keys [postponed]}]
(when postponed
{:title "Postponed"
- :key :postponed
- :data postponed})))
+ :key :postponed
+ :data postponed})))
(reg-sub :wallet.transactions/pending-transactions-list
:<- [:wallet.transactions/grouped-transactions]
(fn [{:keys [pending]}]
(when pending
{:title "Pending"
- :key :pending
- :data pending})))
+ :key :pending
+ :data pending})))
+
+(reg-sub :wallet.transactions/failed-transactions-list
+ :<- [:wallet.transactions/grouped-transactions]
+ (fn [{:keys [failed]}]
+ (when failed
+ {:title "Failed"
+ :key :failed
+ :data failed})))
(defn group-transactions-by-date [transactions]
(->> transactions
@@ -101,8 +109,8 @@
(reg-sub :wallet.transactions/completed-transactions-list
:<- [:wallet.transactions/grouped-transactions]
- (fn [{:keys [inbound outbound]}]
- (group-transactions-by-date (into inbound outbound))))
+ (fn [{:keys [inbound outbound failed]}]
+ (group-transactions-by-date (concat inbound outbound failed))))
(reg-sub :wallet.transactions/transactions-history-list
:<- [:wallet.transactions/postponed-transactions-list]
diff --git a/src/status_im/ui/screens/wallet/transactions/views.cljs b/src/status_im/ui/screens/wallet/transactions/views.cljs
index 7c27dc854e..f89499bcab 100644
--- a/src/status_im/ui/screens/wallet/transactions/views.cljs
+++ b/src/status_im/ui/screens/wallet/transactions/views.cljs
@@ -6,6 +6,7 @@
[status-im.ui.components.react :as react]
[status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.styles :as components.styles]
+ [status-im.ui.components.colors :as colors]
[status-im.ui.components.toolbar.actions :as actions]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.ui.components.status-bar.view :as status-bar]
@@ -33,6 +34,7 @@
[(history-action (not (all-checked? filter-data)))]]])
(defn- inbound? [type] (= :inbound type))
+(defn- failed? [type] (= :failed type))
(defn- transaction-icon [k background-color color]
{:icon k
@@ -41,12 +43,13 @@
(defn- transaction-type->icon [k]
(case k
- :inbound (transaction-icon :icons/arrow-left components.styles/color-green-3-light components.styles/color-green-3)
- :outbound (transaction-icon :icons/arrow-right components.styles/color-blue4-transparent components.styles/color-blue4)
- (:postponed :pending) (transaction-icon :icons/arrow-right components.styles/color-gray4-transparent components.styles/color-gray7)
+ :inbound (transaction-icon :icons/arrow-left (colors/alpha colors/green 0.2) colors/green)
+ :outbound (transaction-icon :icons/arrow-right (colors/alpha colors/blue 0.1) colors/blue)
+ :failed (transaction-icon :icons/exclamation-mark colors/gray-light colors/red)
+ (:postponed :pending) (transaction-icon :icons/arrow-right colors/gray-light colors/gray)
(throw (str "Unknown transaction type: " k))))
-(defn render-transaction [{:keys [hash from-contact to-contact to from type value time-formatted symbol] :as transaction} network]
+(defn render-transaction [{:keys [hash from-contact to-contact to from type value time-formatted symbol]} network]
(let [[label contact address
contact-accessibility-label
address-accessibility-label] (if (inbound? type)
@@ -62,7 +65,8 @@
[react/text {:style styles/tx-amount
:ellipsize-mode "tail"
:number-of-lines 1}
- [react/text {:accessibility-label :amount-text}
+ [react/text {:accessibility-label :amount-text
+ :style styles/amount-text}
(-> value (money/internal->formatted symbol decimals) money/to-fixed str)]
" "
[react/text {:accessibility-label :currency-text}
@@ -170,16 +174,19 @@
(clojure.string/upper-case (name symbol))]]
[react/text {:style styles/details-header-date} date]]])
-(defn progress-bar [progress]
+(defn progress-bar [progress failed?]
[react/view {:style styles/progress-bar}
- [react/view {:style (styles/progress-bar-done progress)}]
- [react/view {:style (styles/progress-bar-todo (- 100 progress))}]])
+ [react/view {:style (styles/progress-bar-done progress failed?)}]
+ [react/view {:style (styles/progress-bar-todo (- 100 progress) failed?)}]])
-(defn details-confirmations [confirmations confirmations-progress]
+(defn details-confirmations [confirmations confirmations-progress type]
[react/view {:style styles/details-block}
- [progress-bar confirmations-progress]
- [react/text {:style styles/details-confirmations-count}
- (str confirmations " " (i18n/label :t/confirmations))]
+ [progress-bar confirmations-progress (failed? type)]
+ (if (failed? type)
+ [react/text {:style styles/details-failed}
+ (i18n/label :t/failed)]
+ [react/text {:style styles/details-confirmations-count}
+ (str confirmations " " (i18n/label :t/confirmations))])
[react/text {:style styles/details-confirmations-helper-text}
(i18n/label :t/confirmations-helper-text)]])
@@ -232,9 +239,9 @@
{:label (i18n/label :t/open-on-etherscan) :action #(.openURL react/linking url)}])])
(defview transaction-details []
- (letsubs [{:keys [hash url] :as transaction} [:wallet.transactions/transaction-details]
- confirmations [:wallet.transactions.details/confirmations]
- confirmations-progress [:wallet.transactions.details/confirmations-progress]]
+ (letsubs [{:keys [hash url type] :as transaction} [:wallet.transactions/transaction-details]
+ confirmations [:wallet.transactions.details/confirmations]
+ confirmations-progress [:wallet.transactions.details/confirmations-progress]]
[react/view {:style components.styles/flex}
[status-bar/status-bar]
[toolbar/toolbar {}
@@ -243,6 +250,6 @@
(when transaction [toolbar/actions (details-action hash url)])]
[react/scroll-view {:style components.styles/main-container}
[details-header transaction]
- [details-confirmations confirmations confirmations-progress]
+ [details-confirmations confirmations confirmations-progress type]
[react/view {:style styles/details-separator}]
[details-list transaction]]]))
diff --git a/src/status_im/utils/ethereum/erc20.cljs b/src/status_im/utils/ethereum/erc20.cljs
index 060d25acfb..716f1950f4 100644
--- a/src/status_im/utils/ethereum/erc20.cljs
+++ b/src/status_im/utils/ethereum/erc20.cljs
@@ -84,35 +84,39 @@
(defn- parse-transaction-entries [current-block-number block-info chain direction transfers]
(into {}
- (for [transfer transfers]
- (let [token (->> transfer :address (tokens/address->token chain))]
- [(:transactionHash transfer)
- {:block (-> block-info :number str)
- :hash (:transactionHash transfer)
- :symbol (:symbol token)
- :from (-> transfer :topics second remove-padding)
- :to (-> transfer :topics last remove-padding)
- :value (-> transfer :data ethereum/hex->bignumber)
- :type direction
+ (keep identity
+ (for [transfer transfers]
+ (if-let [token (->> transfer :address (tokens/address->token chain))]
+ [(:transactionHash transfer)
+ {:block (-> block-info :number str)
+ :hash (:transactionHash transfer)
+ :symbol (:symbol token)
+ :from (-> transfer :topics second remove-padding)
+ :to (-> transfer :topics last remove-padding)
+ :value (-> transfer :data ethereum/hex->bignumber)
+ :type direction
- :confirmations (str (- current-block-number (-> transfer :blockNumber ethereum/hex->int)))
+ :confirmations (str (- current-block-number (-> transfer :blockNumber ethereum/hex->int)))
- :gas-price nil
- :nonce nil
- :data nil
+ :gas-price nil
+ :nonce nil
+ :data nil
- :gas-limit nil
- :timestamp (-> block-info :timestamp (* 1000) str)
+ :gas-limit nil
+ :timestamp (-> block-info :timestamp (* 1000) str)
- :gas-used nil
+ :gas-used nil
- ;; NOTE(goranjovic) - metadata on the type of token in question: contains name, symbol, decimas, address.
- :token token
+ ;; NOTE(goranjovic) - metadata on the type of token: contains name, symbol, decimas, address.
+ :token token
- ;; 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}]))))
+ ;; 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 direction result success-fn]
(let [transfers-by-block (group-by :blockNumber result)]
diff --git a/src/status_im/utils/transactions.cljs b/src/status_im/utils/transactions.cljs
index 3c88d2d813..5b6be83af4 100644
--- a/src/status_im/utils/transactions.cljs
+++ b/src/status_im/utils/transactions.cljs
@@ -25,23 +25,26 @@
(str "https://" network-subdomain ".etherscan.io/api?module=account&action=txlist&address=0x"
account "&startblock=0&endblock=99999999&sort=desc&apikey=" etherscan-api-key "?q=json")))
-(defn- format-transaction [account {:keys [value timeStamp blockNumber hash from to gas gasPrice gasUsed nonce confirmations input]}]
- (let [inbound? (= (str "0x" account) to)]
- {:value value
+(defn- format-transaction [account {:keys [value timeStamp blockNumber hash from to gas gasPrice gasUsed nonce confirmations input isError]}]
+ (let [inbound? (= (str "0x" account) to)
+ error? (= "1" isError)]
+ {:value value
;; timestamp is in seconds, we convert it in ms
- :timestamp (str timeStamp "000")
- :symbol :ETH
- :type (if inbound? :inbound :outbound)
- :block blockNumber
- :hash hash
- :from from
- :to to
- :gas-limit gas
- :gas-price gasPrice
- :gas-used gasUsed
- :nonce nonce
+ :timestamp (str timeStamp "000")
+ :symbol :ETH
+ :type (cond error? :failed
+ inbound? :inbound
+ :else :outbound)
+ :block blockNumber
+ :hash hash
+ :from from
+ :to to
+ :gas-limit gas
+ :gas-price gasPrice
+ :gas-used gasUsed
+ :nonce nonce
:confirmations confirmations
- :data input}))
+ :data input}))
(defn- format-transactions-response [response account]
(->> response