[Fixes #8066] Added native ENS registration
Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
This commit is contained in:
parent
23702dc1e7
commit
8aa16520c6
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
Binary file not shown.
After Width: | Height: | Size: 81 KiB |
|
@ -246,3 +246,5 @@
|
|||
(def v23 (assoc-in v22
|
||||
[:properties :keycard-key-uid]
|
||||
{:type :string :optional true}))
|
||||
|
||||
(def v24 (update v23 :properties merge {:usernames {:type "string[]" :optional true}}))
|
||||
|
|
|
@ -113,6 +113,11 @@
|
|||
extension/v12
|
||||
account/v23])
|
||||
|
||||
(def v29 [network/v1
|
||||
bootnode/v4
|
||||
extension/v12
|
||||
account/v24])
|
||||
|
||||
;; put schemas ordered by version
|
||||
(def schemas [{:schema v1
|
||||
:schemaVersion 1
|
||||
|
@ -197,4 +202,7 @@
|
|||
:migration (constantly nil)}
|
||||
{:schema v28
|
||||
:schemaVersion 28
|
||||
:migration (constantly nil)}
|
||||
{:schema v29
|
||||
:schemaVersion 29
|
||||
:migration (constantly nil)}])
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
(ns status-im.ens.core
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.accounts.update.core :as accounts.update]
|
||||
[status-im.ethereum.abi-spec :as abi-spec]
|
||||
[status-im.ethereum.contracts :as contracts]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.ens :as ens]
|
||||
[status-im.ethereum.resolver :as resolver]
|
||||
[status-im.ethereum.stateofus :as stateofus]
|
||||
[status-im.ui.screens.navigation :as navigation]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.utils.money :as money]
|
||||
[status-im.signing.core :as signing])
|
||||
(:refer-clojure :exclude [name]))
|
||||
|
||||
(defn fullname [custom-domain? username]
|
||||
(if custom-domain?
|
||||
username
|
||||
(stateofus/subdomain username)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:ens/resolve-address
|
||||
(fn [[registry name cb]]
|
||||
(ens/get-addr registry name cb)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:ens/resolve-pubkey
|
||||
(fn [[registry name cb]]
|
||||
(resolver/pubkey registry name cb)))
|
||||
|
||||
(defn assoc-state-for [db username state]
|
||||
(assoc-in db [:ens/registration :states username] state))
|
||||
|
||||
(defn assoc-details-for [db username k v]
|
||||
(assoc-in db [:ens/names :details username k] v))
|
||||
|
||||
(defn assoc-username-candidate [db username]
|
||||
(assoc-in db [:ens/registration :username-candidate] username))
|
||||
|
||||
(defn empty-username-candidate [db] (assoc-username-candidate db ""))
|
||||
|
||||
(fx/defn set-state
|
||||
{:events [:ens/set-state]}
|
||||
[{:keys [db]} username state]
|
||||
{:db (assoc-state-for db username state)})
|
||||
|
||||
(defn- on-resolve [registry custom-domain? username address public-key s]
|
||||
(cond
|
||||
(= (ethereum/normalized-address address) (ethereum/normalized-address s))
|
||||
(resolver/pubkey registry (fullname custom-domain? username)
|
||||
#(re-frame/dispatch [:ens/set-state username (if (= % public-key) :connected :owned)]))
|
||||
|
||||
(and (nil? s) (not custom-domain?)) ;; No address for a stateofus subdomain: it can be registered
|
||||
(re-frame/dispatch [:ens/set-state username :registrable])
|
||||
|
||||
:else
|
||||
(re-frame/dispatch [:ens/set-state username :unregistrable])))
|
||||
|
||||
(fx/defn register-name
|
||||
[{:keys [db] :as cofx} contract custom-domain? username address public-key]
|
||||
(let [{:keys [x y]} (ethereum/coordinates public-key)]
|
||||
(signing/eth-transaction-call
|
||||
cofx
|
||||
{:contract (contracts/get-address db :status/snt)
|
||||
:method "approveAndCall(address,uint256,bytes)"
|
||||
:params [contract
|
||||
(money/unit->token 10 18)
|
||||
(abi-spec/encode "register(bytes32,address,bytes32,bytes32)"
|
||||
[(ethereum/sha3 username) address x y])]
|
||||
:on-result [:ens/save-username custom-domain? username]
|
||||
:on-error [:ens/on-registration-failure]})))
|
||||
|
||||
(defn- valid-custom-domain? [username]
|
||||
(and (ens/is-valid-eth-name? username)
|
||||
(stateofus/lower-case? username)))
|
||||
|
||||
(defn- valid-username? [custom-domain? username]
|
||||
(if custom-domain?
|
||||
(valid-custom-domain? username)
|
||||
(stateofus/valid-username? username)))
|
||||
|
||||
(defn- state [custom-domain? username]
|
||||
(cond
|
||||
(string/blank? username) :initial
|
||||
(> 4 (count username)) :too-short
|
||||
(valid-username? custom-domain? username) :valid
|
||||
:else :invalid))
|
||||
|
||||
(fx/defn set-username-candidate
|
||||
{:events [:ens/set-username-candidate]}
|
||||
[{:keys [db]} custom-domain? username]
|
||||
(let [state (state custom-domain? username)
|
||||
valid? (valid-username? custom-domain? username)
|
||||
name (fullname custom-domain? username)]
|
||||
(merge
|
||||
{:db (-> db
|
||||
(assoc-username-candidate username)
|
||||
(assoc-state-for username state))}
|
||||
(when (and name (= :valid state))
|
||||
(let [{:keys [account/account]} db
|
||||
{:keys [address public-key]} account
|
||||
registry (get ens/ens-registries (ethereum/chain-keyword db))]
|
||||
{:ens/resolve-address [registry name #(on-resolve registry custom-domain? username address public-key %)]})))))
|
||||
|
||||
(fx/defn clear-cache-and-navigate-back
|
||||
{:events [:ens/clear-cache-and-navigate-back]}
|
||||
[{:keys [db] :as cofx} _]
|
||||
(fx/merge cofx
|
||||
{:db (assoc db :ens/registration nil)} ;; Clear cache
|
||||
(navigation/navigate-back)))
|
||||
|
||||
(fx/defn switch-domain-type
|
||||
{:events [:ens/switch-domain-type]}
|
||||
[{:keys [db]} _]
|
||||
{:db (-> (update-in db [:ens/registration :custom-domain?] not)
|
||||
(empty-username-candidate))})
|
||||
|
||||
(fx/defn save-username
|
||||
{:events [:ens/save-username]}
|
||||
[{:keys [db] :as cofx} custom-domain? username]
|
||||
(let [name (fullname custom-domain? username)
|
||||
db (update-in db [:account/account :usernames] #((fnil conj []) %1 %2) name)]
|
||||
(accounts.update/account-update cofx
|
||||
{:usernames (get-in db [:account/account :usernames])}
|
||||
{:success-event [:ens/set-state username :saved]})))
|
||||
|
||||
(fx/defn on-registration-failure
|
||||
{:events [:ens/on-registration-failure]}
|
||||
[{:keys [db]} username]
|
||||
{:db (assoc-state-for db username :registration-failed)})
|
||||
|
||||
(fx/defn register
|
||||
{:events [:ens/register]}
|
||||
[cofx {:keys [contract custom-domain? username address public-key]}]
|
||||
(register-name cofx contract custom-domain? username address public-key))
|
||||
|
||||
(fx/defn store-name-detail
|
||||
{:events [:ens/store-name-detail]}
|
||||
[{:keys [db]} name k v]
|
||||
{:db (assoc-details-for db name k v)})
|
||||
|
||||
(fx/defn navigate-to-name
|
||||
{:events [:ens/navigate-to-name]}
|
||||
[{:keys [db] :as cofx} name]
|
||||
(let [registry (get ens/ens-registries (ethereum/chain-keyword db))]
|
||||
(fx/merge cofx
|
||||
{:ens/resolve-address [registry name #(re-frame/dispatch [:ens/store-name-detail name :address %])]
|
||||
:ens/resolve-pubkey [registry name #(re-frame/dispatch [:ens/store-name-detail name :public-key %])]}
|
||||
(navigation/navigate-to-cofx :ens-name-details name))))
|
|
@ -65,6 +65,14 @@
|
|||
(when s
|
||||
(string/replace s hex-prefix "")))
|
||||
|
||||
(def ^:const public-key-length 128)
|
||||
|
||||
(defn coordinates [public-key]
|
||||
(when-let [hex (naked-address public-key)]
|
||||
(when (= public-key-length (count (subs hex 2)))
|
||||
{:x (normalized-address (subs hex 1 65))
|
||||
:y (normalized-address (subs hex 66))})))
|
||||
|
||||
(defn address? [s]
|
||||
(when s
|
||||
(.isAddress (utils) s)))
|
||||
|
|
|
@ -41,8 +41,7 @@
|
|||
:outputs ["address"]
|
||||
:on-success
|
||||
(fn [[address]]
|
||||
(when-not (= address default-address)
|
||||
(cb address)))}))
|
||||
(cb (when-not (= address default-address) address)))}))
|
||||
|
||||
(defn owner
|
||||
[registry ens-name cb]
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
(ns status-im.ethereum.stateofus
|
||||
(:require [clojure.string :as string]))
|
||||
|
||||
(def domain "stateofus.eth")
|
||||
|
||||
(defn subdomain [username]
|
||||
(str username "." domain))
|
||||
|
||||
(defn username [name]
|
||||
(when (string/ends-with? name domain)
|
||||
(first (string/split name "."))))
|
||||
|
||||
(def registrars
|
||||
{:mainnet "0xDB5ac1a559b02E12F29fC0eC0e37Be8E046DEF49"
|
||||
:testnet "0x11d9F481effd20D76cEE832559bd9Aca25405841"})
|
||||
|
||||
(defn lower-case? [s]
|
||||
(when s
|
||||
(= s (string/lower-case s))))
|
||||
|
||||
(defn valid-username? [username]
|
||||
(boolean
|
||||
(and (lower-case? username)
|
||||
(re-find #"^[a-z0-9]+$" username))))
|
|
@ -1,5 +1,6 @@
|
|||
(ns status-im.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.accounts.core :as accounts]
|
||||
[status-im.accounts.create.core :as accounts.create]
|
||||
[status-im.accounts.login.core :as accounts.login]
|
||||
|
@ -21,6 +22,8 @@
|
|||
[status-im.contact-recovery.core :as contact-recovery]
|
||||
[status-im.contact.block :as contact.block]
|
||||
[status-im.contact.core :as contact]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.ens :as ethereum.ens]
|
||||
[status-im.ethereum.subscriptions :as ethereum.subscriptions]
|
||||
[status-im.ethereum.transactions.core :as ethereum.transactions]
|
||||
[status-im.fleet.core :as fleet]
|
||||
|
@ -1548,11 +1551,6 @@
|
|||
|
||||
;; profile module
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:profile.ui/ens-names-button-pressed
|
||||
(fn [cofx]
|
||||
(browser/open-url cofx "names.statusnet.eth")))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:profile.ui/keycard-settings-button-pressed
|
||||
(fn [cofx]
|
||||
|
@ -1997,4 +1995,4 @@
|
|||
(re-frame/reg-fx
|
||||
:dismiss-keyboard
|
||||
(fn []
|
||||
(react/dismiss-keyboard!)))
|
||||
(react/dismiss-keyboard!)))
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
:warning-sign (js-require/js-require "./resources/images/ui/warning-sign.png")
|
||||
:phone-nfc-on (js-require/js-require "./resources/images/ui/phone-nfc-on.png")
|
||||
:phone-nfc-off (js-require/js-require "./resources/images/ui/phone-nfc-off.png")
|
||||
:dapp-store (js-require/js-require "./resources/images/ui/dapp-store.png")})
|
||||
:dapp-store (js-require/js-require "./resources/images/ui/dapp-store.png")
|
||||
:ens-header (js-require/js-require "./resources/images/ui/ens-header.png")})
|
||||
|
||||
(def loaded-images (atom {}))
|
||||
|
||||
|
|
|
@ -12,10 +12,11 @@
|
|||
[status-im.chat.models :as chat.models]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contact.db :as contact.db]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.stateofus :as stateofus]
|
||||
[status-im.ethereum.tokens :as tokens]
|
||||
[status-im.ethereum.transactions.core :as transactions]
|
||||
[status-im.ethereum.transactions.etherscan :as transactions.etherscan]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.fleet.core :as fleet]
|
||||
[status-im.group-chats.db :as group-chats.db]
|
||||
[status-im.i18n :as i18n]
|
||||
|
@ -34,6 +35,7 @@
|
|||
[status-im.utils.build :as build]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.utils.datetime :as datetime]
|
||||
[status-im.utils.hex :as utils.hex]
|
||||
[status-im.utils.identicon :as identicon]
|
||||
[status-im.utils.money :as money]
|
||||
[status-im.utils.platform :as platform]
|
||||
|
@ -165,6 +167,10 @@
|
|||
;;ethereum
|
||||
(reg-root-key-sub :ethereum/current-block :ethereum/current-block)
|
||||
|
||||
;;ens
|
||||
(reg-root-key-sub :ens/registration :ens/registration)
|
||||
(reg-root-key-sub :ens/names :ens/names)
|
||||
|
||||
;;signing
|
||||
(reg-root-key-sub :signing/tx :signing/tx)
|
||||
(reg-root-key-sub :signing/sign :signing/sign)
|
||||
|
@ -1787,6 +1793,44 @@
|
|||
(#{"0" "0.0" "0.00"} screen-snt-amount)
|
||||
(string/ends-with? screen-snt-amount ".")))))))))
|
||||
|
||||
;;ENS ==================================================================================================================
|
||||
|
||||
(re-frame/reg-sub
|
||||
:ens.stateofus/registrar
|
||||
:<- [:account/network]
|
||||
(fn [network]
|
||||
(let [chain (ethereum/network->chain-keyword network)]
|
||||
(get stateofus/registrars chain))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:account/usernames
|
||||
:<- [:account/account]
|
||||
(fn [account]
|
||||
(:usernames account)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:ens.registration/screen
|
||||
:<- [:ens/registration]
|
||||
:<- [:ens.stateofus/registrar]
|
||||
:<- [:account/account]
|
||||
(fn [[{:keys [custom-domain? username-candidate] :as ens} registrar {:keys [address public-key]}] _]
|
||||
{:state (get-in ens [:states username-candidate])
|
||||
:username username-candidate
|
||||
:custom-domain? (or custom-domain? false)
|
||||
:contract registrar
|
||||
:address address
|
||||
:public-key public-key}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:ens.name/screen
|
||||
:<- [:get-screen-params :ens-name-details]
|
||||
:<- [:ens/names]
|
||||
(fn [[name ens] _]
|
||||
(let [{:keys [address public-key]} (get-in ens [:details name])]
|
||||
{:name name
|
||||
:address address
|
||||
:public-key public-key})))
|
||||
|
||||
;;SIGNING =============================================================================================================
|
||||
|
||||
(re-frame/reg-sub
|
||||
|
|
|
@ -75,14 +75,13 @@
|
|||
(def settings-item-separator
|
||||
{:margin-left 16})
|
||||
|
||||
(defn settings-item
|
||||
[large?]
|
||||
{:padding-left 16
|
||||
:padding-right 8
|
||||
:flex 1
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:height (if large? 82 52)})
|
||||
(def settings-item
|
||||
{:padding-left 16
|
||||
:padding-right 8
|
||||
:flex 1
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:height 64})
|
||||
|
||||
(defn settings-item-icon
|
||||
[icon-color large?]
|
||||
|
@ -111,7 +110,6 @@
|
|||
|
||||
(def settings-item-main-text-container
|
||||
{:flex-direction :row
|
||||
:height 18
|
||||
:align-items :center})
|
||||
|
||||
(def settings-item-subtext
|
||||
|
|
|
@ -114,7 +114,7 @@
|
|||
:icon-opts {:color colors/white}}])
|
||||
|
||||
(defn big-list-item
|
||||
[{:keys [style text text-color subtext value action-fn active? destructive? hide-chevron?
|
||||
[{:keys [style text text-color text-style subtext value action-fn active? destructive? hide-chevron?
|
||||
accessory-value text-color new? activity-indicator
|
||||
accessibility-label icon icon-color image-source icon-content]
|
||||
:or {icon-color colors/blue
|
||||
|
@ -123,14 +123,14 @@
|
|||
active? true
|
||||
style {}}}]
|
||||
{:pre [(or icon image-source activity-indicator)
|
||||
(and action-fn text)
|
||||
text
|
||||
(or (nil? accessibility-label) (keyword? accessibility-label))]}
|
||||
[react/touchable-highlight
|
||||
{:on-press action-fn
|
||||
:style style
|
||||
:accessibility-label accessibility-label
|
||||
:disabled (not active?)}
|
||||
[react/view (styles/settings-item subtext)
|
||||
[react/view styles/settings-item
|
||||
(cond
|
||||
icon
|
||||
[react/view (styles/settings-item-icon icon-color subtext)
|
||||
|
@ -148,14 +148,14 @@
|
|||
[react/view {:style styles/new-label}
|
||||
[react/text {:style styles/new-label-text}
|
||||
(string/upper-case (i18n/label :t/new))]])
|
||||
[react/text {:style (styles/settings-item-text text-color)}
|
||||
[react/text {:style (merge (styles/settings-item-text text-color) text-style)}
|
||||
text]]
|
||||
[react/view {:style {:margin-top 2
|
||||
:justify-content :flex-start}}
|
||||
[react/text {:style styles/settings-item-subtext
|
||||
:number-of-lines 2}
|
||||
subtext]]]
|
||||
[react/text {:style (styles/settings-item-text text-color)
|
||||
[react/text {:style (merge (styles/settings-item-text text-color) text-style)
|
||||
:number-of-lines 1}
|
||||
text])
|
||||
(when accessory-value
|
||||
|
|
|
@ -0,0 +1,521 @@
|
|||
(ns status-im.ui.screens.ens.views
|
||||
"
|
||||
|
||||
+-------------+
|
||||
| Initial |
|
||||
+-----+-------+
|
||||
|
|
||||
| Typing
|
||||
|
|
||||
v
|
||||
+--------------+ +----------------+
|
||||
| Valid | | Invalid/reason |
|
||||
+------+-------+ +-------+--------+
|
||||
| |
|
||||
+----------+----------+
|
||||
|
|
||||
| Checking
|
||||
|
|
||||
|
|
||||
v
|
||||
+------------------------------------------+
|
||||
| +--------------+ +----------------+ |
|
||||
| | Unregistrable| | Registrable | | +-----------------------------------+ +-------------+
|
||||
| +--------------+ +----------------+ | | Connected/details | | Not owned |
|
||||
| | | (none, address, public+key, all) | +-------------+
|
||||
| | +----------+------------------------+
|
||||
| Name available | |
|
||||
+-------------------+----------------------+ |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| Registering | Connecting
|
||||
| (on-chain, 1 tx) | (on-chain, 1tx per info to connect)
|
||||
| |
|
||||
+-----------------------+------------------+
|
||||
|
|
||||
|
|
||||
| Saving
|
||||
|
|
||||
|
|
||||
+-------+-----+
|
||||
| Saved |
|
||||
+-------------+
|
||||
|
||||
"
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.ens.core :as ens]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.ens :as ethereum.ens]
|
||||
[status-im.ethereum.stateofus :as stateofus]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[status-im.ui.components.checkbox.view :as checkbox]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.common.common :as components.common]
|
||||
[status-im.ui.components.icons.vector-icons :as vector-icons]
|
||||
[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]
|
||||
[status-im.ui.components.toolbar.actions :as actions]
|
||||
[status-im.ui.components.toolbar.view :as toolbar])
|
||||
|
||||
(:require-macros [status-im.utils.views :as views]))
|
||||
|
||||
;; Components
|
||||
|
||||
(defn- button [{:keys [on-press] :as m} label]
|
||||
[components.common/button (merge {:button-style {:margin-vertical 8
|
||||
:padding-horizontal 32
|
||||
:justify-content :center
|
||||
:align-items :center}
|
||||
:on-press on-press
|
||||
:label label}
|
||||
m)])
|
||||
|
||||
(defn- link [{:keys [on-press]} label]
|
||||
[react/touchable-opacity {:on-press on-press :style {:justify-content :center}}
|
||||
[react/text {:style {:color colors/blue}}
|
||||
label]])
|
||||
|
||||
(defn- section [{:keys [title content]}]
|
||||
[react/view {:style {:margin-horizontal 16 :align-items :flex-start}}
|
||||
[react/text {:style {:color colors/gray :font-size 15}}
|
||||
title]
|
||||
[react/view {:margin-top 8 :padding-horizontal 16 :padding-vertical 12 :border-width 1 :border-radius 12
|
||||
:border-color colors/gray-lighter}
|
||||
[react/text {:style {:font-size 15}}
|
||||
content]]])
|
||||
|
||||
;; Name details
|
||||
|
||||
(views/defview name-details []
|
||||
(views/letsubs [{:keys [name address public-key]} [:ens.name/screen]]
|
||||
(let [pending? (nil? address)]
|
||||
[react/view {:style {:flex 1}}
|
||||
[status-bar/status-bar {:type :main}]
|
||||
[toolbar/simple-toolbar
|
||||
name]
|
||||
[react/scroll-view {:style {:flex 1}}
|
||||
[react/view {:style {:flex 1 :margin-horizontal 16}}
|
||||
[react/view {:flex-direction :row :align-items :center :margin-top 20}
|
||||
[react/view {:style {:margin-right 16}}
|
||||
[components.common/logo
|
||||
{:size 40
|
||||
:icon-size 16}]]
|
||||
[react/text {:style {:typography :title}}
|
||||
(if pending?
|
||||
(i18n/label :t/ens-transaction-pending)
|
||||
(str (i18n/label :t/ens-10-SNT) ", deposit unlocked"))]]]
|
||||
[react/view {:style {:margin-top 22}}
|
||||
(when-not pending?
|
||||
[section {:title (i18n/label :t/ens-wallet-address)
|
||||
:content (ethereum/normalized-address address)}])
|
||||
(when-not pending?
|
||||
[react/view {:style {:margin-top 14}}
|
||||
[section {:title (i18n/label :t/key)
|
||||
:content public-key}]])
|
||||
[react/view {:style {:margin-top 16 :margin-bottom 32}}
|
||||
[list/big-list-item {:text (i18n/label :t/ens-remove-username)
|
||||
:subtext (i18n/label :t/ens-remove-hints)
|
||||
:text-color colors/gray
|
||||
:text-style {:font-weight "500"}
|
||||
:icon :main-icons/close
|
||||
:icon-color colors/gray
|
||||
:hide-chevron? true}]
|
||||
[react/view {:style {:margin-top 10}}
|
||||
[list/big-list-item {:text (i18n/label :t/ens-release-username)
|
||||
:text-color colors/gray
|
||||
:text-style {:font-weight "500"}
|
||||
:subtext (i18n/label :t/ens-locked)
|
||||
:action-fn #(re-frame/dispatch [:navigate-to :ens-register])
|
||||
:icon :main-icons/delete
|
||||
:icon-color colors/gray
|
||||
:active? false
|
||||
:hide-chevron? true}]]]]]])))
|
||||
|
||||
;; Terms
|
||||
|
||||
(defn- term-point [content]
|
||||
[react/view {:style {:flex 1 :margin-top 24 :margin-horizontal 16 :flex-direction :row}}
|
||||
[react/view {:style {:width 16 :margin-top 8}}
|
||||
[react/view {:style {:background-color colors/gray :width 4 :height 4 :border-radius 25}}]]
|
||||
[react/text {:style {:flex 1 :font-size 15}}
|
||||
content]])
|
||||
|
||||
(defn- etherscan-url [address]
|
||||
(str "https://etherscan.io/address/" address))
|
||||
|
||||
(views/defview terms []
|
||||
(views/letsubs [{:keys [contract]} [:get-screen-params :ens-terms]]
|
||||
[react/scroll-view {:style {:flex 1}}
|
||||
[status-bar/status-bar {:type :main}]
|
||||
[toolbar/simple-toolbar
|
||||
(i18n/label :t/ens-terms-registration)]
|
||||
[react/view {:style {:height 136 :background-color colors/gray-lighter :justify-content :center :align-items :center}}
|
||||
[react/text {:style {:text-align :center :typography :header :letter-spacing -0.275}}
|
||||
(i18n/label :t/ens-terms-header)]]
|
||||
[react/view
|
||||
[term-point
|
||||
(i18n/label :t/ens-terms-point-1)]
|
||||
[term-point
|
||||
(i18n/label :t/ens-terms-point-2)]
|
||||
[term-point
|
||||
(i18n/label :t/ens-terms-point-3)]
|
||||
[term-point
|
||||
(i18n/label :t/ens-terms-point-4)]
|
||||
[term-point
|
||||
(i18n/label :t/ens-terms-point-5)]
|
||||
[term-point
|
||||
(i18n/label :t/ens-terms-point-6)]
|
||||
[term-point
|
||||
(i18n/label :t/ens-terms-point-7)]]
|
||||
[react/view
|
||||
[react/text {:style {:font-size 15 :margin-top 24 :margin-horizontal 16 :font-weight "700"}}
|
||||
(i18n/label :t/ens-terms-point-8)]
|
||||
[term-point
|
||||
(i18n/label :t/ens-terms-point-9 {:address contract})]
|
||||
[react/view {:style {:align-items :center :margin-top 16 :margin-bottom 8}}
|
||||
[link {:on-press #(.openURL (react/linking) (etherscan-url contract))}
|
||||
(i18n/label :t/etherscan-lookup)]]
|
||||
[term-point
|
||||
(i18n/label :t/ens-terms-point-10)]
|
||||
[react/view {:style {:align-items :center :margin-top 16 :margin-bottom 8}}
|
||||
[link {:on-press #(.openURL (react/linking) (etherscan-url (:mainnet ethereum.ens/ens-registries)))}
|
||||
(i18n/label :t/etherscan-lookup)]]]]))
|
||||
|
||||
;; Registration
|
||||
|
||||
(defn- valid-domain? [state]
|
||||
(#{:registrable :owned :connected} state))
|
||||
|
||||
(defn- final-state? [state]
|
||||
(#{:saved :registered :registration-failed} state))
|
||||
|
||||
(defn- main-icon [state]
|
||||
(cond
|
||||
(valid-domain? state) :main-icons/check
|
||||
(= state :unregistrable) :main-icons/cancel
|
||||
:else :main-icons/username))
|
||||
|
||||
(defn- icon-wrapper [color icon]
|
||||
[react/view {:style {:margin-right 10 :width 32 :height 32 :border-radius 25
|
||||
:align-items :center :justify-content :center :background-color color}}
|
||||
icon])
|
||||
|
||||
(defn- input-action [{:keys [state custom-domain? username]}]
|
||||
(if (= :connected state)
|
||||
;; Already registered, just need to save the contact
|
||||
[:ens/save-username custom-domain? username]
|
||||
[:ens/set-state username :registering]))
|
||||
|
||||
(defn- disabled-input-action []
|
||||
[icon-wrapper colors/gray
|
||||
[vector-icons/icon :main-icons/arrow-right {:color colors/white}]])
|
||||
|
||||
(defn- input-icon [{:keys [state custom-domain? username] :as props} usernames]
|
||||
(cond
|
||||
(= state :registering)
|
||||
nil
|
||||
|
||||
(= state :valid)
|
||||
[icon-wrapper colors/blue
|
||||
[react/activity-indicator {:color colors/white}]]
|
||||
|
||||
(valid-domain? state)
|
||||
(let [name (ens/fullname custom-domain? username)]
|
||||
(if (contains? (set usernames) name)
|
||||
[disabled-input-action]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch (input-action props))}
|
||||
[icon-wrapper colors/blue
|
||||
[vector-icons/icon :main-icons/arrow-right {:color colors/white}]]]))
|
||||
|
||||
:else
|
||||
[disabled-input-action]))
|
||||
|
||||
(defn- default-name [custom-domain?]
|
||||
(if custom-domain?
|
||||
"vitalik94.domain.eth"
|
||||
"vitalik94"))
|
||||
|
||||
(defn- domain-label [custom-domain?]
|
||||
(if custom-domain?
|
||||
(i18n/label :t/ens-custom-domain)
|
||||
(str "." stateofus/domain)))
|
||||
|
||||
(defn- domain-switch-label [custom-domain?]
|
||||
(if custom-domain?
|
||||
(i18n/label :t/ens-want-domain)
|
||||
(i18n/label :t/ens-want-custom-domain)))
|
||||
|
||||
(defn- help-message [state custom-domain?]
|
||||
(case state
|
||||
(:initial :too-short)
|
||||
(if custom-domain?
|
||||
(i18n/label :t/ens-custom-username-hints)
|
||||
(i18n/label :t/ens-username-hints))
|
||||
:invalid
|
||||
(if custom-domain?
|
||||
(i18n/label :t/ens-custom-username-hints)
|
||||
(i18n/label :t/ens-username-invalid))
|
||||
:unregistrable
|
||||
(if custom-domain?
|
||||
(i18n/label :t/ens-custom-username-unregistrable)
|
||||
(i18n/label :t/ens-username-unregistrable))
|
||||
:registrable
|
||||
(i18n/label :t/ens-username-registrable)
|
||||
:owned
|
||||
(i18n/label :t/ens-username-owned)
|
||||
:connected
|
||||
(i18n/label :t/ens-username-connected)
|
||||
""))
|
||||
|
||||
(defn- on-username-change [custom-domain? username]
|
||||
(re-frame/dispatch [:ens/set-username-candidate custom-domain? username]))
|
||||
|
||||
(defn- on-registration [props]
|
||||
(re-frame/dispatch [:ens/register props]))
|
||||
|
||||
(defn- agreement [{:keys [checked contract]}]
|
||||
[react/view {:flex-direction :row :margin-horizontal 20 :margin-top 14 :align-items :flex-start :justify-content :center}
|
||||
[checkbox/checkbox {:checked? @checked
|
||||
:style {:padding 0}
|
||||
:on-value-change #(reset! checked %)}]
|
||||
[react/view {:style {:padding-left 10}}
|
||||
[react/view {:style {:flex-direction :row}}
|
||||
[react/text
|
||||
(i18n/label :t/ens-agree-to)]
|
||||
[link {:on-press #(re-frame/dispatch [:navigate-to :ens-terms {:contract contract}])}
|
||||
(i18n/label :t/ens-terms-registration)]]
|
||||
[react/text
|
||||
(i18n/label :t/ens-understand)]]])
|
||||
|
||||
(defn- registration-bottom-bar [{:keys [checked] :as props}]
|
||||
[react/view {:style {:height 60
|
||||
:background-color colors/white
|
||||
:border-top-width 1
|
||||
:border-top-color colors/gray-lighter}}
|
||||
[react/view {:style {:margin-horizontal 16
|
||||
:flex-direction :row
|
||||
:justify-content :space-between}}
|
||||
[react/view {:flex-direction :row}
|
||||
[react/view {:style {:margin-top 12 :margin-right 8}}
|
||||
[components.common/logo
|
||||
{:size 36
|
||||
:icon-size 16}]]
|
||||
[react/view {:flex-direction :column :margin-vertical 8}
|
||||
[react/text {:style {:font-size 15}}
|
||||
(i18n/label :t/ens-10-SNT)]
|
||||
[react/text {:style {:color colors/gray :font-size 15}}
|
||||
(i18n/label :t/ens-deposit)]]]
|
||||
[button {:disabled? (not @checked)
|
||||
:label-style (when (not @checked) {:color colors/gray})
|
||||
:on-press #(on-registration props)}
|
||||
(i18n/label :t/ens-register)]]])
|
||||
|
||||
(defn- registration [{:keys [address public-key] :as props}]
|
||||
[react/view {:style {:flex 1 :margin-top 24}}
|
||||
[section {:title (i18n/label :t/ens-wallet-address)
|
||||
:content address}]
|
||||
[react/view {:style {:margin-top 14}}
|
||||
[section {:title (i18n/label :t/key)
|
||||
:content public-key}]]
|
||||
[agreement props]])
|
||||
|
||||
(defn- icon [{:keys [state]}]
|
||||
[react/view {:style {:margin-top 68 :margin-bottom 24 :width 60 :height 60 :border-radius 30
|
||||
:background-color colors/blue :align-items :center :justify-content :center}}
|
||||
[vector-icons/icon (main-icon state) {:color colors/white}]])
|
||||
|
||||
(defn- username-input [{:keys [custom-domain? username state] :as props} usernames]
|
||||
[react/view {:flex-direction :row :justify-content :center}
|
||||
[react/text-input {:on-change-text #(on-username-change custom-domain? %)
|
||||
:on-submit-editing #(on-registration props)
|
||||
:auto-capitalize :none
|
||||
:auto-correct false
|
||||
:default-value username
|
||||
:auto-focus true
|
||||
:text-align :center
|
||||
:placeholder (default-name custom-domain?)
|
||||
:style {:flex 1 :font-size 22
|
||||
(if (= state :registering) :padding-horizontal :padding-left) 48}}]
|
||||
[input-icon props usernames]])
|
||||
|
||||
(defn- final-state-label [state]
|
||||
(case state
|
||||
:registered
|
||||
(i18n/label :t/ens-registered-title)
|
||||
:saved
|
||||
(i18n/label :t/ens-saved-title)
|
||||
:registration-failed
|
||||
(i18n/label :t/ens-registration-failed-title)
|
||||
""))
|
||||
|
||||
(defn- final-state-details [{:keys [state username]}]
|
||||
(case state
|
||||
:registered
|
||||
[react/text {:style {:color colors/gray :font-size 14}}
|
||||
(i18n/label :t/ens-registered)]
|
||||
:registration-failed
|
||||
[react/text {:style {:color colors/gray :font-size 14}}
|
||||
(i18n/label :t/ens-registration-failed)]
|
||||
:saved
|
||||
[react/view {:style {:flex-direction :row :align-items :center}}
|
||||
[react/nested-text
|
||||
{:style {}}
|
||||
(stateofus/subdomain username)
|
||||
[{:style {:color colors/gray}}
|
||||
(i18n/label :t/ens-saved)]]]
|
||||
[react/view {:flex-direction :row :margin-left 6 :margin-top 14 :align-items :center}
|
||||
[react/text
|
||||
(str (i18n/label :t/ens-terms-registration) " ->")]]))
|
||||
|
||||
(defn- finalized-icon [{:keys [state]}]
|
||||
(case state
|
||||
:registration-failed
|
||||
[react/view {:style {:width 40 :height 40 :border-radius 30 :background-color colors/red-light
|
||||
:align-items :center :justify-content :center}}
|
||||
[vector-icons/icon :main-icons/warning {:color colors/red}]]
|
||||
[react/view {:style {:width 40 :height 40 :border-radius 30 :background-color colors/gray-lighter
|
||||
:align-items :center :justify-content :center}}
|
||||
[vector-icons/icon :main-icons/check {:color colors/blue}]]))
|
||||
|
||||
(defn- registration-finalized [{:keys [state username] :as props}]
|
||||
[react/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[finalized-icon props]
|
||||
[react/text {:style {:typography :header :margin-top 32 :margin-horizontal 32 :text-align :center}}
|
||||
(final-state-label state)]
|
||||
[react/view {:align-items :center :margin-horizontal 32 :margin-top 12 :margin-bottom 20 :justify-content :center}
|
||||
[final-state-details props]]
|
||||
(if (= state :registration-failed)
|
||||
[react/view
|
||||
[button {:on-press #(re-frame/dispatch [:ens/set-state username :registering])}
|
||||
(i18n/label :t/retry)]
|
||||
[button {:background? false
|
||||
:on-press #(re-frame/dispatch [:ens/clear-cache-and-navigate-back])}
|
||||
(i18n/label :t/cancel)]]
|
||||
[button {:on-press #(re-frame/dispatch [:ens/clear-cache-and-navigate-back])}
|
||||
(i18n/label :t/ens-got-it)])])
|
||||
|
||||
(views/defview registration-pending [{:keys [state custom-domain?] :as props} usernames]
|
||||
(views/letsubs [usernames [:account/usernames]]
|
||||
[react/view {:style {:flex 1}}
|
||||
[react/scroll-view {:style {:flex 1}}
|
||||
[react/view {:style {:flex 1}}
|
||||
[react/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[icon props]
|
||||
[username-input props usernames]
|
||||
[react/view {:style {:height 36 :align-items :center :justify-content :space-between :padding-horizontal 12
|
||||
:margin-top 24 :margin-horizontal 16 :border-color colors/gray-lighter :border-radius 20
|
||||
:border-width 1 :flex-direction :row}}
|
||||
[react/text {:style {:font-size 12 :typography :main-medium}}
|
||||
(domain-label custom-domain?)]
|
||||
[react/view {:flex 1 :min-width 24}]
|
||||
(when-not (= state :registering)
|
||||
;; Domain type is not shown during registration
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:ens/switch-domain-type])}
|
||||
[react/text {:style {:color colors/blue :font-size 12 :typography :main-medium} :number-of-lines 2}
|
||||
(domain-switch-label custom-domain?)]])]]
|
||||
(if (= state :registering)
|
||||
[registration props]
|
||||
[react/text {:style {:flex 1 :margin-top 16 :margin-horizontal 16 :font-size 14 :text-align :center}}
|
||||
(help-message state custom-domain?)])]]
|
||||
(when (= state :registering)
|
||||
[registration-bottom-bar props])]))
|
||||
|
||||
(defn- toolbar []
|
||||
[toolbar/toolbar nil
|
||||
[toolbar/nav-button (actions/back #(re-frame/dispatch [:ens/clear-cache-and-navigate-back]))]
|
||||
[toolbar/content-title (i18n/label :t/ens-your-username)]])
|
||||
|
||||
(views/defview register []
|
||||
(views/letsubs [{:keys [address state] :as props} [:ens.registration/screen]]
|
||||
(let [checked (reagent/atom false)
|
||||
props (merge props {:checked checked :address (ethereum/normalized-address address)})]
|
||||
[react/keyboard-avoiding-view {:flex 1}
|
||||
[status-bar/status-bar {:type :main}]
|
||||
[toolbar]
|
||||
(if (final-state? state)
|
||||
[registration-finalized props]
|
||||
[registration-pending props])])))
|
||||
|
||||
;; Welcome
|
||||
|
||||
(defn- welcome-item [{:keys [icon-label title]} content]
|
||||
[react/view {:style {:flex 1 :margin-top 24 :margin-left 16 :flex-direction :row}}
|
||||
[react/view {:style {:height 40 :width 40 :border-radius 25 :border-width 1 :border-color colors/gray-lighter
|
||||
:align-items :center :justify-content :center}}
|
||||
[react/text {:style {:typography :title}}
|
||||
icon-label]]
|
||||
[react/view {:style {:flex 1 :margin-horizontal 16}}
|
||||
[react/text {:style {:font-size 15 :typography :main-semibold}}
|
||||
title]
|
||||
content]])
|
||||
|
||||
(defn- welcome []
|
||||
[react/view {:style {:flex 1}}
|
||||
[react/scroll-view {:content-container-style {:align-items :center}}
|
||||
[react/image {:source (:ens-header resources/ui)
|
||||
:style {:margin-top 32}}]
|
||||
[react/text {:style {:margin-top 32 :margin-bottom 8 :typography :header}}
|
||||
(i18n/label :t/ens-get-name)]
|
||||
[react/text {:style {:margin-top 8 :margin-bottom 24 :color colors/gray :font-size 15 :margin-horizontal 16
|
||||
:text-align :center}}
|
||||
(i18n/label :t/ens-welcome-hints)]
|
||||
[welcome-item {:icon-label "1" :title (i18n/label :t/ens-welcome-point-1-title)}
|
||||
[react/view {:flex-direction :row}
|
||||
[react/nested-text
|
||||
{:style {:color colors/gray}}
|
||||
(i18n/label :t/ens-welcome-point-1)
|
||||
[{:style {:text-decoration-line :underline :color colors/black}}
|
||||
(stateofus/subdomain "myname")]]]]
|
||||
[welcome-item {:icon-label "2" :title (i18n/label :t/ens-welcome-point-2-title)}
|
||||
[react/text {:style {:color colors/gray}}
|
||||
(i18n/label :t/ens-welcome-point-2)]]
|
||||
[welcome-item {:icon-label "3" :title (i18n/label :t/ens-welcome-point-3-title)}
|
||||
[react/text {:style {:color colors/gray}}
|
||||
(i18n/label :t/ens-welcome-point-3)]]
|
||||
[welcome-item {:icon-label "@" :title (i18n/label :t/ens-welcome-point-4-title)}
|
||||
[react/text {:style {:color colors/gray}}
|
||||
(i18n/label :t/ens-welcome-point-4)]]
|
||||
[react/text {:style {:margin-top 16 :text-align :center :color colors/gray :typography :caption :padding-bottom 96}}
|
||||
(i18n/label :t/ens-powered-by)]]
|
||||
[react/view {:align-items :center :background-color colors/white
|
||||
:position :absolute :left 0 :right 0 :bottom 0
|
||||
:border-top-width 1 :border-top-color colors/gray-lighter}
|
||||
[button {:on-press #(re-frame/dispatch [:navigate-to :ens-register])
|
||||
:label (i18n/label :t/get-started)}]]])
|
||||
|
||||
(defn- registered [names]
|
||||
[react/scroll-view {:style {:flex 1}}
|
||||
[react/view {:style {:flex 1 :margin-top 8}}
|
||||
[list/big-list-item {:text (i18n/label :t/ens-add-username)
|
||||
:action-fn #(re-frame/dispatch [:navigate-to :ens-register])
|
||||
:icon :main-icons/add}]]
|
||||
[react/view {:style {:margin-top 22}}
|
||||
[react/text {:style {:color colors/gray :margin-horizontal 16}}
|
||||
(i18n/label :t/ens-your-usernames)]
|
||||
(if (seq names)
|
||||
[react/view {:style {:margin-top 8}}
|
||||
(for [name names]
|
||||
^{:key name}
|
||||
[react/view
|
||||
(let [stateofus-username (stateofus/username name)
|
||||
s (or stateofus-username name)]
|
||||
[list/big-list-item {:text s
|
||||
:subtext (when stateofus-username stateofus/domain)
|
||||
:action-fn #(re-frame/dispatch [:ens/navigate-to-name name])
|
||||
:icon :main-icons/username}])])]
|
||||
[react/text {:style {:color colors/gray :font-size 15}}
|
||||
(i18n/label :t/ens-no-usernames)])]])
|
||||
|
||||
(views/defview main []
|
||||
(views/letsubs [names [:account/usernames]]
|
||||
[react/view {:style {:flex 1}}
|
||||
[status-bar/status-bar {:type :main}]
|
||||
[toolbar/simple-toolbar
|
||||
(i18n/label :t/ens-usernames)]
|
||||
(if (seq names)
|
||||
[registered names]
|
||||
[welcome])]))
|
|
@ -112,10 +112,6 @@
|
|||
extensions-settings (vals (get extensions :settings))]
|
||||
[react/view
|
||||
[profile.components/settings-title (i18n/label :t/settings)]
|
||||
[profile.components/settings-item {:label-kw :t/ens-names
|
||||
:action-fn #(re-frame/dispatch [:profile.ui/ens-names-button-pressed])
|
||||
:accessibility-label :ens-names-button}]
|
||||
[profile.components/settings-item-separator]
|
||||
[profile.components/settings-item {:label-kw :t/main-currency
|
||||
:value (:code currency)
|
||||
:action-fn #(re-frame/dispatch [:navigate-to :currency-settings])
|
||||
|
@ -286,6 +282,22 @@
|
|||
:accessory-value active-contacts-count
|
||||
:action-fn #(re-frame/dispatch [:navigate-to :contacts-list])}])
|
||||
|
||||
(defn- ens-item [ens {:keys [registrar] :as props}]
|
||||
[list.views/big-list-item
|
||||
(let [enabled? (not (nil? registrar))]
|
||||
(merge
|
||||
{:text (or ens (i18n/label :t/ens-usernames))
|
||||
:subtext (if enabled?
|
||||
(if ens (i18n/label :t/ens-your-your-name) (i18n/label :t/ens-usernames-details))
|
||||
(i18n/label :t/ens-network-restriction))
|
||||
:icon :main-icons/username
|
||||
:accessibility-label :ens-button}
|
||||
(if enabled?
|
||||
{:action-fn #(re-frame/dispatch [:navigate-to :ens-main props])}
|
||||
{:icon-color colors/gray
|
||||
:active? false
|
||||
:hide-chevron? (not enabled?)})))])
|
||||
|
||||
(defn tribute-to-talk-item
|
||||
[opts]
|
||||
[list.views/big-list-item
|
||||
|
@ -312,7 +324,8 @@
|
|||
login-data [:accounts/login]
|
||||
scroll (reagent/atom nil)
|
||||
active-contacts-count [:contacts/active-count]
|
||||
tribute-to-talk [:tribute-to-talk/profile]]
|
||||
tribute-to-talk [:tribute-to-talk/profile]
|
||||
stateofus-registrar [:ens.stateofus/registrar]]
|
||||
(let [shown-account (merge current-account changed-account)
|
||||
;; We scroll on the component once rendered. setTimeout is necessary,
|
||||
;; likely to allow the animation to finish.
|
||||
|
@ -344,6 +357,7 @@
|
|||
profile-icon-options)
|
||||
:on-change-text-event :my-profile/update-name}]]
|
||||
[share-profile-item (dissoc current-account :mnemonic)]
|
||||
[ens-item nil {:registrar stateofus-registrar}]
|
||||
[contacts-list-item active-contacts-count]
|
||||
(when tribute-to-talk
|
||||
[tribute-to-talk-item tribute-to-talk])
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
{:name :profile-stack
|
||||
:screens (cond-> [:my-profile
|
||||
:contacts-list
|
||||
:ens-main
|
||||
:ens-register
|
||||
:ens-terms
|
||||
:ens-name-details
|
||||
:blocked-users-list
|
||||
:profile-photo-capture
|
||||
:about-app
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
[status-im.ui.screens.browser.open-dapp.views :as open-dapp]
|
||||
[status-im.ui.screens.browser.views :as browser]
|
||||
[status-im.ui.screens.chat.views :as chat]
|
||||
[status-im.ui.screens.ens.views :as ens]
|
||||
[status-im.ui.screens.contacts-list.views :as contacts-list]
|
||||
[status-im.ui.screens.currency-settings.views :as currency-settings]
|
||||
[status-im.ui.screens.dapps-permissions.views :as dapps-permissions]
|
||||
|
@ -126,6 +127,10 @@
|
|||
:my-profile profile.user/my-profile
|
||||
:my-profile-ext-settings profile.user/extensions-settings
|
||||
:contacts-list contacts-list/contacts-list
|
||||
:ens-main ens/main
|
||||
:ens-register ens/register
|
||||
:ens-terms ens/terms
|
||||
:ens-name-details ens/name-details
|
||||
:blocked-users-list contacts-list/blocked-users-list
|
||||
:profile-photo-capture photo-capture/profile-photo-capture
|
||||
:about-app about-app/about-app
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
(ns status-im.test.ethereum.stateofus
|
||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||
[status-im.ethereum.stateofus :as stateofus]))
|
||||
|
||||
(deftest valid-username?
|
||||
(is (false? (stateofus/valid-username? nil)))
|
||||
(is (true? (stateofus/valid-username? "andrey")))
|
||||
(is (false? (stateofus/valid-username? "Andrey")))
|
||||
(is (true? (stateofus/valid-username? "andrey12"))))
|
|
@ -26,6 +26,7 @@
|
|||
[status-im.test.ethereum.ens]
|
||||
[status-im.test.ethereum.mnemonic]
|
||||
[status-im.test.extensions.core]
|
||||
[status-im.test.ethereum.stateofus]
|
||||
[status-im.test.extensions.ethereum]
|
||||
[status-im.test.fleet.core]
|
||||
[status-im.test.group-chats.core]
|
||||
|
@ -105,6 +106,7 @@
|
|||
'status-im.test.ethereum.eip681
|
||||
'status-im.test.ethereum.ens
|
||||
'status-im.test.ethereum.mnemonic
|
||||
'status-im.test.ethereum.stateofus
|
||||
'status-im.test.extensions.core
|
||||
'status-im.test.extensions.ethereum
|
||||
'status-im.test.fleet.core
|
||||
|
|
|
@ -294,6 +294,7 @@
|
|||
"network-id": "Network ID",
|
||||
"connection-problem": "Messages connection problem",
|
||||
"contact-code": "Contact code",
|
||||
"key": "Key",
|
||||
"enter-ens-or-contact-code": "Enter ENS username or contact code",
|
||||
"transactions-delete-content": "Transaction will be removed from 'Unsigned' list",
|
||||
"home": "Home",
|
||||
|
@ -1073,5 +1074,68 @@
|
|||
"signing-phrase" : "Signing phrase",
|
||||
"network-fee" : "Network fee",
|
||||
"sign-with-password" : "Sign with password",
|
||||
"signing-a-message" : "Signing a message"
|
||||
"signing-a-message" : "Signing a message",
|
||||
"etherscan-lookup": "Look up on Etherscan",
|
||||
"retry": "Retry",
|
||||
"ens-deposit": "Deposit",
|
||||
"ens-register": "Register",
|
||||
"ens-wallet-address": "Wallet address",
|
||||
"ens-terms-registration": "Terms of name registration.",
|
||||
"ens-terms-header": "Terms of name registration",
|
||||
"ens-terms-point-1": "Funds are deposited for 1 year. Your SNT will be locked, but not spent.",
|
||||
"ens-terms-point-2": "After 1 year, you can release the name and get your deposit back, or take no action to keep the name.",
|
||||
"ens-terms-point-3": "If terms of the contract change — e.g. Status makes contract upgrades — user has the right to release the username regardless of time held.",
|
||||
"ens-terms-point-4": "The contract controller cannot access your deposited funds. They can only be moved back to the address that sent them.",
|
||||
"ens-terms-point-5": "Your address(es) will be publicly associated with your ENS name.",
|
||||
"ens-terms-point-6": "Usernames are created as subdomain nodes of stateofus.eth and are subject to the ENS smart contract terms.",
|
||||
"ens-terms-point-7": "You authorize the contract to transfer SNT on your behalf. This can only occur when you approve a transaction to authorize the transfer.",
|
||||
"ens-terms-point-8": "These terms are guaranteed by the smart contract logic at addresses:",
|
||||
"ens-terms-point-9": "{{address}} (Status UsernameRegistrar) ",
|
||||
"ens-terms-point-10": "0x314159265dd8dbb310642f98f50c066173c1259b (ENS Registry).",
|
||||
"ens-usernames": "ENS usernames",
|
||||
"ens-your-username": "Your username",
|
||||
"ens-your-your-name": "Your ENS name",
|
||||
"ens-usernames-details": "Register a universal username to be easily recognized by other users",
|
||||
"ens-network-restriction": "Only available on Mainnet or ropsten",
|
||||
"ens-custom-domain": "Custom domain",
|
||||
"ens-want-domain": "I want a stateofus.eth domain",
|
||||
"ens-want-custom-domain": "I own a name on another domain",
|
||||
"ens-got-it": "Ok, got it",
|
||||
"ens-agree-to": "Agree to ",
|
||||
"ens-10-SNT": "10 SNT",
|
||||
"ens-username-hints": "At least 4 characters. Latin letters, numbers, and lowercase only.",
|
||||
"ens-username-invalid": "Letters and numbers only",
|
||||
"ens-username-registrable": "✓ Username available!",
|
||||
"ens-username-unregistrable": "Username already taken:(",
|
||||
"ens-username-owned": "✓ Username is owned by you. ",
|
||||
"ens-username-owned-continue": "Continuing will connect this username with your key.",
|
||||
"ens-username-connected": "This user name is owned by you and connected with your Chat key.",
|
||||
"ens-custom-username-unregistrable": "Username doesn’t belong to you :(",
|
||||
"ens-custom-username-hints": "Type the entire username including the custom domain like username.domain.eth",
|
||||
"ens-welcome-hints": "ENS names transform those crazy-long addresses into unique usernames.",
|
||||
"ens-welcome-point-1-title": "Simplify your ETH address",
|
||||
"ens-welcome-point-1": "Your complex wallet address (0x...) becomes an easy to read, remember & share URL: ",
|
||||
"ens-welcome-point-2-title": "10 SNT to register",
|
||||
"ens-welcome-point-2": "Register once to keep the name forever. After 1 year, you can release the name and get your SNT back.",
|
||||
"ens-welcome-point-3-title": "Connect & get paid",
|
||||
"ens-welcome-point-3": "Share your name to chat on Status or receive ETH and tokens",
|
||||
"ens-welcome-point-4-title": "Already own a username?",
|
||||
"ens-welcome-point-4": "You can verify and add any usernames you own in the next steps.",
|
||||
"ens-get-name": "Get a universal username",
|
||||
"ens-registered-title": "Nice!\nThe name is yours once the transaction is complete.",
|
||||
"ens-saved-title": "Username added",
|
||||
"ens-registration-failed-title": "Transaction failed",
|
||||
"ens-registered": "You can follow the progress in the Transaction History section of your wallet.",
|
||||
"ens-saved": " is now connected with your key and can be used in Status.",
|
||||
"ens-registration-failed": "To register the username, please try again.",
|
||||
"ens-powered-by": "Powered by Ethereum Name Services",
|
||||
"ens-add-username": "Add username",
|
||||
"ens-remove-username": "Remove username",
|
||||
"ens-remove-hints": "Removing will detach the username from your key.",
|
||||
"ens-locked": "Username locked. You won’t be able to release it until 25.05.2020",
|
||||
"ens-release-username": "Release username",
|
||||
"ens-your-usernames": "Your usernames",
|
||||
"ens-no-usernames": "You don't have any username connected",
|
||||
"ens-understand": "I understand that my wallet address will be publicly connected to my username.",
|
||||
"ens-transaction-pending": "Transaction pending..."
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue