Wrong number of collectibles in the list and they are mixed up [#4904]

Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
This commit is contained in:
Andrey Shovkoplyas 2018-07-02 15:01:52 +03:00
parent 4c3b9e1555
commit ee317c4aeb
No known key found for this signature in database
GPG Key ID: EAAB7C8622D860A4
30 changed files with 298 additions and 225 deletions

2
.env
View File

@ -17,4 +17,4 @@ DEBUG_WEBVIEW=1
INSTABUG_SURVEYS=1
GROUP_CHATS_ENABLED=0
USE_SYM_KEY=0
SPAM_BUTTON_DETECTION_ENABLED=1
SPAM_BUTTON_DETECTION_ENABLED=1

View File

@ -16,4 +16,4 @@ INSTABUG_TOKEN=758630ed52864cbad9c5eeeac596c60c
DEBUG_WEBVIEW=1
INSTABUG_SURVEYS=0
GROUP_CHATS_ENABLED=1
USE_SYM_KEY=0
USE_SYM_KEY=0

View File

@ -18,4 +18,4 @@ INSTABUG_SURVEYS=1
GROUP_CHATS_ENABLED=0
USE_SYM_KEY=0
SPAM_BUTTON_DETECTION_ENABLED=1
MAINNET_WARNING_ENABLED=1
MAINNET_WARNING_ENABLED=1

View File

@ -17,4 +17,4 @@ DEBUG_WEBVIEW=1
INSTABUG_SURVEYS=1
GROUP_CHATS_ENABLED=0
SPAM_BUTTON_DETECTION_ENABLED=1
MAINNET_WARNING_ENABLED=1
MAINNET_WARNING_ENABLED=1

View File

@ -20,4 +20,4 @@ GROUP_CHATS_ENABLED=0
USE_SYM_KEY=0
MAINNET_WARNING_ENABLED=1
SPAM_BUTTON_DETECTION_ENABLED=1
UNIVERSAL_LINKS_ENABLED=0
UNIVERSAL_LINKS_ENABLED=0

View File

@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Added
- Added Farsi public #status channel
- Spam moderation
- Collectibles support (CryptoKitties, CryptoStrikers and Etheremon)
## [0.9.21] - 2018-06-25
### Added

View File

@ -1,7 +1,8 @@
(ns status-im.ui.components.svgimage
(:require [status-im.ui.components.react :as react]
[reagent.core :as reagent]
[status-im.utils.platform :as platform]))
[status-im.utils.platform :as platform]
[status-im.utils.http :as http]))
(defn html [uri width height]
(str
@ -38,7 +39,7 @@
(defn svgimage [{:keys [style source]}]
(let [width (reagent/atom nil)
{:keys [uri k] :or {k 1}} source]
(when (re-find #"^(https:)([/|.|\w|\s|-])*\.(?:jpg|svg|png)$" uri)
(when (http/url-sanitized? uri)
(fn []
[react/view {:style style
:on-layout #(reset! width (-> % .-nativeEvent .-layout .-width))}

View File

@ -114,7 +114,7 @@
(spec/def :navigation.screen-params/usage-data vector?)
(spec/def :navigation.screen-params/display-collectible map?)
(spec/def :navigation.screen-params/collectibles-list map?)
(spec/def :navigation/screen-params (spec/nilable (allowed-keys :opt-un [:navigation.screen-params/network-details
:navigation.screen-params/browser
@ -124,7 +124,7 @@
:navigation.screen-params/edit-contact-group
:navigation.screen-params/dapp-description
:navigation.screen-params/usage-data
:navigation.screen-params/display-collectible])))
:navigation.screen-params/collectibles-list])))
(spec/def :desktop/desktop (spec/nilable any?))

View File

@ -26,6 +26,9 @@
status-im.ui.screens.wallet.settings.events
status-im.ui.screens.wallet.transactions.events
status-im.ui.screens.wallet.choose-recipient.events
status-im.ui.screens.wallet.collectibles.cryptokitties.events
status-im.ui.screens.wallet.collectibles.cryptostrikers.events
status-im.ui.screens.wallet.collectibles.etheremon.events
status-im.ui.screens.browser.events
status-im.ui.screens.offline-messaging-settings.events
status-im.ui.screens.bootnodes-settings.events

View File

@ -25,7 +25,7 @@
[status-im.ui.screens.profile.contact.views :as profile.contact]
[status-im.ui.screens.profile.group-chat.views :as profile.group-chat]
[status-im.ui.screens.profile.photo-capture.views :refer [profile-photo-capture]]
[status-im.ui.screens.wallet.collectibles.views :as collectibles]
[status-im.ui.screens.wallet.collectibles.views :refer [collectibles-list]]
[status-im.ui.screens.wallet.send.views :refer [send-transaction send-transaction-modal sign-message-modal]]
[status-im.ui.screens.wallet.choose-recipient.views :refer [choose-recipient]]
[status-im.ui.screens.wallet.request.views :refer [request-transaction send-transaction-request]]
@ -54,7 +54,7 @@
(defn get-main-component [view-id]
(case view-id
:display-collectible collectibles/display-collectible
:collectibles-list collectibles-list
:intro intro
:create-account create-account
:usage-data usage-data

View File

@ -1,62 +0,0 @@
(ns status-im.ui.screens.wallet.collectibles.cryptokitties
(:require [re-frame.core :as re-frame]
[status-im.i18n :as i18n]
[status-im.ui.components.action-button.action-button :as action-button]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.react :as react]
[status-im.ui.screens.wallet.collectibles.views :as collectibles]
[status-im.ui.screens.wallet.collectibles.styles :as styles]
[status-im.utils.handlers :as handlers]
[status-im.utils.http :as http]
[status-im.ui.components.svgimage :as svgimage]))
(def ck :CK)
(handlers/register-handler-fx
:load-kitties
(fn [{db :db} [_ ids]]
{:db db
:http-get-n (mapv (fn [id]
{:url (str "https://api.cryptokitties.co/kitties/" id)
:success-event-creator (fn [o]
[:load-collectible-success ck {id (http/parse-payload o)}])
:failure-event-creator (fn [o]
[:load-collectible-failure ck {id (http/parse-payload o)}])})
ids)}))
(defn kitties-url [address]
(str "https://api.cryptokitties.co/kitties?offset=0&limit=20&owner_wallet_address=" address "&parents=false"))
(handlers/register-handler-fx
:load-kitties-success
(fn [{db :db} [_ ids]]
{:db db
:dispatch [:load-kitties ids]}))
;; TODO(julien) Each HTTP call will return up to 20 kitties. Make sure all extra kitties are fetched
(defmethod collectibles/load-collectibles-fx ck [_ _ _ address]
{:http-get {:url (kitties-url address)
:success-event-creator (fn [o]
[:load-kitties-success (map :id (:kitties (http/parse-payload o)))])
:failure-event-creator (fn [o]
[:load-collectibles-failure (http/parse-payload o)])
:timeout-ms 10000}})
(def base-url "https://www.cryptokitties.co/kitty/")
(defmethod collectibles/render-collectible ck [_ {:keys [id name bio image_url]}]
[react/view {:style styles/details}
[react/view {:style styles/details-text}
[svgimage/svgimage {:style styles/details-image
:source {:uri image_url}}]
[react/view {:flex 1}
[react/text {:style styles/details-name}
(or name (i18n/label :t/cryptokitty-name {:id id}))]
[react/text {:number-of-lines 3
:ellipsize-mode :tail}
bio]]]
[action-button/action-button {:label (i18n/label :t/view-cryptokitties)
:icon :icons/address
:icon-opts {:color colors/blue}
:accessibility-label :open-collectible-button
:on-press #(re-frame/dispatch [:open-browser {:url (str base-url id)}])}]])

View File

@ -0,0 +1,31 @@
(ns status-im.ui.screens.wallet.collectibles.cryptokitties.events
(:require [status-im.utils.handlers :as handlers]
[status-im.ui.screens.wallet.collectibles.events :as collectibles]
[status-im.utils.http :as http]))
(def ck :CK)
(handlers/register-handler-fx
:load-kitties
(fn [{db :db} [_ ids]]
{:db db
:http-get-n (mapv (fn [id]
{:url (str "https://api.cryptokitties.co/kitties/" id)
:success-event-creator (fn [o]
[:load-collectible-success ck {id (http/parse-payload o)}])
:failure-event-creator (fn [o]
[:load-collectible-failure ck {id (http/parse-payload o)}])})
ids)}))
;; TODO(andrey) Each HTTP call will return up to 100 kitties. Maybe we need to implement some kind of paging later
(defmethod collectibles/load-collectibles-fx ck [_ _ items-number address]
{:http-get {:url (str "https://api.cryptokitties.co/kitties?offset=0&limit="
items-number
"&owner_wallet_address="
address
"&parents=false")
:success-event-creator (fn [o]
[:load-kitties (map :id (:kitties (http/parse-payload o)))])
:failure-event-creator (fn [o]
[:load-collectibles-failure (http/parse-payload o)])
:timeout-ms 10000}})

View File

@ -0,0 +1,28 @@
(ns status-im.ui.screens.wallet.collectibles.cryptokitties.views
(:require [re-frame.core :as re-frame]
[status-im.i18n :as i18n]
[status-im.ui.components.action-button.action-button :as action-button]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.react :as react]
[status-im.ui.screens.wallet.collectibles.styles :as styles]
[status-im.ui.screens.wallet.collectibles.views :as collectibles]
[status-im.ui.components.svgimage :as svgimage]))
(defmethod collectibles/render-collectible :CK [_ {:keys [id name bio image_url]}]
[react/view {:style styles/details}
[react/view {:style styles/details-text}
[svgimage/svgimage {:style styles/details-image
:source {:uri image_url}}]
[react/view {:flex 1}
[react/text {:style styles/details-name}
(or name (i18n/label :t/cryptokitty-name {:id id}))]
[react/text {:number-of-lines 3
:ellipsize-mode :tail}
bio]]]
[action-button/action-button
{:label (i18n/label :t/view-cryptokitties)
:icon :icons/address
:icon-opts {:color colors/blue}
:accessibility-label :open-collectible-button
:on-press #(re-frame/dispatch [:open-browser
{:url (str "https://www.cryptokitties.co/kitty/" id)}])}]])

View File

@ -1,36 +0,0 @@
(ns status-im.ui.screens.wallet.collectibles.cryptostrikers
(:require [re-frame.core :as re-frame]
[status-im.i18n :as i18n]
[status-im.ui.components.action-button.action-button :as action-button]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.react :as react]
[status-im.ui.screens.wallet.collectibles.styles :as styles]
[status-im.ui.screens.wallet.collectibles.views :as collectibles]
[status-im.utils.http :as http]
[status-im.ui.components.svgimage :as svgimage]))
(def strikers :STRK)
(defmethod collectibles/load-collectible-fx strikers [_ id]
{:http-get {:url (str "https://us-central1-cryptostrikers-prod.cloudfunctions.net/cards/" id)
:success-event-creator (fn [o]
[:load-collectible-success strikers {id (http/parse-payload o)}])
:failure-event-creator (fn [o]
[:load-collectible-failure strikers {id (http/parse-payload o)}])}})
(defmethod collectibles/render-collectible strikers [_ {:keys [external_url description name image]}]
[react/view {:style styles/details}
[react/view {:style styles/details-text}
[svgimage/svgimage {:style styles/details-image
:source {:uri image
:k 1.4}}]
[react/view {:flex 1 :justify-content :center}
[react/text {:style styles/details-name}
name]
[react/text
description]]]
[action-button/action-button {:label (i18n/label :t/view-cryptostrikers)
:icon :icons/address
:icon-opts {:color colors/blue}
:accessibility-label :open-collectible-button
:on-press #(re-frame/dispatch [:open-browser {:url external_url}])}]])

View File

@ -0,0 +1,12 @@
(ns status-im.ui.screens.wallet.collectibles.cryptostrikers.events
(:require [status-im.ui.screens.wallet.collectibles.events :as collectibles]
[status-im.utils.http :as http]))
(def strikers :STRK)
(defmethod collectibles/load-collectible-fx strikers [_ id]
{:http-get {:url (str "https://us-central1-cryptostrikers-prod.cloudfunctions.net/cards/" id)
:success-event-creator (fn [o]
[:load-collectible-success strikers {id (http/parse-payload o)}])
:failure-event-creator (fn [o]
[:load-collectible-failure strikers {id (http/parse-payload o)}])}})

View File

@ -0,0 +1,27 @@
(ns status-im.ui.screens.wallet.collectibles.cryptostrikers.views
(:require [re-frame.core :as re-frame]
[status-im.i18n :as i18n]
[status-im.ui.components.action-button.action-button :as action-button]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.react :as react]
[status-im.ui.screens.wallet.collectibles.styles :as styles]
[status-im.ui.components.svgimage :as svgimage]
[status-im.ui.screens.wallet.collectibles.views :as collectibles]))
(defmethod collectibles/render-collectible :STRK [_ {:keys [external_url description name image]}]
[react/view {:style styles/details}
[react/view {:style styles/details-text}
[svgimage/svgimage {:style styles/details-image
:source {:uri image
:k 1.4}}]
[react/view {:flex 1 :justify-content :center}
[react/text {:style styles/details-name}
name]
[react/text
description]]]
[action-button/action-button
{:label (i18n/label :t/view-cryptostrikers)
:icon :icons/address
:icon-opts {:color colors/blue}
:accessibility-label :open-collectible-button
:on-press #(re-frame/dispatch [:open-browser {:url external_url}])}]])

View File

@ -1,37 +0,0 @@
(ns status-im.ui.screens.wallet.collectibles.etheremon
(:require [re-frame.core :as re-frame]
[status-im.i18n :as i18n]
[status-im.ui.components.action-button.action-button :as action-button]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.react :as react]
[status-im.ui.screens.wallet.collectibles.styles :as styles]
[status-im.ui.screens.wallet.collectibles.views :as collectibles]
[status-im.utils.http :as http]
[status-im.ui.components.svgimage :as svgimage]))
(def emona :EMONA)
(defmethod collectibles/load-collectible-fx emona [_ id]
{:http-get {:url (str "https://www.etheremon.com/api/monster/get_data?monster_ids=" id)
:success-event-creator (fn [o]
[:load-collectible-success emona (:data (http/parse-payload o))])
:failure-event-creator (fn [o]
[:load-collectible-failure emona {id (http/parse-payload o)}])}})
(def base-url "https://www.etheremon.com/#/mons/")
(defmethod collectibles/render-collectible emona [_ {:keys [monster_id user_defined_name image]}]
[react/view {:style styles/details}
[react/view {:style styles/details-text}
[react/view {:flex 1}
[svgimage/svgimage {:style styles/details-image
:source {:uri image
:k 2}}]]
[react/view {:flex 1 :justify-content :center}
[react/text {:style styles/details-name}
user_defined_name]]]
[action-button/action-button {:label (i18n/label :t/view-etheremon)
:icon :icons/address
:icon-opts {:color colors/blue}
:accessibility-label :open-collectible-button
:on-press #(re-frame/dispatch [:open-browser {:url (str base-url monster_id)}])}]])

View File

@ -0,0 +1,12 @@
(ns status-im.ui.screens.wallet.collectibles.etheremon.events
(:require [status-im.ui.screens.wallet.collectibles.events :as collectibles]
[status-im.utils.http :as http]))
(def emona :EMONA)
(defmethod collectibles/load-collectible-fx emona [_ id]
{:http-get {:url (str "https://www.etheremon.com/api/monster/get_data?monster_ids=" id)
:success-event-creator (fn [o]
[:load-collectible-success emona (:data (http/parse-payload o))])
:failure-event-creator (fn [o]
[:load-collectible-failure emona {id (http/parse-payload o)}])}})

View File

@ -0,0 +1,27 @@
(ns status-im.ui.screens.wallet.collectibles.etheremon.views
(:require [re-frame.core :as re-frame]
[status-im.i18n :as i18n]
[status-im.ui.components.action-button.action-button :as action-button]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.react :as react]
[status-im.ui.screens.wallet.collectibles.styles :as styles]
[status-im.ui.components.svgimage :as svgimage]
[status-im.ui.screens.wallet.collectibles.views :as collectibles]))
(defmethod collectibles/render-collectible :EMONA [_ {:keys [user_defined_name image class_id]}]
[react/view {:style styles/details}
[react/view {:style styles/details-text}
[react/view {:flex 1}
[svgimage/svgimage {:style styles/details-image
:source {:uri image
:k 2}}]]
[react/view {:flex 1 :justify-content :center}
[react/text {:style styles/details-name}
user_defined_name]]]
[action-button/action-button
{:label (i18n/label :t/view-etheremon)
:icon :icons/address
:icon-opts {:color colors/blue}
:accessibility-label :open-collectible-button
:on-press #(re-frame/dispatch [:open-browser
{:url (str "https://www.etheremon.com/#/mons/" class_id)}])}]])

View File

@ -1,6 +1,45 @@
(ns status-im.ui.screens.wallet.collectibles.events
(:require [re-frame.core :as re-frame]
[status-im.utils.handlers :as handlers]))
[status-im.utils.handlers :as handlers]
[status-im.utils.ethereum.erc721 :as erc721]
[status-im.utils.ethereum.tokens :as tokens]
[status-im.utils.money :as money]))
(defmulti load-collectible-fx (fn [symbol _] symbol))
(defmethod load-collectible-fx :default [_ _] nil)
(defmulti load-collectibles-fx (fn [_ symbol _ _] symbol))
(defmethod load-collectibles-fx :default [web3 symbol items-number address]
{:load-collectibles-fx [web3 symbol items-number address]})
(handlers/register-handler-fx
:show-collectibles-list
(fn [{:keys [db]} [_ address {:keys [symbol amount] :as collectible}]]
(let [items-number (money/to-number amount)
loaded-items-number (count (get-in db [:collectibles symbol]))]
(merge (when (not= items-number loaded-items-number)
(load-collectibles-fx (:web3 db) symbol items-number address))
{:dispatch [:navigate-to :collectibles-list collectible]}))))
(defn load-token [web3 i items-number contract address symbol]
(when (< i items-number)
(erc721/token-of-owner-by-index web3 contract address i
(fn [v1 v2]
(load-token web3 (inc i) items-number contract address symbol)
(re-frame/dispatch [:load-collectible symbol (.toNumber v2)])))))
(re-frame/reg-fx
:load-collectibles-fx
(fn [[web3 symbol items-number address]]
(let [contract (:address (tokens/symbol->token :mainnet symbol))]
(load-token web3 0 items-number contract address symbol))))
(handlers/register-handler-fx
:load-collectible
(fn [_ [_ symbol token-id]]
(load-collectible-fx symbol token-id)))
(handlers/register-handler-fx
:load-collectible-success

View File

@ -1,6 +1,11 @@
(ns status-im.ui.screens.wallet.collectibles.subs
(:require [re-frame.core :as re-frame]))
(re-frame/reg-sub :collectibles
(fn [db [_ s]]
(vals (get-in db [:collectibles s]))))
(re-frame/reg-sub :collectibles :collectibles)
(re-frame/reg-sub
:screen-collectibles
:<- [:collectibles]
:<- [:get-screen-params]
(fn [[collectibles {:keys [symbol]}]]
(mapv #(assoc (second %) :id (first %)) (get collectibles symbol))))

View File

@ -1,7 +1,6 @@
(ns status-im.ui.screens.wallet.collectibles.views
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :as re-frame]
[status-im.ui.components.colors :as colors]
(:require [status-im.ui.components.colors :as colors]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.react :as react]
[status-im.ui.components.status-bar.view :as status-bar]
@ -9,33 +8,24 @@
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.ui.screens.wallet.collectibles.styles :as styles]))
(defmulti load-collectible-fx (fn [symbol _] symbol))
(defmethod load-collectible-fx :default [_ _] nil)
(defmulti load-collectibles-fx (fn [_ symbol _ _] symbol))
(defmethod load-collectibles-fx :default [web3 symbol i address]
{:load-collectibles [web3 symbol i address]})
(defmulti render-collectible (fn [symbol _] symbol))
(defmethod render-collectible :default [symbol {:keys [id name]}]
[react/view {:style styles/default-collectible}
[react/text (str (clojure.core/name symbol) " #" (or id name))]])
(defview display-collectible []
(letsubs [{:keys [name symbol]} [:get-screen-params]]
(let [collectibles @(re-frame/subscribe [:collectibles symbol])]
[react/view {:style component.styles/flex}
(if (seq collectibles)
[react/view {:style component.styles/flex}
[status-bar/status-bar]
[toolbar/toolbar {}
toolbar/default-nav-back
[toolbar/content-title name]]
[list/flat-list {:data collectibles
:key-fn (comp str :id)
:render-fn #(render-collectible symbol %)}]]
[react/view {:style styles/loading-indicator}
[react/activity-indicator {:animating true :size :large :color colors/blue}]])])))
(defview collectibles-list []
(letsubs [{:keys [name symbol]} [:get-screen-params]
collectibles [:screen-collectibles]]
[react/view {:style component.styles/flex}
[react/view {:style component.styles/flex}
[status-bar/status-bar]
[toolbar/toolbar {}
toolbar/default-nav-back
[toolbar/content-title name]]
(if (seq collectibles)
[list/flat-list {:data collectibles
:key-fn (comp str :id)
:render-fn #(render-collectible symbol %)}]
[react/view {:style styles/loading-indicator}
[react/activity-indicator {:animating true :size :large :color colors/blue}]])]]))

View File

@ -14,8 +14,6 @@
status-im.ui.screens.wallet.request.events
[status-im.constants :as constants]
[status-im.ui.screens.navigation :as navigation]
[status-im.ui.screens.wallet.collectibles.views :as collectibles]
[status-im.utils.ethereum.erc721 :as erc721]
[status-im.utils.money :as money]))
(defn get-balance [{:keys [web3 account-id on-success on-error]}]
@ -281,23 +279,4 @@
(fn [{:keys [db]}]
{:db (-> db
(assoc-in [:wallet :send-transaction] {})
(navigation/navigate-back))}))
(handlers/register-handler-fx
:wallet/show-collectibles
(fn [{:keys [db]} [_ i address {:keys [symbol] :as m}]]
(assoc (collectibles/load-collectibles-fx (:web3 db) symbol i address)
:dispatch [:navigate-to :display-collectible m])))
(re-frame/reg-fx
:load-collectibles
(fn [[web3 symbol i address]]
(dotimes [n i]
(erc721/token-of-owner-by-index web3 (:address (tokens/symbol->token :mainnet symbol)) address n
#(re-frame/dispatch [:load-collectible symbol (.toNumber %2)])))))
(handlers/register-handler-fx
:load-collectible
(fn [{db :db} [_ symbol id]]
(assoc (collectibles/load-collectible-fx symbol id)
:db db)))
(navigation/navigate-back))}))

View File

@ -11,9 +11,9 @@
[status-im.ui.screens.wallet.styles :as styles]
[status-im.ui.screens.wallet.utils :as wallet.utils]
[status-im.utils.money :as money]
status-im.ui.screens.wallet.collectibles.cryptokitties
status-im.ui.screens.wallet.collectibles.cryptostrikers
status-im.ui.screens.wallet.collectibles.etheremon))
status-im.ui.screens.wallet.collectibles.etheremon.views
status-im.ui.screens.wallet.collectibles.cryptostrikers.views
status-im.ui.screens.wallet.collectibles.cryptokitties.views))
(defn toolbar-view []
[toolbar/toolbar {:style styles/toolbar :flat? true}
@ -88,11 +88,12 @@
[list/item-icon {:icon :icons/forward
:icon-opts {:color :gray}}])
(defn- render-collectible [address-hex {:keys [symbol name icon amount] :as m}]
(let [i (money/to-fixed amount)
details? (pos? i)]
[react/touchable-highlight (when details?
{:on-press #(re-frame/dispatch [:wallet/show-collectibles i address-hex m])})
(defn- render-collectible [address-hex {:keys [symbol name icon amount] :as collectible}]
(let [items-number (money/to-fixed amount)
details? (pos? items-number)]
[react/touchable-highlight
(when details?
{:on-press #(re-frame/dispatch [:show-collectibles-list address-hex collectible])})
[react/view {:style styles/asset-item-container}
[list/item
[list/item-image icon]
@ -100,8 +101,9 @@
[react/text {:style styles/asset-item-value
:number-of-lines 1
:ellipsize-mode :tail
:accessibility-label (str (-> symbol clojure.core/name clojure.string/lower-case) "-collectible-value-text")}
(or i 0)]
:accessibility-label (str (-> symbol clojure.core/name clojure.string/lower-case)
"-collectible-value-text")}
(or items-number "...")]
[react/text {:style styles/asset-item-currency
:number-of-lines 1}
name]]

View File

@ -6,5 +6,9 @@
(defn token-of-owner-by-index [web3 contract address index cb]
(ethereum/call web3
(ethereum/call-params contract "tokenOfOwnerByIndex(address,uint256)" (ethereum/normalized-address address) index)
(ethereum/call-params
contract
"tokenOfOwnerByIndex(address,uint256)"
(ethereum/normalized-address address)
(ethereum/int->hex index))
#(cb %1 (ethereum/hex->bignumber %2))))

View File

@ -1,6 +1,7 @@
(ns status-im.utils.ethereum.tokens
(:require-macros [status-im.utils.ethereum.macros :refer [resolve-icons]])
(:require [clojure.string :as string]))
(:require [clojure.string :as string]
[status-im.utils.config :as config]))
(defn- asset-border [color]
{:border-color color :border-width 1 :border-radius 32})
@ -386,21 +387,18 @@
:address "0x9B11EFcAAA1890f6eE52C6bB7CF8153aC5d74139"
:decimals 8
:hidden? true}
{:symbol :CK
:nft? true
:name "CryptoKitties"
:address "0x06012c8cf97bead5deae237070f9587f8e7a266d"
:hidden? true}
{:symbol :EMONA
:nft? true
:name "Etheremon"
:address "0xB2c0782ae4A299f7358758B2D15dA9bF29E1DD99"
:hidden? true}
{:symbol :STRK
:nft? true
:name "CryptoStrikers"
:address "0xdcaad9fd9a74144d226dbf94ce6162ca9f09ed7e"
:hidden? true}])
{:symbol :CK
:nft? true
:name "CryptoKitties"
:address "0x06012c8cf97bead5deae237070f9587f8e7a266d"}
{:symbol :EMONA
:nft? true
:name "Etheremon"
:address "0xB2c0782ae4A299f7358758B2D15dA9bF29E1DD99"}
{:symbol :STRK
:nft? true
:name "CryptoStrikers"
:address "0xdcaad9fd9a74144d226dbf94ce6162ca9f09ed7e"}])
:testnet
(resolve-icons :testnet
[{:name "Status Test Token"

View File

@ -70,3 +70,6 @@
:keywordize-keys true)
(catch :default _
(log/debug (str "Failed to parse " o))))))
(defn url-sanitized? [uri]
(not (nil? (re-find #"^(https:)([/|.|\w|\s|-])*\.(?:jpg|svg|png)$" uri))))

View File

@ -76,6 +76,10 @@
(when bn
(.toFixed bn)))
(defn to-number [bn]
(when bn
(.toNumber bn)))
(defn wei->str [unit n]
(str (to-fixed (wei-> unit n)) " " (string/upper-case (name unit))))

View File

@ -43,6 +43,7 @@
[status-im.test.utils.prices]
[status-im.test.utils.keychain.core]
[status-im.test.utils.universal-links.core]
[status-im.test.utils.http]
[status-im.test.ui.screens.events]
[status-im.test.ui.screens.accounts.login.events]))
@ -98,5 +99,6 @@
'status-im.test.utils.prices
'status-im.test.utils.keychain.core
'status-im.test.utils.universal-links.core
'status-im.test.utils.http
'status-im.test.ui.screens.events
'status-im.test.ui.screens.accounts.login.events)

View File

@ -0,0 +1,40 @@
(ns status-im.test.utils.http
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.utils.http :as http]))
(deftest url-sanitize-check
(testing "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/818934.svg"
(testing "it returns true"
(is (http/url-sanitized? "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/818934.svg"))))
(testing "https://www.cryptostrikers.com/assets/images/cards/017.svg"
(testing "it returns true"
(is (http/url-sanitized? "https://www.cryptostrikers.com/assets/images/cards/017.svg"))))
(testing "https://www.etheremon.com/assets/images/mons_origin/025.png"
(testing "it returns true"
(is (http/url-sanitized? "https://www.etheremon.com/assets/images/mons_origin/025.png"))))
(testing "http://www.etheremon.com/assets/images/mons_origin/025.png"
(testing "it returns false"
(is (not (http/url-sanitized? "http://www.etheremon.com/assets/images/mons_origin/025.png")))))
(testing "xxx:x \\\\x0Aonerror=javascript:alert(1)"
(testing "it returns false"
(is (not (http/url-sanitized? "xxx:x \\\\x0Aonerror=javascript:alert(1)")))))
(testing "https://www.etheremon.com/assets/images/mons_origin/025.png'&lt;script&gt;alert(&#39;123&#39;);&lt;/script&gt;"
(testing "it returns false"
(is (not (http/url-sanitized? "https://www.etheremon.com/assets/images/mons_origin/025.png'&lt;script&gt;alert(&#39;123&#39;);&lt;/script&gt;")))))
(testing "https://www.etheremon.com/assets/images/mons'&lt;script&gt;alert(&#39;123&#39;);&lt;/script&gt;origin/025.png"
(testing "it returns false"
(is (not (http/url-sanitized? "https://www.etheremon.com/assets/images/mons'&lt;script&gt;alert(&#39;123&#39;);&lt;/script&gt;origin/025.png")))))
(testing "https://www.etheremon.com/assets/images/mons_origin/025.png'><script>\\\\x3Bjavascript:alert(1)</script>"
(testing "it returns false"
(is (not (http/url-sanitized? "https://www.etheremon.com/assets/images/mons_origin/025.png'><script>\\\\x3Bjavascript:alert(1)</script>")))))
(testing "https://www.etheremon.com/assets/images/mons'><script>\\\\x3Bjavascript:alert(1)</script>origin/025.png"
(testing "it returns false"
(is (not (http/url-sanitized? "https://www.etheremon.com/assets/images/mons'><script>\\\\x3Bjavascript:alert(1)</script>origin/025.png"))))))