[#8666] Add account via BIP 44

Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
This commit is contained in:
Andrey Shovkoplyas 2019-08-12 10:53:31 +02:00
parent fde55b80d0
commit ba112a765b
No known key found for this signature in database
GPG Key ID: EAAB7C8622D860A4
46 changed files with 757 additions and 331 deletions

View File

@ -306,6 +306,7 @@
:wallet-request-assets :wallet-request-assets
:choose-recipient :choose-recipient
:recent-recipients :recent-recipients
:select-account
:wallet-send-transaction-request :wallet-send-transaction-request
:contact-code :contact-code
:wallet-settings-hook) :wallet-settings-hook)
@ -317,6 +318,7 @@
colors/white)}) colors/white)})
bottom-background (when (#{:recent-recipients bottom-background (when (#{:recent-recipients
:select-account
:wallet-send-assets :wallet-send-assets
:wallet-request-assets} current-view) :wallet-request-assets} current-view)
[view {:background-color colors/white [view {:background-color colors/white

View File

@ -244,6 +244,7 @@ var TopLevel = {
"messaging" : function () {}, "messaging" : function () {},
"method" : function () {}, "method" : function () {},
"minus" : function () {}, "minus" : function () {},
"plus" : function () {},
"mkdir" : function () {}, "mkdir" : function () {},
"module" : function () {}, "module" : function () {},
"moveFile" : function () {}, "moveFile" : function () {},
@ -563,5 +564,9 @@ var TopLevel = {
"createAppContainer" : function () {}, "createAppContainer" : function () {},
"useScreens" : function () {}, "useScreens" : function () {},
"multiAccountGenerateAndDeriveAddresses" : function () {}, "multiAccountGenerateAndDeriveAddresses" : function () {},
"multiAccountStoreDerived" : function () {} "multiAccountStoreDerived" : function () {},
"multiAccountDeriveAddresses" : function () {},
"multiAccountReset" : function () {},
"multiAccountLoadAccount" : function () {},
"multiAccountStoreAccount" : function () {}
} }

View File

@ -660,6 +660,82 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
StatusThreadPoolExecutor.getInstance().execute(r); StatusThreadPoolExecutor.getInstance().execute(r);
} }
@ReactMethod
public void multiAccountStoreAccount(final String json, final Callback callback) {
Log.d(TAG, "multiAccountStoreAccount");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiAccountStoreAccount(json);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
public void multiAccountLoadAccount(final String json, final Callback callback) {
Log.d(TAG, "multiAccountLoadAccount");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiAccountLoadAccount(json);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
public void multiAccountReset(final Callback callback) {
Log.d(TAG, "multiAccountReset");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiAccountReset();
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
public void multiAccountDeriveAddresses(final String json, final Callback callback) {
Log.d(TAG, "multiAccountDeriveAddresses");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiAccountDeriveAddresses(json);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod @ReactMethod
public void multiAccountGenerateAndDeriveAddresses(final String json, final Callback callback) { public void multiAccountGenerateAndDeriveAddresses(final String json, final Callback callback) {
Log.d(TAG, "multiAccountGenerateAndDeriveAddresses"); Log.d(TAG, "multiAccountGenerateAndDeriveAddresses");

View File

@ -345,6 +345,35 @@ RCT_EXPORT_METHOD(multiAccountGenerateAndDeriveAddresses:(NSString *)json
callback(@[result]); callback(@[result]);
} }
//////////////////////////////////////////////////////////////////// MultiAccountStoreAccount
RCT_EXPORT_METHOD(multiAccountStoreAccount:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountStoreAccount() method called");
#endif
NSString *result = StatusgoMultiAccountStoreAccount(json);
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// MultiAccountLoadAccount
RCT_EXPORT_METHOD(multiAccountLoadAccount:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountLoadAccount() method called");
#endif
NSString *result = StatusgoMultiAccountLoadAccount(json);
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// MultiAccountReset
RCT_EXPORT_METHOD(multiAccountReset:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountReset() method called");
#endif
NSString *result = StatusgoMultiAccountReset();
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// multiAccountStoreDerived //////////////////////////////////////////////////////////////////// multiAccountStoreDerived
RCT_EXPORT_METHOD(multiAccountStoreDerived:(NSString *)json RCT_EXPORT_METHOD(multiAccountStoreDerived:(NSString *)json
callback:(RCTResponseSenderBlock)callback) { callback:(RCTResponseSenderBlock)callback) {
@ -355,6 +384,15 @@ RCT_EXPORT_METHOD(multiAccountStoreDerived:(NSString *)json
callback(@[result]); callback(@[result]);
} }
//////////////////////////////////////////////////////////////////// MultiAccountDeriveAddresses
RCT_EXPORT_METHOD(multiAccountDeriveAddresses:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountDeriveAddresses() method called");
#endif
NSString *result = StatusgoMultiAccountDeriveAddresses(json);
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// login //////////////////////////////////////////////////////////////////// login
RCT_EXPORT_METHOD(login:(NSString *)json RCT_EXPORT_METHOD(login:(NSString *)json

View File

@ -60,8 +60,9 @@
(def assets-separator [react/view transactions-styles/asset-separator]) (def assets-separator [react/view transactions-styles/asset-separator])
(defview choose-asset [nft?] (defn choose-asset [nft?] [react/view])
(letsubs [assets [:wallet/visible-assets-with-amount]] ;;TODO we'll need to specify address here
#_(letsubs [assets [:wallet/visible-assets-with-amount]]
[react/view [react/view
[list/flat-list {:data (filter #(if nft? [list/flat-list {:data (filter #(if nft?
(:nft? %) (:nft? %)
@ -74,7 +75,7 @@
:enableEmptySections true :enableEmptySections true
:separator assets-separator :separator assets-separator
:keyboardShouldPersistTaps :always :keyboardShouldPersistTaps :always
:bounces false}]])) :bounces false}]])
(defn choose-asset-suggestion [] (defn choose-asset-suggestion []
[choose-asset false]) [choose-asset false])

View File

@ -237,6 +237,7 @@
(def ^:const status-create-address "status_createaddress") (def ^:const status-create-address "status_createaddress")
(def ^:const path-root "m/44'/60'/0'/0")
(def ^:const path-default-wallet "m/44'/60'/0'/0/0") (def ^:const path-default-wallet "m/44'/60'/0'/0/0")
(def ^:const path-whisper "m/43'/60'/1581'/0'/0") (def ^:const path-whisper "m/43'/60'/1581'/0'/0")

View File

@ -255,3 +255,4 @@
(def v26 (update v25 :properties merge {:root-address {:type :string :optional true} (def v26 (update v25 :properties merge {:root-address {:type :string :optional true}
:accounts {:type :string :optional true}})) :accounts {:type :string :optional true}}))
(def v27 (update v26 :properties merge {:latest-derived-path {:type :int :optional true}}))

View File

@ -128,6 +128,11 @@
extension/v12 extension/v12
account/v26]) account/v26])
(def v32 [network/v1
bootnode/v4
extension/v12
account/v27])
;; put schemas ordered by version ;; put schemas ordered by version
(def schemas [{:schema v1 (def schemas [{:schema v1
:schemaVersion 1 :schemaVersion 1
@ -221,4 +226,7 @@
:migration (constantly nil)} :migration (constantly nil)}
{:schema v31 {:schema v31
:schemaVersion 31 :schemaVersion 31
:migration (constantly nil)}
{:schema v32
:schemaVersion 32
:migration (constantly nil)}]) :migration (constantly nil)}])

View File

@ -42,6 +42,7 @@
"status_startOneOnOneChat" {} "status_startOneOnOneChat" {}
"status_removeChat" {} "status_removeChat" {}
"wallet_getTransfers" {} "wallet_getTransfers" {}
"wallet_getTransfersByAddress" {}
"browsers_getBrowsers" {} "browsers_getBrowsers" {}
"browsers_addBrowser" {} "browsers_addBrowser" {}
"browsers_deleteBrowser" {} "browsers_deleteBrowser" {}

View File

@ -26,6 +26,7 @@
(fx/defn new-block (fx/defn new-block
[{:keys [db] :as cofx} historical? block-number accounts] [{:keys [db] :as cofx} historical? block-number accounts]
(let [{:keys [:wallet/all-tokens]} db (let [{:keys [:wallet/all-tokens]} db
accounts (get-in db [:multiaccount :accounts]) ;;TODO https://github.com/status-im/status-go/issues/1566
chain (ethereum/chain-keyword db) chain (ethereum/chain-keyword db)
chain-tokens (into {} (map (juxt :address identity) chain-tokens (into {} (map (juxt :address identity)
(tokens/tokens-for all-tokens chain)))] (tokens/tokens-for all-tokens chain)))]
@ -34,20 +35,23 @@
(not historical?) (not historical?)
(assoc :db (assoc db :ethereum/current-block block-number)) (assoc :db (assoc db :ethereum/current-block block-number))
(not-empty accounts) true ;(not-empty accounts) ;;TODO https://github.com/status-im/status-go/issues/1566
(assoc ::transactions/get-transfers {:chain-tokens chain-tokens (assoc ::transactions/get-transfers {:accounts accounts
:chain-tokens chain-tokens
:from-block block-number})) :from-block block-number}))
(transactions/check-watched-transactions)))) (transactions/check-watched-transactions))))
(fx/defn reorg (fx/defn reorg
[{:keys [db] :as cofx} block-number accounts] [{:keys [db] :as cofx} block-number accounts]
(let [{:keys [:wallet/all-tokens]} db (let [{:keys [:wallet/all-tokens]} db
accounts (get-in db [:multiaccount :accounts]) ;;TODO https://github.com/status-im/status-go/issues/1566
chain (ethereum/chain-keyword db) chain (ethereum/chain-keyword db)
chain-tokens (into {} (map (juxt :address identity) chain-tokens (into {} (map (juxt :address identity)
(tokens/tokens-for all-tokens chain)))] (tokens/tokens-for all-tokens chain)))]
{:db (update-in db [:wallet :transactions] {:db (update-in db [:wallet :transactions]
wallet/remove-transactions-since-block block-number) wallet/remove-transactions-since-block block-number)
::transactions/get-transfers {:chain-tokens chain-tokens ::transactions/get-transfers {:accounts accounts
:chain-tokens chain-tokens
:from-block block-number}})) :from-block block-number}}))
(fx/defn new-wallet-event (fx/defn new-wallet-event

View File

@ -119,36 +119,26 @@
watched-transactions)))) watched-transactions))))
(fx/defn add-transfer (fx/defn add-transfer
[{:keys [db] :as cofx} {:keys [hash id] :as transfer}] [{:keys [db] :as cofx} {:keys [hash id] :as transfer} address]
(let [transfer-by-hash (get-in db [:wallet :transactions hash]) (let [transfer-by-hash (get-in db [:wallet :accounts address :transactions hash])]
transfer-by-id (get-in db [:wallet :transaction id]) ;;transfer-by-id (get-in db [:wallet :transaction id]) ;; TODO didn't found any usage of this
unique-id (when-not (or transfer-by-id (when-let [unique-id (when (not= transfer transfer-by-hash) ;(or transfer-by-id)
(= transfer transfer-by-hash)) (if (and transfer-by-hash
(if (and transfer-by-hash (not (= :pending
(not (= :pending (:type transfer-by-hash))))
(:type transfer-by-hash)))) id
id hash))]
hash))]
(when unique-id
(fx/merge cofx (fx/merge cofx
{:db (assoc-in db [:wallet :transactions unique-id] {:db (assoc-in db [:wallet :accounts address :transactions unique-id]
(assoc transfer :hash unique-id))} (assoc transfer :hash unique-id))}
(check-transaction transfer))))) (check-transaction transfer)))))
(fx/defn new-transfers (fx/defn new-transfers
{:events [::new-transfers]} {:events [::new-transfers]}
[{:keys [db] :as cofx} transfers] [{:keys [db] :as cofx} address transfers]
(let [add-transfers-fx (map add-transfer transfers)] (let [add-transfers-fx (map #(add-transfer % address) transfers)]
(apply fx/merge cofx (conj add-transfers-fx (apply fx/merge cofx (conj add-transfers-fx
wallet/update-balances)))) (wallet/update-balances [address])))))
(fx/defn handle-history
[{:keys [db] :as cofx} transactions]
(fx/merge cofx
{:db (update-in db
[:wallet :transactions]
#(merge transactions %))}
wallet/update-balances))
(fx/defn handle-token-history (fx/defn handle-token-history
[{:keys [db]} transactions] [{:keys [db]} transactions]
@ -158,21 +148,22 @@
(re-frame/reg-fx (re-frame/reg-fx
::get-transfers ::get-transfers
(fn [{:keys [chain-tokens from-block to-block] (fn [{:keys [accounts chain-tokens from-block to-block]
:or {from-block "0" :or {from-block "0"
to-block nil}}] to-block nil}}]
;; start inbound token transaction subscriptions ;; start inbound token transaction subscriptions
;; outbound token transactions are already caught in new blocks filter ;; outbound token transactions are already caught in new blocks filter
(json-rpc/call (doseq [{:keys [address]} accounts]
{:method "wallet_getTransfers" (json-rpc/call
:params [(encode/uint from-block) (encode/uint to-block)] {:method "wallet_getTransfersByAddress"
:on-success #(re-frame/dispatch :params [address (encode/uint from-block) (encode/uint to-block)]
[::new-transfers (enrich-transfers chain-tokens %)])}))) :on-success #(re-frame/dispatch [::new-transfers address (enrich-transfers chain-tokens %)])}))))
(fx/defn initialize (fx/defn initialize
[{:keys [db] :as cofx}] [{:keys [db] :as cofx}]
(let [{:keys [:wallet/all-tokens]} db (let [accounts (get-in db [:multiaccount :accounts]) ;;TODO https://github.com/status-im/status-go/issues/1566
{:keys [:wallet/all-tokens]} db
chain (ethereum/chain-keyword db) chain (ethereum/chain-keyword db)
chain-tokens (into {} (map (juxt :address identity) chain-tokens (into {} (map (juxt :address identity)
(tokens/tokens-for all-tokens chain)))] (tokens/tokens-for all-tokens chain)))]
{::get-transfers {:chain-tokens chain-tokens}})) {::get-transfers {:accounts accounts :chain-tokens chain-tokens}}))

View File

@ -1788,12 +1788,6 @@
(fn [cofx [_ id handler]] (fn [cofx [_ id handler]]
(ethereum.subscriptions/register-subscription cofx id handler))) (ethereum.subscriptions/register-subscription cofx id handler)))
;; ethereum transactions events
(handlers/register-handler-fx
:ethereum.transactions.callback/fetch-history-success
(fn [cofx [_ transactions]]
(ethereum.transactions/handle-history cofx transactions)))
(handlers/register-handler-fx (handlers/register-handler-fx
:ethereum.transactions.callback/etherscan-error :ethereum.transactions.callback/etherscan-error
(fn [cofx [event error]] (fn [cofx [event error]]
@ -1834,8 +1828,8 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet/token-found :wallet/token-found
(fn [cofx [_ symbol balance]] (fn [cofx [_ address symbol balance]]
(wallet/configure-token-balance-and-visibility cofx symbol balance))) (wallet/configure-token-balance-and-visibility cofx address symbol balance)))
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet.settings.ui/navigate-back-pressed :wallet.settings.ui/navigate-back-pressed
@ -1844,12 +1838,12 @@
(when on-close (when on-close
{:dispatch on-close}) {:dispatch on-close})
(navigation/navigate-back) (navigation/navigate-back)
(wallet/update-balances)))) (wallet/update-balances nil))))
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet.callback/update-balance-success :wallet.callback/update-balance-success
(fn [cofx [_ balance]] (fn [cofx [_ address balance]]
(wallet/update-balance cofx balance))) (wallet/update-balance cofx address balance)))
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet.callback/update-balance-fail :wallet.callback/update-balance-fail
@ -1858,8 +1852,8 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet.callback/update-token-balance-success :wallet.callback/update-token-balance-success
(fn [cofx [_ symbol balance]] (fn [cofx [_ address symbol balance]]
(wallet/update-token-balance cofx symbol balance))) (wallet/update-token-balance cofx address symbol balance)))
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet.callback/update-token-balance-fail :wallet.callback/update-token-balance-fail
@ -1878,8 +1872,8 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet.ui/show-transaction-details :wallet.ui/show-transaction-details
(fn [cofx [_ hash]] (fn [cofx [_ hash address]]
(wallet/open-transaction-details cofx hash))) (wallet/open-transaction-details cofx hash address)))
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet.setup.ui/navigate-back-pressed :wallet.setup.ui/navigate-back-pressed

View File

@ -48,11 +48,13 @@
(defn create-multiaccount! [{:keys [id password]}] (defn create-multiaccount! [{:keys [id password]}]
(if id (if id
(status/multiaccount-store-derived (do
id ;(status/multiaccount-store-account id password #()) ;; TODO if i add this, i'm unable to login after
[constants/path-whisper constants/path-default-wallet] (status/multiaccount-store-derived
password id
#(re-frame/dispatch [:multiaccounts.create.callback/create-multiaccount-success password])) [constants/path-whisper constants/path-default-wallet]
password
#(re-frame/dispatch [:multiaccounts.create.callback/create-multiaccount-success password])))
(status/create-multiaccount (status/create-multiaccount
password password
#(re-frame/dispatch [:multiaccounts.create.callback/create-multiaccount-success (types/json->clj %) password])))) #(re-frame/dispatch [:multiaccounts.create.callback/create-multiaccount-success (types/json->clj %) password]))))
@ -243,6 +245,7 @@
new-multiaccount {;;multiaccount new-multiaccount {;;multiaccount
:root-address (:address multiaccount) :root-address (:address multiaccount)
:public-key publicKey :public-key publicKey
:latest-derived-path 0
:installation-id (get-in db [:multiaccounts/new-installation-id]) ;;TODO why can't we generate it here? :installation-id (get-in db [:multiaccounts/new-installation-id]) ;;TODO why can't we generate it here?
:address address :address address
:name (gfycat/generate-gfy publicKey) :name (gfycat/generate-gfy publicKey)

View File

@ -90,7 +90,7 @@
(fx/defn initialize-wallet [cofx] (fx/defn initialize-wallet [cofx]
(fx/merge cofx (fx/merge cofx
(wallet/initialize-tokens) (wallet/initialize-tokens)
(wallet/update-balances) (wallet/update-balances nil)
(wallet/update-prices) (wallet/update-prices)
(transactions/initialize))) (transactions/initialize)))

View File

@ -19,6 +19,18 @@
(defn create-multiaccount [password callback] (defn create-multiaccount [password callback]
(native-module/create-account password callback)) (native-module/create-account password callback))
(defn multiaccount-store-account [account-id password callback]
(native-module/multiaccount-store-account account-id password callback))
(defn multiaccount-load-account [address password callback]
(native-module/multiaccount-load-account address password callback))
(defn multiaccount-reset [callback]
(native-module/multiaccount-reset callback))
(defn multiaccount-derive-addresses [account-id paths callback]
(native-module/multiaccount-derive-addresses account-id paths callback))
(defn recover-multiaccount [passphrase password callback] (defn recover-multiaccount [passphrase password callback]
(native-module/recover-account passphrase password callback)) (native-module/recover-account passphrase password callback))

View File

@ -71,6 +71,32 @@
:paths paths}) :paths paths})
on-result))) on-result)))
(defn multiaccount-derive-addresses [account-id paths on-result]
(when (and @node-started (status))
(.multiAccountDeriveAddresses (status)
(types/clj->json {:accountID account-id
:paths paths})
on-result)))
(defn multiaccount-store-account [account-id password on-result]
(when (and @node-started (status))
(.multiAccountStoreAccount (status)
(types/clj->json {:accountID account-id
:password password})
on-result)))
(defn multiaccount-load-account [address password on-result]
(when (and @node-started (status))
(.multiAccountLoadAccount (status)
(types/clj->json {:address address
:password password})
on-result)))
(defn multiaccount-reset [on-result]
(when (and @node-started (status))
(.multiAccountReset (status)
on-result)))
(defn multiaccount-store-derived [account-id paths password on-result] (defn multiaccount-store-derived [account-id paths password on-result]
(when (and @node-started (status)) (when (and @node-started (status))
(.multiAccountStoreDerived (status) (.multiAccountStoreDerived (status)

View File

@ -137,24 +137,25 @@
:token token :token token
:symbol symbol})))))) :symbol symbol}))))))
(defn parse-tx-obj [db {:keys [to value data]}] (defn parse-tx-obj [db {:keys [from to value data]}]
(if (nil? to) (merge {:from {:address from}}
{:contact {:name (i18n/label :t/new-contract)}} (if (nil? to)
(let [eth-value (when value (money/bignumber value)) {:contact {:name (i18n/label :t/new-contract)}}
eth-amount (when eth-value (money/to-number (money/wei->ether eth-value))) (let [eth-value (when value (money/bignumber value))
token (get-transfer-token db to data)] eth-amount (when eth-value (money/to-number (money/wei->ether eth-value)))
(cond token (get-transfer-token db to data)]
(and eth-amount (or (not (zero? eth-amount)) (nil? data))) (cond
{:to to (and eth-amount (or (not (zero? eth-amount)) (nil? data)))
:contact (get-contact db to) {:to to
:symbol :ETH :contact (get-contact db to)
:amount (str eth-amount) :symbol :ETH
:token (tokens/asset-for (:wallet/all-tokens db) (ethereum/chain-keyword db) :ETH)} :amount (str eth-amount)
(not (nil? token)) :token (tokens/asset-for (:wallet/all-tokens db) (ethereum/chain-keyword db) :ETH)}
token (not (nil? token))
:else token
{:to to :else
:contact {:address (ethereum/normalized-address to)}})))) {:to to
:contact {:address (ethereum/normalized-address to)}})))))
(defn prepare-tx [db {{:keys [data gas gasPrice] :as tx-obj} :tx-obj :as tx}] (defn prepare-tx [db {{:keys [data gas gasPrice] :as tx-obj} :tx-obj :as tx}]
(merge (merge

View File

@ -181,6 +181,7 @@
(reg-root-key-sub :intro-wizard :intro-wizard) (reg-root-key-sub :intro-wizard :intro-wizard)
(reg-root-key-sub :popover/popover :popover/popover) (reg-root-key-sub :popover/popover :popover/popover)
(reg-root-key-sub :generate-account :generate-account)
;;GENERAL ============================================================================================================== ;;GENERAL ==============================================================================================================
@ -800,6 +801,7 @@
(re-frame/reg-sub (re-frame/reg-sub
:chats/transaction-status :chats/transaction-status
;;TODO address here for transactions
:<- [:wallet/transactions] :<- [:wallet/transactions]
:<- [:ethereum/current-block] :<- [:ethereum/current-block]
(fn [[transactions current-block] [_ hash]] (fn [[transactions current-block] [_ hash]]
@ -965,8 +967,21 @@
(re-frame/reg-sub (re-frame/reg-sub
:balance :balance
:<- [:wallet] :<- [:wallet]
(fn [wallet [_ address]]
(get-in wallet [:accounts address :balance])))
(re-frame/reg-sub
:balance-default
:<- [:wallet]
:<- [:multiaccount]
(fn [[wallet {:keys [accounts]}]]
(get-in wallet [:accounts (:address (ethereum/get-default-account accounts)) :balance])))
(re-frame/reg-sub
:balances
:<- [:wallet]
(fn [wallet] (fn [wallet]
(:balance wallet))) (map :balance (vals (:accounts wallet)))))
(re-frame/reg-sub (re-frame/reg-sub
:price :price
@ -986,20 +1001,6 @@
(fn [settings] (fn [settings]
(or (get-in settings [:wallet :currency]) :usd))) (or (get-in settings [:wallet :currency]) :usd)))
(re-frame/reg-sub
:asset-value
(fn [[_ fsym decimals tsym]]
[(re-frame/subscribe [:balance])
(re-frame/subscribe [:price fsym tsym])
(re-frame/subscribe [:wallet/currency])])
(fn [[balance price currency] [_ fsym decimals tsym]]
(when (and balance price)
(-> (money/internal->formatted (get balance fsym) fsym decimals)
(money/crypto->fiat price)
(money/with-precision 2)
str
(i18n/format-currency (:code currency))))))
(defn- get-balance-total-value (defn- get-balance-total-value
[balance prices currency token->decimals] [balance prices currency token->decimals]
(reduce-kv (fn [acc symbol value] (reduce-kv (fn [acc symbol value]
@ -1012,21 +1013,39 @@
(re-frame/reg-sub (re-frame/reg-sub
:portfolio-value :portfolio-value
:<- [:balance] :<- [:balances]
:<- [:prices] :<- [:prices]
:<- [:wallet/currency] :<- [:wallet/currency]
:<- [:ethereum/chain-keyword] :<- [:ethereum/chain-keyword]
:<- [:wallet/all-tokens] :<- [:wallet/all-tokens]
(fn [[balance prices currency chain all-tokens] [_ currency-code]] (fn [[balances prices currency chain all-tokens]]
(if (and balances prices)
(let [assets (tokens/tokens-for all-tokens chain)
token->decimals (into {} (map #(vector (:symbol %) (:decimals %)) assets))
currency-key (-> currency :code keyword)
balance-total-value (apply + (map #(get-balance-total-value % prices currency-key token->decimals) balances))]
(if (pos? balance-total-value)
(-> balance-total-value
(money/with-precision 2)
str
(i18n/format-currency (:code currency) false))
"0"))
"...")))
(re-frame/reg-sub
:account-portfolio-value
(fn [[_ address] _]
[(re-frame/subscribe [:balance address])
(re-frame/subscribe [:prices])
(re-frame/subscribe [:wallet/currency])
(re-frame/subscribe [:ethereum/chain-keyword])
(re-frame/subscribe [:wallet/all-tokens])])
(fn [[balance prices currency chain all-tokens]]
(if (and balance prices) (if (and balance prices)
(let [assets (tokens/tokens-for all-tokens chain) (let [assets (tokens/tokens-for all-tokens chain)
token->decimals (into {} (map #(vector (:symbol %) (:decimals %)) assets)) token->decimals (into {} (map #(vector (:symbol %) (:decimals %)) assets))
balance-total-value currency-key (-> currency :code keyword)
(get-balance-total-value balance balance-total-value (get-balance-total-value balance prices currency-key token->decimals)]
prices
(or currency-code
(-> currency :code keyword))
token->decimals)]
(if (pos? balance-total-value) (if (pos? balance-total-value)
(-> balance-total-value (-> balance-total-value
(money/with-precision 2) (money/with-precision 2)
@ -1050,12 +1069,6 @@
(let [vt-set (set visible-tokens)] (let [vt-set (set visible-tokens)]
(group-by :custom? (map #(assoc % :checked? (boolean (get vt-set (keyword (:symbol %))))) all-tokens))))) (group-by :custom? (map #(assoc % :checked? (boolean (get vt-set (keyword (:symbol %))))) all-tokens)))))
(re-frame/reg-sub
:wallet/balance-loading?
:<- [:wallet]
(fn [wallet]
(:balance-loading? wallet)))
(re-frame/reg-sub (re-frame/reg-sub
:wallet/error-message :wallet/error-message
:<- [:wallet] :<- [:wallet]
@ -1082,18 +1095,19 @@
(re-frame/reg-sub (re-frame/reg-sub
:wallet/visible-assets-with-amount :wallet/visible-assets-with-amount
:<- [:balance] (fn [[_ address] _]
:<- [:wallet/visible-assets] [(re-frame/subscribe [:balance address])
(re-frame/subscribe [:wallet/visible-assets])])
(fn [[balance visible-assets]] (fn [[balance visible-assets]]
(map #(assoc % :amount (get balance (:symbol %))) visible-assets))) (map #(assoc % :amount (get balance (:symbol %))) visible-assets)))
(defn update-value [balance prices currency] (defn update-value [prices currency]
(fn [{:keys [symbol decimals] :as token}] (fn [{:keys [symbol decimals amount] :as token}]
(let [price (get-in prices [symbol (-> currency :code keyword) :price])] (let [price (get-in prices [symbol (-> currency :code keyword) :price])]
(assoc token (assoc token
:price price :price price
:value (when (and balance price) :value (when (and amount price)
(-> (money/internal->formatted (get balance symbol) symbol decimals) (-> (money/internal->formatted amount symbol decimals)
(money/crypto->fiat price) (money/crypto->fiat price)
(money/with-precision 2) (money/with-precision 2)
str str
@ -1101,19 +1115,45 @@
(re-frame/reg-sub (re-frame/reg-sub
:wallet/visible-assets-with-values :wallet/visible-assets-with-values
:<- [:wallet/visible-assets-with-amount] (fn [[_ address] _]
[(re-frame/subscribe [:wallet/visible-assets-with-amount address])
(re-frame/subscribe [:prices])
(re-frame/subscribe [:wallet/currency])])
(fn [[assets prices currency]]
(let [{:keys [tokens nfts]} (group-by #(if (:nft? %) :nfts :tokens) assets)
tokens-with-values (map (update-value prices currency) tokens)]
{:tokens tokens-with-values
:nfts nfts})))
(defn get-asset-amount [balances sym]
(reduce #(if-let [bl (get %2 sym)]
(.plus %1 bl)
%1)
(money/bignumber 0)
balances))
(re-frame/reg-sub
:wallet/all-visible-assets-with-amount
:<- [:balances]
:<- [:wallet/visible-assets]
(fn [[balances visible-assets]]
(map #(assoc % :amount (get-asset-amount balances (:symbol %))) visible-assets)))
(re-frame/reg-sub
:wallet/all-visible-assets-with-values
:<- [:wallet/all-visible-assets-with-amount]
:<- [:prices] :<- [:prices]
:<- [:wallet/currency] :<- [:wallet/currency]
:<- [:balance] (fn [[assets prices currency]]
(fn [[assets prices currency balance]]
(let [{:keys [tokens nfts]} (group-by #(if (:nft? %) :nfts :tokens) assets) (let [{:keys [tokens nfts]} (group-by #(if (:nft? %) :nfts :tokens) assets)
tokens-with-values (map (update-value balance prices currency) tokens)] tokens-with-values (map (update-value prices currency) tokens)]
{:tokens tokens-with-values {:tokens tokens-with-values
:nfts nfts}))) :nfts nfts})))
(re-frame/reg-sub (re-frame/reg-sub
:wallet/transferrable-assets-with-amount :wallet/transferrable-assets-with-amount
:<- [:wallet/visible-assets-with-amount] (fn [[_ address]]
(re-frame/subscribe [:wallet/visible-assets-with-amount address]))
(fn [all-assets] (fn [all-assets]
(filter #(not (:nft? %)) all-assets))) (filter #(not (:nft? %)) all-assets)))
@ -1128,8 +1168,8 @@
(re-frame/reg-sub (re-frame/reg-sub
:wallet/transactions :wallet/transactions
:<- [:wallet] :<- [:wallet]
(fn [wallet] (fn [wallet [_ address]]
(get wallet :transactions))) (get-in wallet [:accounts address :transactions])))
(re-frame/reg-sub (re-frame/reg-sub
:wallet/filters :wallet/filters
@ -1161,14 +1201,15 @@
(re-frame/reg-sub (re-frame/reg-sub
:wallet.transactions/transactions :wallet.transactions/transactions
:<- [:wallet/transactions] (fn [[_ address] _]
:<- [:contacts/contacts-by-address] [(re-frame/subscribe [:wallet/transactions address])
:<- [:ethereum/native-currency] (re-frame/subscribe [:contacts/contacts-by-address])
(re-frame/subscribe [:ethereum/native-currency])])
(fn [[transactions contacts native-currency]] (fn [[transactions contacts native-currency]]
(reduce (fn [acc [hash transaction]] (reduce (fn [acc [hash transaction]]
(assoc acc (assoc acc
hash hash
(enrich-transaction transaction contacts native-currency))) (enrich-transaction transaction contacts native-currency))) ;;TODO this doesn't look good for performance, we need to calculate this only once for each transaction
{} {}
transactions))) transactions)))
@ -1212,7 +1253,8 @@
(defn- enrich-transaction-for-list (defn- enrich-transaction-for-list
[filters [filters
{:keys [type from-contact from to-contact to hash timestamp] :as transaction}] {:keys [type from-contact from to-contact to hash timestamp] :as transaction}
address]
(when (filters type) (when (filters type)
(assoc (case type (assoc (case type
:inbound :inbound
@ -1229,7 +1271,7 @@
:contact to-contact :contact to-contact
:address to)) :address to))
:time-formatted (datetime/timestamp->time timestamp) :time-formatted (datetime/timestamp->time timestamp)
:on-touch-fn #(re-frame/dispatch [:wallet.ui/show-transaction-details hash])))) :on-touch-fn #(re-frame/dispatch [:wallet.ui/show-transaction-details hash address]))))
(defn- group-transactions-by-date (defn- group-transactions-by-date
[transactions] [transactions]
@ -1243,33 +1285,28 @@
(re-frame/reg-sub (re-frame/reg-sub
:wallet.transactions.history/screen :wallet.transactions.history/screen
:<- [:wallet.transactions/transactions] (fn [[_ address] _]
:<- [:wallet/filters] [(re-frame/subscribe [:wallet.transactions/transactions address])
:<- [:wallet.transactions/all-filters?] (re-frame/subscribe [:wallet/filters])
(fn [[transactions filters all-filters?]] (re-frame/subscribe [:wallet.transactions/all-filters?])])
(fn [[transactions filters all-filters?] [_ address]]
{:all-filters? all-filters? {:all-filters? all-filters?
:transaction-history-sections :transaction-history-sections
(->> transactions (->> transactions
vals vals
(keep #(enrich-transaction-for-list filters %)) (keep #(enrich-transaction-for-list filters % address))
(group-transactions-by-date))})) (group-transactions-by-date))}))
(re-frame/reg-sub
:wallet.transactions/current-transaction
:<- [:wallet]
(fn [wallet]
(:current-transaction wallet)))
(re-frame/reg-sub (re-frame/reg-sub
:wallet.transactions.details/current-transaction :wallet.transactions.details/current-transaction
:<- [:wallet.transactions/transactions] (fn [[_ hash address] _]
:<- [:wallet.transactions/current-transaction] [(re-frame/subscribe [:wallet.transactions/transactions address])
:<- [:ethereum/native-currency] (re-frame/subscribe [:ethereum/native-currency])
:<- [:ethereum/chain-keyword] (re-frame/subscribe [:ethereum/chain-keyword])])
(fn [[transactions current-transaction native-currency chain-keyword]] (fn [[transactions native-currency chain-keyword] [_ hash _]]
(let [{:keys [gas-used gas-price hash timestamp type token value] (let [{:keys [gas-used gas-price hash timestamp type token value]
:as transaction} :as transaction}
(get transactions current-transaction) (get transactions hash)
native-currency-text (name (or (:symbol-display native-currency) native-currency-text (name (or (:symbol-display native-currency)
(:symbol native-currency)))] (:symbol native-currency)))]
(when transaction (when transaction
@ -1301,8 +1338,9 @@
(re-frame/reg-sub (re-frame/reg-sub
:wallet.transactions.details/screen :wallet.transactions.details/screen
:<- [:wallet.transactions.details/current-transaction] (fn [[_ hash address] _]
:<- [:ethereum/current-block] [(re-frame/subscribe [:wallet.transactions.details/current-transaction hash address])
(re-frame/subscribe [:ethereum/current-block])])
(fn [[transaction current-block]] (fn [[transaction current-block]]
(let [confirmations (wallet.db/get-confirmations transaction (let [confirmations (wallet.db/get-confirmations transaction
current-block)] current-block)]
@ -1358,11 +1396,12 @@
(re-frame/reg-sub (re-frame/reg-sub
:wallet.send/transaction :wallet.send/transaction
:<- [::send-transaction] :<- [::send-transaction]
:<- [:balance] :<- [:wallet]
(fn [[{:keys [amount symbol] :as transaction} balance]] (fn [[{:keys [amount symbol from] :as transaction} wallet]]
(-> transaction (let [balance (get-in wallet [:accounts from :balance])]
(check-sufficient-funds balance symbol amount) (-> transaction
(check-sufficient-gas balance symbol amount)))) (check-sufficient-funds balance symbol amount)
(check-sufficient-gas balance symbol amount)))))
(re-frame/reg-sub (re-frame/reg-sub
:wallet/settings :wallet/settings
@ -1960,8 +1999,9 @@
(re-frame/reg-sub (re-frame/reg-sub
:signing/amount-errors :signing/amount-errors
:<- [:signing/tx] (fn [[_ address] _]
:<- [:balance] [(re-frame/subscribe [:signing/tx])
(re-frame/subscribe [:balance address])])
(fn [[{:keys [amount token gas gasPrice approve?]} balance]] (fn [[{:keys [amount token gas gasPrice approve?]} balance]]
(if (and amount token (not approve?)) (if (and amount token (not approve?))
(let [amount-bn (money/formatted->internal (money/bignumber amount) (:symbol token) (:decimals token)) (let [amount-bn (money/formatted->internal (money/bignumber amount) (:symbol token) (:decimals token))

View File

@ -57,3 +57,11 @@
(def text-gray gray) (def text-gray gray)
(def default-chat-color "#a187d5") ;; legacy (def default-chat-color "#a187d5") ;; legacy
(def account-colors ["#9B832F"
"#D37EF4"
"#1D806F"
"#FA6565"
"#7CDA00"
"#887AF9"
"#8B3131"])

View File

@ -4,15 +4,16 @@
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.ui.components.list-item.styles :as styles] [status-im.ui.components.list-item.styles :as styles]
[status-im.utils.image :as utils.image] [status-im.utils.image :as utils.image]
[status-im.ui.components.tooltip.views :as tooltip])) [status-im.ui.components.tooltip.views :as tooltip]
[status-im.ui.components.action-button.styles :as st]))
; type - optional :default , :small ; type - optional :default , :small
; accessories - optional vector of :chevron, :check or component or string ; accessories - optional vector of :chevron, :check or component or string
; theme - optional :default, :wallet ; theme - optional :default, :wallet, :action
(defn list-item [{:keys [title subtitle accessories image image-path type theme on-press error content] :or {type :default theme :default}}] (defn list-item [{:keys [title subtitle accessories image image-path icon type theme on-press error content] :or {type :default theme :default}}]
(let [small? (= :small type)] (let [small? (= :small type)]
[react/touchable-highlight {:on-press on-press :disabled (not on-press)} [react/touchable-highlight {:on-press on-press :disabled (not on-press)}
[react/view {:style (styles/container small?)} [react/view {:style (styles/container small?)}
@ -22,6 +23,13 @@
(if (vector? image) (if (vector? image)
image image
[image])]) [image])])
;;Icon
(when icon
[react/view {:margin-left 16}
[react/view (when (= theme :action) (st/action-button-icon-container nil))
[icons/icon icon (if (= theme :action)
st/action-button-label
{:color colors/gray-transparent-40})]]])
(when image-path (when image-path
[react/view {:margin-left 16} [react/view {:margin-left 16}
[react/image {:source (utils.image/source image-path) [react/image {:source (utils.image/source image-path)
@ -29,7 +37,8 @@
;;Title ;;Title
(when title (when title
[react/view {:style {:margin-left 16 :margin-right 16}} [react/view {:style {:margin-left 16 :margin-right 16}}
[react/text {:style (styles/title small? subtitle) [react/text {:style (merge (styles/title small? subtitle)
(when (= theme :action) st/action-button-label))
:number-of-lines 1 :number-of-lines 1
:ellipsize-mode :tail} :ellipsize-mode :tail}
title] title]

View File

@ -60,6 +60,7 @@
:wallet-send-assets {:type :wallet} :wallet-send-assets {:type :wallet}
:wallet-request-assets {:type :wallet} :wallet-request-assets {:type :wallet}
:recent-recipients {:type :wallet} :recent-recipients {:type :wallet}
:select-account {:type :wallet}
:contact-code {:type :wallet} :contact-code {:type :wallet}
:wallet-send-transaction-request {:type :wallet} :wallet-send-transaction-request {:type :wallet}
:wallet-settings-assets {:type :main} :wallet-settings-assets {:type :main}

View File

@ -358,4 +358,5 @@
::collectibles ::collectibles
::extensions-store ::extensions-store
:registry/registry :registry/registry
::two-pane-ui-enabled?])) ::two-pane-ui-enabled?
::generate-account]))

View File

@ -55,7 +55,7 @@
(hide-panel-anim bottom-anim-value alpha-value (- window-height))))) (hide-panel-anim bottom-anim-value alpha-value (- window-height)))))
:reagent-render (fn [] :reagent-render (fn []
(when @current-popover (when @current-popover
(let [view (:view @current-popover)] (let [{:keys [view style]} @current-popover]
[react/view {:position :absolute :top 0 :bottom 0 :left 0 :right 0} [react/view {:position :absolute :top 0 :bottom 0 :left 0 :right 0}
[react/animated-view {:style {:flex 1 :background-color :black :opacity alpha-value}}] [react/animated-view {:style {:flex 1 :background-color :black :opacity alpha-value}}]
[react/animated-view {:style [react/animated-view {:style
@ -66,13 +66,14 @@
:transform [{:translateY bottom-anim-value}]}} :transform [{:translateY bottom-anim-value}]}}
[react/touchable-highlight {:style {:flex 1} :on-press #(re-frame/dispatch [:hide-popover])} [react/touchable-highlight {:style {:flex 1} :on-press #(re-frame/dispatch [:hide-popover])}
[react/view {:flex 1 :align-items :center :justify-content :center} [react/view {:flex 1 :align-items :center :justify-content :center}
[react/view {:background-color :white [react/view (merge {:background-color :white
:border-radius 16 :border-radius 16
:margin 32 :margin 32
:shadow-offset {:width 0 :height 2} :shadow-offset {:width 0 :height 2}
:shadow-radius 8 :shadow-radius 8
:shadow-opacity 1 :shadow-opacity 1
:shadow-color "rgba(0, 9, 26, 0.12)"} :shadow-color "rgba(0, 9, 26, 0.12)"}
style)
(cond (cond
(vector? view) (vector? view)
view view

View File

@ -64,7 +64,8 @@
[status-im.ui.screens.wallet.transactions.views :as wallet-transactions] [status-im.ui.screens.wallet.transactions.views :as wallet-transactions]
[status-im.ui.screens.wallet.custom-tokens.views :as custom-tokens] [status-im.ui.screens.wallet.custom-tokens.views :as custom-tokens]
[status-im.ui.screens.wallet.accounts.views :as wallet.accounts] [status-im.ui.screens.wallet.accounts.views :as wallet.accounts]
[status-im.ui.screens.wallet.account.views :as wallet.account])) [status-im.ui.screens.wallet.account.views :as wallet.account]
[status-im.ui.screens.wallet.add-new.views :as add-account]))
(def all-screens (def all-screens
{:login login/login {:login login/login
@ -140,12 +141,11 @@
:contact-code wallet.components/contact-code :contact-code wallet.components/contact-code
:wallet-send-transaction send/send-transaction :wallet-send-transaction send/send-transaction
:recent-recipients wallet.components/recent-recipients :recent-recipients wallet.components/recent-recipients
:select-account wallet.components/accounts
:recipient-qr-code wallet.components/recipient-qr-code :recipient-qr-code wallet.components/recipient-qr-code
:wallet-send-assets wallet.components/send-assets :wallet-send-assets wallet.components/send-assets
:wallet-send-transaction-request request/send-transaction-request :wallet-send-transaction-request request/send-transaction-request
:wallet-request-assets wallet.components/request-assets :wallet-request-assets wallet.components/request-assets
:unsigned-transactions wallet-transactions/transactions
:transactions-history wallet-transactions/transactions
:wallet-transaction-details wallet-transactions/transaction-details :wallet-transaction-details wallet-transactions/transaction-details
:wallet-settings-hook wallet-settings/settings-hook :wallet-settings-hook wallet-settings/settings-hook
:selection-modal-screen [:modal extensions.module/selection-modal-screen-view] :selection-modal-screen [:modal extensions.module/selection-modal-screen-view]
@ -186,7 +186,10 @@
:keycard-settings hardwallet.settings/keycard-settings :keycard-settings hardwallet.settings/keycard-settings
:mobile-network-settings mobile-network-settings/mobile-network-settings :mobile-network-settings mobile-network-settings/mobile-network-settings
:welcome [:modal home/welcome] :welcome [:modal home/welcome]
:keycard-welcome keycard/welcome}) :keycard-welcome keycard/welcome
:add-new-account add-account/add-account
:add-new-account-password add-account/password
:account-added add-account/account-added})
(defn get-screen [screen] (defn get-screen [screen]
(get all-screens screen #(throw (str "Screen " screen " is not defined.")))) (get all-screens screen #(throw (str "Screen " screen " is not defined."))))

View File

@ -4,12 +4,16 @@
{:name :wallet-stack {:name :wallet-stack
:screens [:wallet :screens [:wallet
:wallet-account :wallet-account
:add-new-account
:add-new-account-password
:account-added
:collectibles-list :collectibles-list
:wallet-onboarding-setup :wallet-onboarding-setup
:contact-code :contact-code
{:name :send-transaction-stack {:name :send-transaction-stack
:screens [:wallet-send-transaction :screens [:wallet-send-transaction
:recent-recipients :recent-recipients
:select-account
:enter-pin-sign :enter-pin-sign
:hardwallet-connect-sign :hardwallet-connect-sign
:recipient-qr-code :recipient-qr-code
@ -18,8 +22,6 @@
:screens [:wallet-send-transaction-request :screens [:wallet-send-transaction-request
:wallet-request-assets :wallet-request-assets
:recent-recipients]} :recent-recipients]}
:unsigned-transactions
:transactions-history
:wallet-transaction-details :wallet-transaction-details
:wallet-settings-hook :wallet-settings-hook
:extension-screen-holder :extension-screen-holder

View File

@ -55,9 +55,9 @@
(multiaccounts/displayed-name contact) (multiaccounts/displayed-name contact)
(:address contact))) (:address contact)))
(defn contact-item [contact] (defn contact-item [title contact]
[list-item/list-item {:type :small [list-item/list-item {:type :small
:title (i18n/label :t/to) :title title
:accessories [[react/text {:ellipsize-mode :middle :number-of-lines 1 :style {:flex-wrap :wrap}} :accessories [[react/text {:ellipsize-mode :middle :number-of-lines 1 :style {:flex-wrap :wrap}}
(displayed-name contact)]]}]) (displayed-name contact)]]}])
@ -205,11 +205,11 @@
[react/text (or formatted-data "")]]] [react/text (or formatted-data "")]]]
[password-view sign]]])) [password-view sign]]]))
(views/defview sheet [{:keys [contact amount token approve?] :as tx}] (views/defview sheet [{:keys [from contact amount token approve?] :as tx}]
(views/letsubs [fee [:signing/fee] (views/letsubs [fee [:signing/fee]
sign [:signing/sign] sign [:signing/sign]
chain [:ethereum/chain-keyword] chain [:ethereum/chain-keyword]
{:keys [amount-error gas-error]} [:signing/amount-errors] {:keys [amount-error gas-error]} [:signing/amount-errors (:address from)]
keycard-multiaccount? [:keycard-multiaccount?]] keycard-multiaccount? [:keycard-multiaccount?]]
(let [display-symbol (wallet.utils/display-symbol token) (let [display-symbol (wallet.utils/display-symbol token)
fee-display-symbol (wallet.utils/display-symbol (tokens/native-currency chain))] fee-display-symbol (wallet.utils/display-symbol (tokens/native-currency chain))]
@ -220,7 +220,9 @@
[react/view {:padding-top 20} [react/view {:padding-top 20}
[password-view sign]] [password-view sign]]
[react/view [react/view
[contact-item contact] [contact-item (i18n/label :t/from) from]
[separator]
[contact-item (i18n/label :t/to) contact]
[separator] [separator]
[token-item token display-symbol] [token-item token display-symbol]
(when-not approve? (when-not approve?
@ -286,4 +288,4 @@
(views/letsubs [tx [:signing/tx] (views/letsubs [tx [:signing/tx]
{window-height :height} [:dimensions/window]] {window-height :height} [:dimensions/window]]
;;we use select-keys here because we don't want to update view if other keys in map is changed ;;we use select-keys here because we don't want to update view if other keys in map is changed
[signing-view (when tx (select-keys tx [:contact :amount :token :approve? :message])) window-height])) [signing-view (when tx (select-keys tx [:from :contact :amount :token :approve? :message])) window-height]))

View File

@ -23,7 +23,7 @@
(defview price-badge [price id owned pending] (defview price-badge [price id owned pending]
(letsubs [chain [:ethereum/chain-keyword] (letsubs [chain [:ethereum/chain-keyword]
balance [:balance]] balance [:balance-default]]
(let [snt (money/to-number (if (= :mainnet chain) (:SNT balance) (:STT balance))) (let [snt (money/to-number (if (= :mainnet chain) (:SNT balance) (:STT balance)))
not-enough-snt? (> price snt) not-enough-snt? (> price snt)
no-snt? (or (nil? snt) (zero? snt))] no-snt? (or (nil? snt) (zero? snt))]

View File

@ -1,9 +1,10 @@
(ns status-im.ui.screens.wallet.account.styles (ns status-im.ui.screens.wallet.account.styles
(:require [status-im.ui.components.colors :as colors])) (:require [status-im.ui.components.colors :as colors]))
(defn card [window-width] (defn card [window-width color]
{:width (- window-width 64) :height 161 {:width (- window-width 30)
:background-color colors/blue :height 161
:background-color color
:shadow-offset {:width 0 :height 2} :shadow-offset {:width 0 :height 2}
:shadow-radius 8 :shadow-radius 8
:shadow-opacity 1 :shadow-opacity 1

View File

@ -38,11 +38,11 @@
[icons/icon icon {:color colors/white}] [icons/icon icon {:color colors/white}]
[react/text {:style {:margin-left 8 :color colors/white}} label]]]]) [react/text {:style {:margin-left 8 :color colors/white}} label]]]])
(views/defview account-card [{:keys [address]}] (views/defview account-card [{:keys [address color]}]
(views/letsubs [currency [:wallet/currency] (views/letsubs [currency [:wallet/currency]
portfolio-value [:portfolio-value] portfolio-value [:account-portfolio-value address]
window-width [:dimensions/window-width]] window-width [:dimensions/window-width]]
[react/view {:style (styles/card window-width)} [react/view {:style (styles/card window-width color)}
[react/view {:padding 16 :padding-bottom 12 :flex 1 :justify-content :space-between} [react/view {:padding 16 :padding-bottom 12 :flex 1 :justify-content :space-between}
[react/nested-text {:style {:color colors/white-transparent :line-height 38 [react/nested-text {:style {:color colors/white-transparent :line-height 38
:font-weight "600" :font-size 32}} :font-weight "600" :font-size 32}}
@ -66,20 +66,19 @@
[react/view {:style styles/divider}] [react/view {:style styles/divider}]
[button (i18n/label :t/receive) :main-icons/receive #(re-frame/dispatch [:show-popover {:view :share-account :address address}])]]])) [button (i18n/label :t/receive) :main-icons/receive #(re-frame/dispatch [:show-popover {:view :share-account :address address}])]]]))
(views/defview transactions [] (views/defview transactions [address]
(views/letsubs [{:keys [transaction-history-sections]} (views/letsubs [{:keys [transaction-history-sections]}
[:wallet.transactions.history/screen]] [:wallet.transactions.history/screen address]]
[history/history-list transaction-history-sections])) [history/history-list transaction-history-sections]))
(views/defview assets-and-collections [] (views/defview assets-and-collections [address]
(views/letsubs [{:keys [tokens nfts]} [:wallet/visible-assets-with-values] (views/letsubs [{:keys [tokens nfts]} [:wallet/visible-assets-with-values address]
currency [:wallet/currency]] currency [:wallet/currency]]
(let [{:keys [tab]} @state] (let [{:keys [tab]} @state]
[react/view {:flex 1} [react/view {:flex 1}
[react/view {:flex-direction :row :margin-bottom 8 :padding-horizontal 4} [react/view {:flex-direction :row :margin-bottom 8 :padding-horizontal 4}
[accounts/tab-title state :assets (i18n/label :t/wallet-assets) (= tab :assets)] [accounts/tab-title state :assets (i18n/label :t/wallet-assets) (= tab :assets)]
(when (seq nfts) [accounts/tab-title state :nft (i18n/label :t/wallet-collectibles) (= tab :nft)]
[accounts/tab-title state :nft (i18n/label :t/wallet-collectibles) (= tab :nft)])
[accounts/tab-title state :history (i18n/label :t/history) (= tab :history)]] [accounts/tab-title state :history (i18n/label :t/history) (= tab :history)]]
(cond (cond
(= tab :assets) (= tab :assets)
@ -91,18 +90,22 @@
:align-self :stretch}}] :align-self :stretch}}]
:render-fn (accounts/render-asset (:code currency))}] :render-fn (accounts/render-asset (:code currency))}]
(= tab :nft) (= tab :nft)
[list/flat-list {:data nfts (if (seq nfts)
:default-separator? false [list/flat-list {:data nfts
:key-fn :name :default-separator? false
:footer [react/view :key-fn :name
{:style {:height tabs.styles/tabs-diff :footer [react/view
:align-self :stretch}}] {:style {:height tabs.styles/tabs-diff
:render-fn accounts/render-collectible}] :align-self :stretch}}]
:render-fn accounts/render-collectible}]
[react/view {:align-items :center :margin-top 32}
[react/text {:style {:color colors/gray}}
(i18n/label :t/no-collectibles)]])
(= tab :history) (= tab :history)
[transactions])]))) [transactions address])])))
(views/defview account [] (views/defview account []
(views/letsubs [{:keys [name] :as account} [:get-screen-params]] (views/letsubs [{:keys [name address] :as account} [:get-screen-params]]
[react/view {:flex 1 :background-color colors/white} [react/view {:flex 1 :background-color colors/white}
[toolbar-view name] [toolbar-view name]
[react/scroll-view [react/scroll-view
@ -110,4 +113,4 @@
[react/scroll-view {:horizontal true} [react/scroll-view {:horizontal true}
[react/view {:flex-direction :row :padding-top 8 :padding-bottom 12} [react/view {:flex-direction :row :padding-top 8 :padding-bottom 12}
[account-card account]]]] [account-card account]]]]
[assets-and-collections]]])) [assets-and-collections address]]]))

View File

@ -50,10 +50,10 @@
(defn add-account [] (defn add-account []
[react/view [react/view
[action-button/action-button-disabled {:label (i18n/label :t/add-an-account) [action-button/action-button {:label (i18n/label :t/add-an-account)
:icon :main-icons/add :icon :main-icons/add
:icon-opts {:color :blue} :icon-opts {:color :blue}
:on-press #(hide-sheet-and-dispatch [:navigate-to])}] :on-press #(hide-sheet-and-dispatch [:navigate-to :add-new-account])}]
[action-button/action-button-disabled {:label (i18n/label :t/add-a-watch-account) [action-button/action-button-disabled {:label (i18n/label :t/add-a-watch-account)
:icon :main-icons/watch :icon :main-icons/watch
:icon-opts {:color :blue} :icon-opts {:color :blue}

View File

@ -4,6 +4,7 @@
(defn card [color] (defn card [color]
{:width 156 {:width 156
:height 145 :height 145
:margin-right 16
:background-color color :background-color color
:shadow-offset {:width 0 :height 2} :shadow-offset {:width 0 :height 2}
:shadow-radius 8 :shadow-radius 8
@ -20,7 +21,6 @@
(def add-card (def add-card
{:width 156 {:width 156
:height 145 :height 145
:margin-left 16
:margin-top 5 :margin-top 5
:margin-right 5 :margin-right 5
:margin-bottom 5 :margin-bottom 5

View File

@ -25,7 +25,7 @@
(views/defview account-card [{:keys [name color address] :as account}] (views/defview account-card [{:keys [name color address] :as account}]
(views/letsubs [currency [:wallet/currency] (views/letsubs [currency [:wallet/currency]
portfolio-value [:portfolio-value]] portfolio-value [:account-portfolio-value address]]
[react/touchable-highlight {:on-press #(re-frame/dispatch [:navigate-to :wallet-account account]) [react/touchable-highlight {:on-press #(re-frame/dispatch [:navigate-to :wallet-account account])
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet :on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [sheets/send-receive address]) {:content (fn [] [sheets/send-receive address])
@ -97,7 +97,7 @@
:accessories [items-number :chevron]}]])) :accessories [items-number :chevron]}]]))
(views/defview assets-and-collections [] (views/defview assets-and-collections []
(views/letsubs [{:keys [tokens nfts]} [:wallet/visible-assets-with-values] (views/letsubs [{:keys [tokens nfts]} [:wallet/all-visible-assets-with-values]
currency [:wallet/currency]] currency [:wallet/currency]]
(let [{:keys [tab]} @state] (let [{:keys [tab]} @state]
[react/view {:flex 1} [react/view {:flex 1}

View File

@ -0,0 +1,127 @@
(ns status-im.ui.screens.wallet.add-new.views
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [status-im.ui.components.react :as react]
[status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.i18n :as i18n]
[re-frame.core :as re-frame]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.list-header.views :as list-header]
[status-im.ui.components.list-item.views :as list-item]
[status-im.ui.components.common.common :as components.common]
[status-im.ui.components.icons.vector-icons :as icons]
[status-im.ui.components.text-input.view :as text-input]
[reagent.core :as reagent]
[clojure.string :as string]
[cljs.spec.alpha :as spec]
[status-im.multiaccounts.db :as multiaccounts.db]))
(defn add-account []
[react/view {:flex 1}
[status-bar/status-bar]
[toolbar/toolbar {:transparent? true} toolbar/default-nav-back nil]
[react/scroll-view {:keyboard-should-persist-taps :handled
:style {:flex 1}}
[react/view {:align-items :center :padding-horizontal 40}
[react/text {:style {:typography :header :margin-top 16}} (i18n/label :t/add-an-account)]
[react/text {:style {:color colors/gray :text-align :center :margin-top 16 :line-height 22}}
(i18n/label :t/add-account-description)]]
[react/view {:height 52}]
[list-header/list-header (i18n/label :t/default)]
[list-item/list-item {:title (i18n/label :t/generate-a-new-account) :theme :action
:icon :main-icons/add :accessories [:chevron]
:on-press #(re-frame/dispatch [:navigate-to :add-new-account-password])}]]])
(defview colors-popover [selected-color]
(letsubs [width [:dimensions/window-width]]
[react/view {:padding-bottom 16}
[react/scroll-view {:style {:margin 16}}
(doall
(for [color colors/account-colors]
^{:key color}
[react/touchable-highlight {:on-press #(do
(re-frame/dispatch [:set-in [:generate-account :account :color] color])
(re-frame/dispatch [:hide-popover]))}
[react/view {:height 52 :background-color color :border-radius 8 :width (* 0.7 width)
:justify-content :center :padding-left 12 :margin-bottom 16}
[react/view {:height 32 :width 32 :border-radius 20 :align-items :center :justify-content :center
:background-color colors/black-transparent}
(when (= selected-color color)
[icons/icon :main-icons/check {:color colors/white}])]]]))]
[components.common/button {:on-press #(re-frame/dispatch [:hide-popover])
:label (i18n/label :t/cancel)
:background? false}]]))
(defview account-added []
(letsubs [{:keys [account]} [:generate-account]]
[react/keyboard-avoiding-view {:flex 1}
[status-bar/status-bar]
[react/scroll-view {:keyboard-should-persist-taps :handled
:style {:margin-top 70 :flex 1}}
[react/view {:align-items :center :padding-horizontal 40}
[react/view {:height 40 :width 40 :border-radius 20 :align-items :center :justify-content :center
:background-color (:color account)}
[icons/icon :main-icons/check {:color colors/white}]]
[react/text {:style {:typography :header :margin-top 16}}
(i18n/label :t/account-added)]
[react/text {:style {:color colors/gray :text-align :center :margin-top 16 :line-height 22}}
(i18n/label :t/you-can-change-account)]]
[react/view {:height 52}]
[react/view {:margin-horizontal 16}
[text-input/text-input-with-label
{:label (i18n/label :t/account-name)
:auto-focus false
:default-value (:name account)
:on-change-text #(re-frame/dispatch [:set-in [:generate-account :account :name] %])}]
[react/text {:style {:margin-top 30}} (i18n/label :t/account-color)]
[react/touchable-highlight {:on-press #(re-frame/dispatch [:show-popover {:view [colors-popover (:color account)]
:style {:max-height "60%"}}])}
[react/view {:height 52 :margin-top 12 :background-color (:color account) :border-radius 8
:align-items :flex-end :justify-content :center :padding-right 12}
[icons/icon :main-icons/dropdown {:color colors/white}]]]]]
[react/view {:style {:flex-direction :row
:justify-content :flex-end
:align-self :stretch
:padding-vertical 16
:border-top-width 1
:border-top-color colors/gray-lighter
:padding-right 12}}
[components.common/bottom-button {:label (i18n/label :t/finish)
:on-press #(re-frame/dispatch [:wallet.accounts/save-generated-account])
:disabled? (string/blank? (:name account))
:forward? true}]]]))
(defview password []
(letsubs [{:keys [error]} [:generate-account]
entered-password (reagent/atom "")]
[react/keyboard-avoiding-view {:style {:flex 1}}
[status-bar/status-bar {:flat? true}]
[toolbar/toolbar {:transparent? true} toolbar/default-nav-back nil]
[react/view {:flex 1}
[react/view {:style {:flex 1
:justify-content :space-between
:align-items :center :margin-horizontal 16}}
[react/text {:style {:typography :header :margin-top 16}} (i18n/label :t/enter-your-password)]
[react/view {:style {:justify-content :center :flex 1}}
[react/text-input {:secure-text-entry true
:auto-focus true
:text-align :center
:placeholder ""
:style {:typography :header}
:on-change-text #(reset! entered-password %)}]
(when error
[react/text {:style {:text-align :center :color colors/red :margin-top 76}} error])]
[react/text {:style {:color colors/gray :text-align :center :margin-bottom 16}}
(i18n/label :t/to-encrypt-enter-password)]]
[react/view {:style {:flex-direction :row
:justify-content :flex-end
:align-self :stretch
:padding-vertical 16
:border-top-width 1
:border-top-color colors/gray-lighter
:padding-right 12}}
[components.common/bottom-button {:label (i18n/label :t/generate-account)
:on-press #(re-frame/dispatch
[:wallet.accounts/generate-new-account @entered-password])
:disabled? (not (spec/valid? ::multiaccounts.db/password @entered-password))
:forward? true}]]]]))

View File

@ -29,7 +29,8 @@
[status-im.wallet.utils :as wallet.utils] [status-im.wallet.utils :as wallet.utils]
[status-im.utils.core :as utils.core] [status-im.utils.core :as utils.core]
[status-im.utils.money :as money] [status-im.utils.money :as money]
[status-im.utils.utils :as utils.utils]) [status-im.utils.utils :as utils.utils]
[status-im.ui.components.chat-icon.screen :as chat-icon.screen])
(:require-macros [status-im.utils.views :as views])) (:require-macros [status-im.utils.views :as views]))
;; Wallet tab has a different coloring scheme (dark) that forces color changes (background, text) ;; Wallet tab has a different coloring scheme (dark) that forces color changes (background, text)
@ -120,8 +121,8 @@
(wallet.utils/display-symbol token)]] (wallet.utils/display-symbol token)]]
[list/item-secondary (wallet.utils/format-amount amount decimals)]]]]]) [list/item-secondary (wallet.utils/format-amount amount decimals)]]]]])
(views/defview assets [type] (views/defview assets [type address]
(views/letsubs [assets [:wallet/transferrable-assets-with-amount]] (views/letsubs [assets [:wallet/transferrable-assets-with-amount address]]
[simple-screen [simple-screen
[toolbar (i18n/label :t/wallet-assets)] [toolbar (i18n/label :t/wallet-assets)]
[react/view {:style (assoc components.styles/flex :background-color :white)} [react/view {:style (assoc components.styles/flex :background-color :white)}
@ -130,11 +131,13 @@
:key-fn (comp str :symbol) :key-fn (comp str :symbol)
:render-fn #(render-token % type)}]]])) :render-fn #(render-token % type)}]]]))
(defn send-assets [] (views/defview send-assets []
[assets :send]) (views/letsubs [address [:get-screen-params]]
[assets :send address]))
(defn request-assets [] (views/defview request-assets []
[assets :request]) (views/letsubs [address [:get-screen-params]]
[assets :request address]))
(defn- type->view [k] (defn- type->view [k]
(case k (case k
@ -142,14 +145,14 @@
:request :wallet-request-assets :request :wallet-request-assets
(throw (str "Unknown type: " k)))) (throw (str "Unknown type: " k))))
(views/defview asset-selector [{:keys [disabled? type symbol error]}] (views/defview asset-selector [{:keys [disabled? type symbol error address]}]
(views/letsubs [balance [:balance] (views/letsubs [balance [:balance address]
chain [:ethereum/chain-keyword] chain [:ethereum/chain-keyword]
all-tokens [:wallet/all-tokens]] all-tokens [:wallet/all-tokens]]
(let [{:keys [name icon decimals color] :as token} (tokens/asset-for all-tokens chain symbol)] (let [{:keys [name icon decimals color] :as token} (tokens/asset-for all-tokens chain symbol)]
(when name (when name
[react/view [react/view
[cartouche {:disabled? disabled? :on-press #(re-frame/dispatch [:navigate-to (type->view type)])} [cartouche {:disabled? disabled? :on-press #(re-frame/dispatch [:navigate-to (type->view type) address])}
(i18n/label :t/wallet-asset) (i18n/label :t/wallet-asset)
[react/view {:style styles/asset-content-container [react/view {:style styles/asset-content-container
:accessibility-label :choose-asset-button} :accessibility-label :choose-asset-button}
@ -202,6 +205,17 @@
:accessibility-label :contact-address-text} :accessibility-label :contact-address-text}
(eip55/address->checksum (ethereum/normalized-address (:address contact)))]]]]) (eip55/address->checksum (ethereum/normalized-address (:address contact)))]]]])
(defn render-account [account]
[list/touchable-item #(re-frame/dispatch [:wallet/fill-request-from-contact account false])
[list/item
[chat-icon/custom-icon-view-list (:name account) (:color account)]
[list/item-content
[list/item-primary {:accessibility-label :contact-name-text}
(:name account)]
[react/text {:style list.styles/secondary-text
:accessibility-label :contact-address-text}
(eip55/address->checksum (ethereum/normalized-address (:address account)))]]]])
(views/defview recent-recipients [] (views/defview recent-recipients []
(views/letsubs [contacts [:contacts/active] (views/letsubs [contacts [:contacts/active]
{:keys [request?]} [:get-screen-params :recent-recipients]] {:keys [request?]} [:get-screen-params :recent-recipients]]
@ -212,6 +226,15 @@
:key-fn :address :key-fn :address
:render-fn #(render-contact % request?)}]]])) :render-fn #(render-contact % request?)}]]]))
(views/defview accounts []
(views/letsubs [{:keys [accounts]} [:multiaccount]]
[simple-screen
[toolbar (i18n/label :t/accounts)]
[react/view styles/recent-recipients
[list/flat-list {:data accounts
:key-fn :address
:render-fn render-account}]]]))
(defn contact-code [] (defn contact-code []
(let [content (reagent/atom nil)] (let [content (reagent/atom nil)]
(fn [] (fn []
@ -252,7 +275,9 @@
[{:label (i18n/label :t/recent-recipients) [{:label (i18n/label :t/recent-recipients)
:action #(re-frame/dispatch [:navigate-to :recent-recipients {:request? request?}])}] :action #(re-frame/dispatch [:navigate-to :recent-recipients {:request? request?}])}]
(when-not contact-only?)) (when-not contact-only?))
:options [{:label (i18n/label :t/scan-qr) :options [{:label (i18n/label :t/accounts)
:action #(re-frame/dispatch [:navigate-to :select-account])}
{:label (i18n/label :t/scan-qr)
:action request-camera-permissions} :action request-camera-permissions}
{:label (i18n/label :t/recipient-code) {:label (i18n/label :t/recipient-code)
:action #(re-frame/dispatch [:navigate-to :contact-code])}]})) :action #(re-frame/dispatch [:navigate-to :contact-code])}]}))

View File

@ -82,12 +82,12 @@
:auto-focus false :auto-focus false
:placeholder "18"}]]] :placeholder "18"}]]]
[react/view {:height 16}] [react/view {:height 16}]
[text-input/text-input-with-label #_[text-input/text-input-with-label
{:label (i18n/label :t/balance) {:label (i18n/label :t/balance)
:default-value (when (and balance decimals) :default-value (when (and balance decimals)
(wallet.utils/format-amount balance decimals)) (wallet.utils/format-amount balance decimals))
:editable false :editable false
:placeholder (i18n/label :t/no-tokens-found)}]] :placeholder (i18n/label :t/no-tokens-found)}]]
[react/view {:style {:height 1 :background-color colors/gray-lighter}}] [react/view {:style {:height 1 :background-color colors/gray-lighter}}]
[react/view {:flex-direction :row [react/view {:flex-direction :row
:margin-horizontal 12 :margin-horizontal 12

View File

@ -32,3 +32,7 @@
(defmethod navigation/preload-data! :wallet-add-custom-token (defmethod navigation/preload-data! :wallet-add-custom-token
[db [event]] [db [event]]
(dissoc db :wallet/custom-token-screen)) (dissoc db :wallet/custom-token-screen))
(defmethod navigation/preload-data! :add-new-account
[db [event]]
(dissoc db :generate-account))

View File

@ -80,7 +80,7 @@
(eip55/address->checksum address)]]] (eip55/address->checksum address)]]]
[react/view {:height 1 :background-color colors/gray-lighter :margin-top 8}] [react/view {:height 1 :background-color colors/gray-lighter :margin-top 8}]
[react/view {:padding-bottom 16} [react/view {:padding-bottom 16}
[components.common/button {:on-press #(re-frame/dispatch [:wallet.accounts/share]) [components.common/button {:on-press #(re-frame/dispatch [:wallet.accounts/share address])
:button-style {:margin-vertical 20 :margin-horizontal 16} :button-style {:margin-vertical 20 :margin-horizontal 16}
:accessibility-label :share-address-button :accessibility-label :share-address-button
:label (i18n/label :t/share-address)}] :label (i18n/label :t/share-address)}]

View File

@ -36,7 +36,7 @@
colors/white-light-transparent)}]]]) colors/white-light-transparent)}]]])
(defn- render-send-transaction-view [{:keys [chain transaction scroll all-tokens amount-input network-status]}] (defn- render-send-transaction-view [{:keys [chain transaction scroll all-tokens amount-input network-status]}]
(let [{:keys [amount amount-text amount-error asset-error to to-name sufficient-funds? symbol]} transaction (let [{:keys [from amount amount-text amount-error asset-error to to-name sufficient-funds? symbol]} transaction
{:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol) {:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol)
online? (= :online network-status)] online? (= :online network-status)]
[wallet.components/simple-screen {:avoid-keyboard? true [wallet.components/simple-screen {:avoid-keyboard? true
@ -54,6 +54,7 @@
:name to-name}] :name to-name}]
[wallet.components/asset-selector [wallet.components/asset-selector
{:error asset-error {:error asset-error
:address from
:type :send :type :send
:symbol symbol}] :symbol symbol}]
[wallet.components/amount-selector [wallet.components/amount-selector

View File

@ -34,6 +34,7 @@
(def empty-text (def empty-text
{:text-align :center {:text-align :center
:color colors/gray
:margin-top 22 :margin-top 22
:margin-horizontal 92}) :margin-horizontal 92})

View File

@ -11,17 +11,14 @@
[status-im.ui.screens.wallet.transactions.styles :as styles]) [status-im.ui.screens.wallet.transactions.styles :as styles])
(:require-macros [status-im.utils.views :refer [defview letsubs]])) (:require-macros [status-im.utils.views :refer [defview letsubs]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TRANSACTION HISTORY
;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn history-action (defn history-action
[all-filters?] [all-filters?]
(cond-> (cond-> {:icon :main-icons/filter
{:icon :main-icons/filter :icon-opts {:accessibility-label :filters-button}
:icon-opts {:accessibility-label :filters-button} :handler #(re-frame/dispatch [:navigate-to :wallet-transactions-filter])}
:handler #(re-frame/dispatch [:navigate-to :wallet-transactions-filter])}
(not all-filters?) (assoc-in [:icon-opts :overlay-style] styles/corner-dot))) (not all-filters?)
(assoc-in [:icon-opts :overlay-style] styles/corner-dot)))
(defn- toolbar-view (defn- toolbar-view
[all-filters?] [all-filters?]
@ -102,19 +99,6 @@
:key :transactions-history-empty}] :key :transactions-history-empty}]
:refreshing false}]]) :refreshing false}]])
(defview transactions
[]
(letsubs [{:keys [transaction-history-sections all-filters?]}
[:wallet.transactions.history/screen]]
[react/view styles/transactions-view
[status-bar/status-bar]
[toolbar-view all-filters?]
[history-list transaction-history-sections]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TRANSACTION FILTERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- render-item-filter [{:keys [id label checked? on-touch]}] (defn- render-item-filter [{:keys [id label checked? on-touch]}]
[react/view {:accessibility-label :filter-item} [react/view {:accessibility-label :filter-item}
[list/list-item-with-checkbox [list/list-item-with-checkbox
@ -151,10 +135,6 @@
:data filters}] :data filters}]
:key-fn :id}]]])) :key-fn :id}]]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TRANSACTION DETAILS
;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn details-header (defn details-header
[date type amount-text currency-text] [date type amount-text currency-text]
[react/view {:style styles/details-header} [react/view {:style styles/details-header}
@ -237,11 +217,11 @@
{:label (i18n/label :t/open-on-etherscan) {:label (i18n/label :t/open-on-etherscan)
:action #(.openURL (react/linking) url)}])]) :action #(.openURL (react/linking) url)}])])
(defview transaction-details [] (defview transaction-details-view [hash address]
(letsubs [{:keys [hash url type confirmations confirmations-progress (letsubs [{:keys [url type confirmations confirmations-progress
date amount-text currency-text] date amount-text currency-text]
:as transaction} :as transaction}
[:wallet.transactions.details/screen]] [:wallet.transactions.details/screen hash address]]
[react/view {:style components.styles/flex} [react/view {:style components.styles/flex}
[status-bar/status-bar] [status-bar/status-bar]
[toolbar/toolbar {} [toolbar/toolbar {}
@ -253,3 +233,8 @@
[details-confirmations confirmations confirmations-progress (= :failed type)] [details-confirmations confirmations confirmations-progress (= :failed type)]
[react/view {:style styles/details-separator}] [react/view {:style styles/details-separator}]
[details-list transaction]]])) [details-list transaction]]]))
(defview transaction-details []
(letsubs [{:keys [hash address]} [:get-screen-params]]
(when (and hash address)
[transaction-details-view hash address])))

View File

@ -4,14 +4,67 @@
[status-im.utils.fx :as fx] [status-im.utils.fx :as fx]
[status-im.ethereum.eip55 :as eip55] [status-im.ethereum.eip55 :as eip55]
[status-im.ui.components.list-selection :as list-selection] [status-im.ui.components.list-selection :as list-selection]
[status-im.utils.handlers :as handlers])) [status-im.utils.handlers :as handlers]
[status-im.native-module.core :as status]
[status-im.utils.types :as types]
[status-im.constants :as constants]
[status-im.ui.components.colors :as colors]
[status-im.ui.screens.navigation :as navigation]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.wallet.core :as wallet]
[status-im.i18n :as i18n]))
(re-frame/reg-fx (re-frame/reg-fx
:list.selection/open-share :list.selection/open-share
(fn [obj] (fn [obj]
(list-selection/open-share obj))) (list-selection/open-share obj)))
(re-frame/reg-fx
:wallet.accounts/generate-account
(fn [{:keys [address password path-num]}]
(status/multiaccount-load-account
address
password
(fn [value]
(let [{:keys [id error]} (types/json->clj value)]
(if error
(re-frame/dispatch [:set-in [:generate-account :error] (i18n/label :t/add-account-incorrect-password)])
(let [path (str constants/path-root "/" path-num)]
(status/multiaccount-derive-addresses
id
[path]
#(re-frame/dispatch [:wallet.accounts/account-generated
(merge
(get (types/json->clj %) (keyword path))
{:name (str "Account " path-num)
:color (rand-nth colors/account-colors)})])))))))))
(fx/defn set-symbol-request (fx/defn set-symbol-request
{:events [:wallet.accounts/share]} {:events [:wallet.accounts/share]}
[{:keys [db]}] [_ address]
{:list.selection/open-share {:message (eip55/address->checksum (ethereum/default-address db))}}) {:list.selection/open-share {:message (eip55/address->checksum address)}})
(fx/defn generate-new-account
{:events [:wallet.accounts/generate-new-account]}
[{:keys [db]} password]
{:wallet.accounts/generate-account {:address (get-in db [:multiaccount :address])
:path-num (inc (get-in db [:multiaccount :latest-derived-path]))
:password password}})
(fx/defn account-generated
{:events [:wallet.accounts/account-generated]}
[{:keys [db] :as cofx} account]
(fx/merge cofx
{:db (assoc db :generate-account {:account account})}
(navigation/navigate-to-cofx :account-added nil)))
(fx/defn save-account
{:events [:wallet.accounts/save-generated-account]}
[{:keys [db] :as cofx}]
(let [new-account (get-in db [:generate-account :account])
{:keys [accounts latest-derived-path]} (:multiaccount db)]
(fx/merge cofx
(multiaccounts.update/multiaccount-update {:accounts (conj accounts new-account)
:latest-derived-path (inc latest-derived-path)} nil)
(wallet/update-balances nil)
(navigation/navigate-to-cofx :wallet nil))))

View File

@ -29,6 +29,16 @@
:on-success on-success :on-success on-success
:on-error on-error}))) :on-error on-error})))
(re-frame/reg-fx
:wallet/get-balances
(fn [addresses]
(doseq [address addresses]
(json-rpc/call
{:method "eth_getBalance"
:params [address "latest"]
:on-success #(re-frame/dispatch [:wallet.callback/update-balance-success address %])
:on-error #(re-frame/dispatch [:wallet.callback/update-balance-fail %])}))))
;; TODO(oskarth): At some point we want to get list of relevant ;; TODO(oskarth): At some point we want to get list of relevant
;; assets to get prices for ;; assets to get prices for
(re-frame/reg-fx (re-frame/reg-fx
@ -55,21 +65,17 @@
[{:keys [db]} err] [{:keys [db]} err]
(log/debug "Unable to get balance: " err) (log/debug "Unable to get balance: " err)
{:db (-> db {:db (-> db
(assoc-error-message :balance-update :error-unable-to-get-balance) (assoc-error-message :balance-update :error-unable-to-get-balance))})
(assoc-in [:wallet :balance-loading?] false))})
(fx/defn on-update-token-balance-fail (fx/defn on-update-token-balance-fail
[{:keys [db]} symbol err] [{:keys [db]} symbol err]
(log/debug "Unable to get token " symbol "balance: " err) (log/debug "Unable to get token " symbol "balance: " err)
{:db (-> db {:db (-> db
(assoc-error-message :balance-update :error-unable-to-get-token-balance) (assoc-error-message :balance-update :error-unable-to-get-token-balance))})
(assoc-in [:wallet :balance-loading?] false))})
(fx/defn open-transaction-details (fx/defn open-transaction-details
[{:keys [db] :as cofx} hash] [{:keys [db] :as cofx} hash address]
(fx/merge cofx (navigation/navigate-to-cofx cofx :wallet-transaction-details {:hash hash :address address}))
{:db (assoc-in db [:wallet :current-transaction] hash)}
(navigation/navigate-to-cofx :wallet-transaction-details nil)))
(defn- validate-token-name! (defn- validate-token-name!
[{:keys [address symbol name]}] [{:keys [address symbol name]}]
@ -136,18 +142,23 @@
(validate-token-name! token)))) (validate-token-name! token))))
(re-frame/reg-fx (re-frame/reg-fx
:wallet/get-tokens-balance :wallet/get-tokens-balances
(fn [{:keys [account-address tokens on-success on-error]}] (fn [{:keys [addresses tokens assets]}]
;;TODO not great to have so many calls , should be optimized, there is wallet_getTokensBalances why wouldn't use it?
(doseq [{:keys [address symbol]} tokens] (doseq [{:keys [address symbol]} tokens]
(json-rpc/eth-call (doseq [account-address addresses]
{:contract address (json-rpc/eth-call
:method "balanceOf(address)" {:contract address
:params [account-address] :method "balanceOf(address)"
:outputs ["uint256"] :params [account-address]
:on-success :outputs ["uint256"]
(fn [[balance]] :on-success (fn [[balance]]
(on-success symbol (money/bignumber balance))) (if (and assets (assets symbol))
:on-error #(on-error symbol %)})))) (re-frame/dispatch [:wallet.callback/update-token-balance-success account-address symbol balance])
;; NOTE: when there it is not a visible assets we make an initialization round
(when (pos? balance)
(re-frame/dispatch [:wallet/token-found account-address symbol balance]))))
:on-error #(re-frame/dispatch [:wallet.callback/update-token-balance-fail symbol %])})))))
(defn clear-error-message [db error-type] (defn clear-error-message [db error-type]
(update-in db [:wallet :errors] dissoc error-type)) (update-in db [:wallet :errors] dissoc error-type))
@ -175,46 +186,22 @@
{:wallet/validate-tokens (get tokens/all-default-tokens chain)}))))) {:wallet/validate-tokens (get tokens/all-default-tokens chain)})))))
(fx/defn update-balances (fx/defn update-balances
[{{:keys [network-status :wallet/all-tokens] [{{:keys [network-status :wallet/all-tokens]
{:keys [settings]} :multiaccount :as db} :db :as cofx}] {:keys [settings accounts]} :multiaccount :as db} :db :as cofx} addresses]
(let [normalized-address (ethereum/current-address db) (let [addresses (or addresses (map :address accounts))
chain (ethereum/chain-keyword db) chain (ethereum/chain-keyword db)
assets (get-in settings [:wallet :visible-tokens chain]) assets (get-in settings [:wallet :visible-tokens chain])
tokens (->> (tokens/tokens-for all-tokens chain) tokens (->> (tokens/tokens-for all-tokens chain)
(remove #(or (:hidden? %))))] (remove #(or (:hidden? %))))]
(when (not= network-status :offline) (when (not= network-status :offline)
(fx/merge (fx/merge
cofx cofx
{:wallet/get-balance {:wallet/get-balances addresses
{:account-address normalized-address :wallet/get-tokens-balances {:addresses addresses
:on-success #(re-frame/dispatch :assets assets
[:wallet.callback/update-balance-success %]) :tokens tokens}
:on-error #(re-frame/dispatch :db (-> db
[:wallet.callback/update-balance-fail %])} (clear-error-message :balance-update))}
:wallet/get-tokens-balance
{:account-address normalized-address
:tokens tokens
:on-success
(fn [symbol balance]
(if (and assets
(assets symbol))
(re-frame/dispatch
[:wallet.callback/update-token-balance-success symbol balance])
;; NOTE: when there it is not a visible assets
;; we make an initialization round
(when (> balance 0)
(re-frame/dispatch
[:wallet/token-found symbol balance]))))
:on-error
(fn [symbol error]
(re-frame/dispatch
[:wallet.callback/update-token-balance-fail symbol error]))}
:db
(-> db
(clear-error-message :balance-update)
(assoc-in [:wallet :balance-loading?] true))}
(when-not assets (when-not assets
(multiaccounts.update/update-settings (multiaccounts.update/update-settings
(assoc-in settings (assoc-in settings
@ -260,16 +247,14 @@
:prices-loading? false)}) :prices-loading? false)})
(fx/defn update-balance (fx/defn update-balance
[{:keys [db]} balance] [{:keys [db]} address balance]
{:db (-> db {:db (-> db
(assoc-in [:wallet :balance :ETH] (money/bignumber balance)) (assoc-in [:wallet :accounts address :balance :ETH] (money/bignumber balance)))})
(assoc-in [:wallet :balance-loading?] false))})
(fx/defn update-token-balance (fx/defn update-token-balance
[{:keys [db]} symbol balance] [{:keys [db]} address symbol balance]
{:db (-> db {:db (-> db
(assoc-in [:wallet :balance symbol] (money/bignumber balance)) (assoc-in [:wallet :accounts address :balance symbol] (money/bignumber balance)))})
(assoc-in [:wallet :balance-loading?] false))})
(defn update-toggle-in-settings (defn update-toggle-in-settings
[{{:keys [multiaccount] :as db} :db} symbol checked?] [{{:keys [multiaccount] :as db} :db} symbol checked?]
@ -297,11 +282,11 @@
(multiaccounts.update/update-settings cofx new-settings {}))) (multiaccounts.update/update-settings cofx new-settings {})))
(fx/defn configure-token-balance-and-visibility (fx/defn configure-token-balance-and-visibility
[cofx symbol balance] [cofx address symbol balance]
(fx/merge cofx (fx/merge cofx
(toggle-visible-token symbol true) (toggle-visible-token symbol true)
;;TODO(goranjovic): move `update-token-balance-success` function to wallet models ;;TODO(goranjovic): move `update-token-balance-success` function to wallet models
(update-token-balance symbol balance))) (update-token-balance address symbol balance)))
(defn set-and-validate-amount-db [db amount symbol decimals] (defn set-and-validate-amount-db [db amount symbol decimals]
(let [{:keys [value error]} (wallet.db/parse-amount amount decimals)] (let [{:keys [value error]} (wallet.db/parse-amount amount decimals)]

View File

@ -91,8 +91,7 @@
(fx/defn total-supply-result (fx/defn total-supply-result
[{:keys [db]} contract total-supply] [{:keys [db]} contract total-supply]
(if (money/valid? total-supply) (if (money/valid? total-supply)
{:wallet.custom-token/get-balance {:wallet.custom-token/get-name contract}
[contract (ethereum/default-address db)]}
{:db (update db {:db (update db
:wallet/custom-token-screen :wallet/custom-token-screen
merge {:in-progress? nil merge {:in-progress? nil

View File

@ -66,8 +66,7 @@
#{:inbound :outbound :pending :failed}) #{:inbound :outbound :pending :failed})
(def default-wallet (def default-wallet
{:filters default-wallet-filters {:filters default-wallet-filters})
:transactions empty-transaction-map})
(defn get-confirmations (defn get-confirmations
[{:keys [block]} current-block] [{:keys [block]} current-block]

View File

@ -26,7 +26,8 @@
(testing "first tx object is parsed" (testing "first tx object is parsed"
(is (= (dissoc (get-in sign-first [:db :signing/tx]) :token) (is (= (dissoc (get-in sign-first [:db :signing/tx]) :token)
(merge first-tx (merge first-tx
{:gas nil {:from {:address nil}
:gas nil
:gasPrice nil :gasPrice nil
:data nil :data nil
:to to :to to
@ -49,7 +50,8 @@
(testing "second tx object is parsed" (testing "second tx object is parsed"
(is (= (dissoc (get-in first-discarded [:db :signing/tx]) :token) (is (= (dissoc (get-in first-discarded [:db :signing/tx]) :token)
(merge second-tx (merge second-tx
{:gas nil {:from {:address nil}
:gas nil
:gasPrice nil :gasPrice nil
:data data :data data
:to contract :to contract

View File

@ -173,7 +173,7 @@
"intro-wizard-text7": "Status will notify you about new messages. You can edit your notification preferences later in settings", "intro-wizard-text7": "Status will notify you about new messages. You can edit your notification preferences later in settings",
"generate-a-key": "Generate a key", "generate-a-key": "Generate a key",
"generate-a-new-key": "Generate a new key", "generate-a-new-key": "Generate a new key",
"enter-your-password": "Enter your password...", "enter-your-password": "Enter your password",
"generating-keys": "Generating keys...", "generating-keys": "Generating keys...",
"you-will-need-this-code": "You'll need this code to open Status and sign transactions", "you-will-need-this-code": "You'll need this code to open Status and sign transactions",
"this-device": "This device", "this-device": "This device",
@ -1259,5 +1259,15 @@
"not-keycard-title": "Not a Keycard", "not-keycard-title": "Not a Keycard",
"not-keycard-text": "The card you used is not a Keycard. You need to purchase a Keycard to use it", "not-keycard-text": "The card you used is not a Keycard. You need to purchase a Keycard to use it",
"create-new-key": "Create a new key", "create-new-key": "Create a new key",
"add-another-key": "Add another key" "add-another-key": "Add another key",
"generate-a-new-account": "Generate a new account",
"generate-account": "Generate account",
"add-account-description": "You can import any type of Ethereum account to add it to your Status wallet",
"account-added": "Account added",
"you-can-change-account": "You can change the account name and color to what you wish",
"account-name": "Account name",
"account-color": "Account color",
"to-encrypt-enter-password": "To encrypt the account please enter your password",
"accounts": "Accounts",
"add-account-incorrect-password": "Password seems to be incorrect. Enter the password you use to unlock the app."
} }