[#13007] Move ENS logic to status-go

Signed-off-by: andrey <motor4ik@gmail.com>
This commit is contained in:
andrey 2022-01-21 11:49:16 +01:00
parent c0e30b459f
commit 8e560d313d
No known key found for this signature in database
GPG Key ID: 89B67245FD2F0272
16 changed files with 158 additions and 532 deletions

View File

@ -1,6 +1,5 @@
status-im.utils.build/warning-handler
status-im.utils.build/get-current-sha
status-im.ethereum.resolver/name
status-im.chat.constants/spacing-char
status-im.chat.constants/arg-wrapping-char
status-im.ios.core/init

View File

@ -101,23 +101,22 @@
(re-frame/reg-fx
::resolve-contract
(fn [{:keys [chain contract on-success]}]
(let [register (get ens/ens-registries chain)]
(when contract
(if (string/starts-with? contract "0x")
(on-success contract)
(ens/get-addr register contract on-success))))))
(fn [{:keys [chain-id contract on-success]}]
(when contract
(if (string/starts-with? contract "0x")
(on-success contract)
(ens/address chain-id contract on-success)))))
(fx/defn create [{:keys [db]}]
(when-not config/google-free
{::resolve-contract {:chain (ethereum/chain-keyword db)
{::resolve-contract {:chain (ethereum/chain-id db)
:contract (contracts/get-address db :status/acquisition)
:on-success #(re-frame/dispatch [:set-in [:acquisition :contract] %])}
::get-referrer nil}))
(fx/defn login [{:keys [db]}]
(when-not config/google-free
{::resolve-contract {:chain (ethereum/chain-keyword db)
{::resolve-contract {:chain (ethereum/chain-id db)
:contract (contracts/get-address db :status/acquisition)
:on-success #(re-frame/dispatch [:set-in [:acquisition :contract] %])}
::check-referrer nil}))

View File

@ -3,7 +3,6 @@
[re-frame.core :as re-frame]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.ens :as ens]
[status-im.ethereum.resolver :as resolver]
[status-im.add-new.db :as db]
[status-im.utils.random :as random]
[status-im.utils.utils :as utils]
@ -13,14 +12,14 @@
[status-im.contact.core :as contact]
[status-im.router.core :as router]
[status-im.navigation :as navigation]
[status-im.ethereum.stateofus :as stateofus]
[status-im.utils.db :as utils.db]))
(re-frame/reg-fx
:resolve-public-key
(fn [{:keys [chain contact-identity cb]}]
(let [registry (get ens/ens-registries chain)
ens-name (resolver/ens-name-parse contact-identity)]
(resolver/pubkey registry ens-name cb))))
(fn [{:keys [chain-id contact-identity cb]}]
(let [ens-name (stateofus/ens-name-parse contact-identity)]
(ens/pubkey chain-id ens-name cb))))
;;NOTE we want to handle only last resolve
(def resolve-last-id (atom nil))
@ -53,17 +52,16 @@
:else
:valid)
:error error
:ens-name (resolver/ens-name-parse new-ens-name)})}
:ens-name (stateofus/ens-name-parse new-ens-name)})}
(when is-ens?
(reset! resolve-last-id (random/id))
(let [chain (ethereum/chain-keyword db)]
{:resolve-public-key
{:chain chain
:contact-identity new-identity
:cb #(re-frame/dispatch [:new-chat/set-new-identity
%
new-identity
@resolve-last-id])}}))))))))
{:resolve-public-key
{:chain-id (ethereum/chain-id db)
:contact-identity new-identity
:cb #(re-frame/dispatch [:new-chat/set-new-identity
%
new-identity
@resolve-last-id])}})))))))
(fx/defn clear-new-identity
{:events [::clear-new-identity ::new-chat-focus]}

View File

@ -6,7 +6,6 @@
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.ens :as ens]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.ethereum.resolver :as resolver]
[status-im.i18n.i18n :as i18n]
[status-im.native-module.core :as status]
[status-im.ui.components.list-selection :as list-selection]
@ -14,7 +13,6 @@
[status-im.utils.contenthash :as contenthash]
[status-im.utils.fx :as fx]
[status-im.utils.http :as http]
[status-im.utils.multihash :as multihash]
[status-im.utils.platform :as platform]
[status-im.utils.random :as random]
[status-im.utils.types :as types]
@ -73,22 +71,10 @@
(let [history-host (http/url-host (try (nth history history-index) (catch js/Error _)))]
(cond-> browser history-host (assoc :unsafe? (eth-phishing-detect history-host)))))
(defn- content->hash [hex]
(when (and hex (not= hex "0x"))
;; TODO(julien) Remove once our ENS DApp are migrated
(multihash/base58 (multihash/create :sha2-256 (subs hex 2)))))
(defn resolve-ens-content-callback [hex]
(let [hash (content->hash hex)]
(if (and hash (not= hash resolver/default-hash))
(re-frame/dispatch [:browser.callback/resolve-ens-multihash-success {:namespace :ipfs :hash hash}])
(re-frame/dispatch [:browser.callback/resolve-ens-contenthash]))))
(defn resolve-ens-contenthash-callback [hex]
(let [{:keys [hash] :as m} (contenthash/decode hex)]
(if (and hash (not= hash resolver/default-hash))
(re-frame/dispatch [:browser.callback/resolve-ens-multihash-success m])
(re-frame/dispatch [:browser.callback/resolve-ens-multihash-error]))))
(defn resolve-ens-contenthash-callback [url]
(if (not (string/blank? url))
(re-frame/dispatch [:browser.callback/resolve-ens-multihash-success url])
(re-frame/dispatch [:browser.callback/resolve-ens-multihash-error])))
(fx/defn resolve-url
[{:keys [db]} {:keys [error? resolved-url]}]
@ -96,26 +82,12 @@
(let [current-url (get-current-url (get-current-browser db))
host (http/url-host current-url)]
(if (and (not resolved-url) (ens/is-valid-eth-name? host))
(let [chain (ethereum/chain-keyword db)]
{:db (update db :browser/options assoc :resolving? true)
:browser/resolve-ens-content {:registry (get ens/ens-registries
chain)
:ens-name host
:cb resolve-ens-content-callback}})
{:db (update db :browser/options assoc :resolving? true)
:browser/resolve-ens-contenthash {:chain-id (ethereum/chain-id db)
:ens-name host
:cb resolve-ens-contenthash-callback}}
{:db (update db :browser/options assoc :url (or resolved-url current-url) :resolving? false)}))))
(fx/defn resolve-ens-contenthash
{:events [:browser.callback/resolve-ens-contenthash]}
[{:keys [db]}]
(let [current-url (get-current-url (get-current-browser db))
host (http/url-host current-url)
chain (ethereum/chain-keyword db)]
{:db (update db :browser/options assoc :resolving? true)
:browser/resolve-ens-contenthash {:registry (get ens/ens-registries
chain)
:ens-name host
:cb resolve-ens-contenthash-callback}}))
(fx/defn update-browser
[{:keys [db]}
{:keys [browser-id] :as browser}]
@ -217,11 +189,11 @@
(fx/defn resolve-ens-multihash-success
{:events [:browser.callback/resolve-ens-multihash-success]}
[{:keys [db] :as cofx} m]
[{:keys [db] :as cofx} url]
(let [current-url (get-current-url (get-current-browser db))
host (http/url-host current-url)
path (subs current-url (+ (.indexOf ^js current-url host) (count host)))
gateway (storage-gateway m)]
gateway url]
(fx/merge cofx
{:db (-> (update db :browser/options
assoc
@ -497,15 +469,10 @@
(= type constants/api-request)
(browser.permissions/process-permission cofx dapp-name permission messageId params))))
(re-frame/reg-fx
:browser/resolve-ens-content
(fn [{:keys [registry ens-name cb]}]
(resolver/content registry ens-name cb)))
(re-frame/reg-fx
:browser/resolve-ens-contenthash
(fn [{:keys [registry ens-name cb]}]
(resolver/contenthash registry ens-name cb)))
(fn [{:keys [chain-id ens-name cb]}]
(ens/resource-url chain-id ens-name cb)))
(re-frame/reg-fx
:browser/send-to-bridge

View File

@ -7,7 +7,6 @@
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.eip55 :as eip55]
[status-im.ethereum.ens :as ens]
[status-im.ethereum.resolver :as resolver]
[status-im.ethereum.stateofus :as stateofus]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.signing.core :as signing]
@ -23,6 +22,26 @@
username
(stateofus/subdomain username)))
(re-frame/reg-fx
::resolve-address
(fn [[chain-id name cb]]
(ens/address chain-id name cb)))
(re-frame/reg-fx
::resolve-owner
(fn [[chain-id name cb]]
(ens/owner chain-id name cb)))
(re-frame/reg-fx
::resolve-pubkey
(fn [[chain-id name cb]]
(ens/pubkey chain-id name cb)))
(re-frame/reg-fx
::get-expiration-time
(fn [[chain-id name cb]]
(ens/expire-at chain-id name cb)))
(fx/defn update-ens-tx-state
{:events [:update-ens-tx-state]}
[{:keys [db]} new-state username custom-domain? tx-hash]
@ -52,29 +71,6 @@
[{:keys [db]} tx-hash]
{:db (update db :ens/registrations dissoc tx-hash)})
(re-frame/reg-fx
::resolve-address
(fn [[registry name cb]]
(ens/get-addr registry name cb)))
(re-frame/reg-fx
::resolve-owner
(fn [[registry name cb]]
(ens/get-owner registry name cb)))
(re-frame/reg-fx
::resolve-pubkey
(fn [[registry name cb]]
(resolver/pubkey registry name cb)))
(re-frame/reg-fx
::get-expiration-time
(fn [[chain label-hash cb]]
(stateofus/get-registrar
chain
(fn [registrar]
(stateofus/get-expiration-time registrar label-hash cb)))))
(fx/defn set-state
{:events [::name-resolved]}
[{:keys [db]} username state address]
@ -135,7 +131,7 @@
nil)))
(defn- on-resolve-owner
[registry custom-domain? username addresses public-key response resolve-last-id* resolve-last-id]
[chain-id custom-domain? username addresses public-key response resolve-last-id* resolve-last-id]
(when (= @resolve-last-id* resolve-last-id)
(cond
@ -146,14 +142,15 @@
;; if we get an address back, we try to get the public key associated
;; with the username as well
(get addresses (eip55/address->checksum response))
(resolver/pubkey registry (fullname custom-domain? username)
#(re-frame/dispatch [::name-resolved username
(cond
(not public-key) :owned
(= % public-key) :connected
:else :connected-with-different-key)
(eip55/address->checksum response)]))
(ens/pubkey
chain-id
(fullname custom-domain? username)
#(re-frame/dispatch [::name-resolved username
(cond
(not public-key) :owned
(= % public-key) :connected
:else :connected-with-different-key)
(eip55/address->checksum response)]))
:else
(re-frame/dispatch [::name-resolved username :taken]))))
@ -163,6 +160,9 @@
3 50
1 10))
;; (andrey) there is the method "register" in status-go, but im not sure how we could use it
;; because we still need to prepare tx and show it to user, and then have a condition to do not sign tx but
;; call register method instead, doesn't look like a good solution
(fx/defn register-name
{:events [::register-name-pressed]}
[{:keys [db] :as cofx}]
@ -225,11 +225,11 @@
(let [{:keys [multiaccount]} db
{:keys [public-key]} multiaccount
addresses (ethereum/addresses-without-watch db)
registry (get ens/ens-registries (ethereum/chain-keyword db))]
{::resolve-owner [registry
chain-id (ethereum/chain-id db)]
{::resolve-owner [chain-id
(fullname custom-domain? username)
#(on-resolve-owner
registry custom-domain? username addresses public-key %
chain-id custom-domain? username addresses public-key %
resolve-last-id @resolve-last-id)]})))))
(fx/defn return-to-ens-main-screen
@ -260,7 +260,7 @@
(fx/defn save-preferred-name
{:events [::save-preferred-name]}
[{:keys [db] :as cofx} name]
[cofx name]
(multiaccounts.update/multiaccount-update cofx
:preferred-name name
{}))
@ -270,7 +270,7 @@
it should only be called if the user cancels the signing
Actual registration failure has not been implemented properly"
{:events [::on-registration-failure]}
[{:keys [db]} username])
[_ _])
(fx/defn store-name-address
{:events [::address-resolved]}
@ -293,20 +293,17 @@
(fx/defn navigate-to-name
{:events [::navigate-to-name]}
[{:keys [db] :as cofx} username]
(let [chain (ethereum/chain-keyword db)
registry (get ens/ens-registries chain)]
(let [chain-id (ethereum/chain-id db)]
(fx/merge cofx
{::get-expiration-time
[chain
(-> username
stateofus/username
ethereum/sha3)
[chain-id
(stateofus/username username)
#(re-frame/dispatch [::get-expiration-time-success username %])]
::resolve-address
[registry username
[chain-id username
#(re-frame/dispatch [::address-resolved username %])]
::resolve-pubkey
[registry username
[chain-id username
#(re-frame/dispatch [::public-key-resolved username %])]}
(navigation/navigate-to-cofx :ens-name-details username))))

View File

@ -19,6 +19,7 @@
(def default-namehash "0000000000000000000000000000000000000000000000000000000000000000")
(def default-address "0x0000000000000000000000000000000000000000")
(def default-key "0x0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
(def default-hash "0x0000000000000000000000000000000000000000000000000000000000000000")
(defn namehash
[s]
@ -33,8 +34,6 @@
(ethereum/sha3 (str (namehash remainder)
(subs (ethereum/sha3 label) 2))))))))
;; Registry contract
(defn resolver
[registry ens-name cb]
(json-rpc/eth-call
@ -47,113 +46,6 @@
(fn [[address]]
(cb (when-not (= address default-address) address)))}))
(defn owner
[registry ens-name cb]
(json-rpc/eth-call
{:contract registry
:method "owner(bytes32)"
:params [(namehash ens-name)]
:outputs ["address"]
:on-error #(cb "0x")
:on-success
(fn [[address]]
(cb address))}))
(defn ttl
[registry ens-name cb]
(json-rpc/eth-call
{:contract registry
:method "ttl(bytes32)"
:params [(namehash ens-name)]
:outputs ["uint256"]
:on-success
(fn [[ttl]]
(cb ttl))}))
;; Resolver contract
;; Resolver must implement EIP65 (supportsInterface). When interacting with an unknown resolver it's safer to rely on it.
(def addr-hash "0x3b3b57de")
(defn addr
[resolver ens-name cb]
(json-rpc/eth-call
{:contract resolver
:method "addr(bytes32)"
:params [(namehash ens-name)]
:outputs ["address"]
:on-error #(cb "0x")
:on-success
(fn [[address]]
(cb address))}))
(def name-hash "0x691f3431")
;; Defined by https://eips.ethereum.org/EIPS/eip-181
(defn name
[resolver ens-name cb]
(json-rpc/eth-call
{:contract resolver
:method "name(bytes32)"
:params [(namehash ens-name)]
:outputs ["string"]
:on-error #(cb "0x")
:on-success
(fn [[name]]
(cb name))}))
(defn cleanup-hash [raw-hash]
;; NOTE: it would be better if our abi-spec/decode was able to do that
(let [;; ignore hex prefix
[_ raw-hash-rest] (split-at 2 raw-hash)
;; the first field gives us the length of the next one in hex and has
;; a length of 32 bytes
;; 1 byte is 2 chars here
[next-field-length-hex raw-hash-rest] (split-at 64 raw-hash-rest)
next-field-length (* ^number (abi-spec/hex-to-number (string/join next-field-length-hex)) 2)
;; we get the next field which is the length of the hash and is
;; expected to be 32 bytes as well
[hash-field-length-hex raw-hash-rest] (split-at next-field-length
raw-hash-rest)
hash-field-length (* ^number (abi-spec/hex-to-number (string/join hash-field-length-hex)) 2)
;; we get the hash
[hash _] (split-at hash-field-length raw-hash-rest)]
(str "0x" (string/join hash))))
(defn contenthash
[resolver ens-name cb]
(json-rpc/eth-call
{:contract resolver
:method "contenthash(bytes32)"
:params [(namehash ens-name)]
:on-error #(cb "0x")
:on-success
(fn [raw-hash]
;; NOTE: it would be better if our abi-spec/decode was able to do that
(cb (cleanup-hash raw-hash)))}))
(defn content
[resolver ens-name cb]
(json-rpc/eth-call
{:contract resolver
:method "content(bytes32)"
:params [(namehash ens-name)]
:on-success
(fn [hash]
(cb hash))
;;at some point infura started to return execution reverted error instead of "0x" result
;;our code expects "0x" result
:on-error #(cb "0x")}))
(def ABI-hash "0x2203ab56")
(def pubkey-hash "0xc8690233")
(defn uncompressed-public-key
[x y]
(when (and x y)
(str "0x04" x y)))
(defn valid-eth-name-prefix?
[prefix]
(not
@ -167,29 +59,43 @@
(string? ens-name)
(string/ends-with? ens-name ".eth")))
(defn address
[chain-id ens-name cb]
{:pre [(is-valid-eth-name? ens-name)]}
(json-rpc/call {:method "ens_addressOf"
:params [chain-id ens-name]
:on-success cb
:on-error #(cb "0x")}))
(defn pubkey
[resolver ens-name cb]
(json-rpc/eth-call
{:contract resolver
:method "pubkey(bytes32)"
:params [(namehash ens-name)]
:outputs ["bytes32" "bytes32"]
:on-success
(fn [[x y]]
(let [public-key (uncompressed-public-key x y)]
(cb public-key)))
;;at some point infura started to return execution reverted error instead of "0x" result
;;our code expects "0x" result
:on-error #(cb "0x")}))
(defn get-addr
[registry ens-name cb]
[chain-id ens-name cb]
{:pre [(is-valid-eth-name? ens-name)]}
(resolver registry
ens-name
#(addr % ens-name cb)))
(json-rpc/call {:method "ens_publicKeyOf"
:params [chain-id ens-name]
:on-success (fn [result]
(cb (str "0x04" (subs result 2))))
;;at some point infura started to return execution reverted error instead of "0x" result
;;our code expects "0x" result
:on-error #(cb "0x")}))
(defn get-owner
[registry ens-name cb]
{:pre [(is-valid-eth-name? ens-name)]}
(owner registry ens-name cb))
(defn owner
[chain-id ens-name cb]
(json-rpc/call {:method "ens_ownerOf"
:params [chain-id ens-name]
:on-success cb
:on-error #(cb "0x")}))
(defn resource-url
[chain-id ens-name cb]
(json-rpc/call {:method "ens_resourceURL"
:params [chain-id ens-name]
:on-success #(cb (str "https://" (:Host %)))
:on-error #(cb "0x")}))
(defn expire-at
[chain-id ens-name cb]
(json-rpc/call {:method "ens_expireAt"
:params [chain-id ens-name]
:on-success
;;NOTE: returns a timestamp in s and we want ms
#(cb (* (js/Number (abi-spec/hex-to-number %)) 1000))}))

View File

@ -8,12 +8,4 @@
(is (= "0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"
(ens/namehash "eth")))
(is (= "0xde9b09fd7c5f901e23a3f19fecc54828e9c848539801e86591bd9801b019f84f"
(ens/namehash "foo.eth"))))
(deftest cleanup-hash
;; simpledapp.eth
(is (= "0xe30101701220795c1ea0ceaf4ceedc9896f14b73bb30e978e4855ee221b9a57f5a934268280e"
(ens/cleanup-hash "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026e30101701220795c1ea0ceaf4ceedc9896f14b73bb30e978e4855ee221b9a57f5a934268280e0000000000000000000000000000000000000000000000000000")))
;; ethereum.eth
(is (= "0xe301017012206e70f0f72e2bcd0ad69bb2b15ee9e0f4f88693f6b2f485e48699e7d6f8dbd62a"
(ens/cleanup-hash "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026e301017012206e70f0f72e2bcd0ad69bb2b15ee9e0f4f88693f6b2f485e48699e7d6f8dbd62a0000000000000000000000000000000000000000000000000000"))))
(ens/namehash "foo.eth"))))

View File

@ -29,6 +29,12 @@
"eth_getCode" {}
"eth_syncing" {}
"eth_feeHistory" {}
"ens_publicKeyOf" {}
"ens_addressOf" {}
"ens_expireAt" {}
"ens_ownerOf" {}
"ens_contentHash" {}
"ens_resourceURL" {}
"net_version" {}
"web3_clientVersion" {}
"shh_generateSymKeyFromPassword" {}

View File

@ -1,35 +0,0 @@
(ns status-im.ethereum.resolver
(:refer-clojure :exclude [name])
(:require [status-im.ethereum.ens :as ens]
[status-im.ethereum.stateofus :as stateofus]
[clojure.string :as string]))
(def default-hash "0x0000000000000000000000000000000000000000000000000000000000000000")
(defn contenthash [registry ens-name cb]
(ens/resolver registry
ens-name
#(ens/contenthash % ens-name cb)))
(defn content [registry ens-name cb]
(ens/resolver registry
ens-name
#(ens/content % ens-name cb)))
(defn name [registry ens-name cb]
(ens/resolver registry
ens-name
#(ens/name % ens-name cb)))
(defn pubkey
[registry ens-name cb]
{:pre [(ens/is-valid-eth-name? ens-name)]}
(ens/resolver registry
ens-name
#(ens/pubkey % ens-name cb)))
(defn ens-name-parse [contact-identity]
(when (string? contact-identity)
(string/lower-case
(if (ens/is-valid-eth-name? contact-identity)
contact-identity
(stateofus/subdomain contact-identity)))))

View File

@ -1,8 +1,8 @@
(ns status-im.ethereum.stateofus
(:require [clojure.string :as string]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.config :as config]
[status-im.ethereum.ens :as ens]))
[status-im.ethereum.ens :as ens]
[status-im.ethereum.core :as ethereum]))
(def domain "stateofus.eth")
@ -37,14 +37,13 @@
(defn get-registrar [chain callback]
(if-let [contract (get @registrars-cache chain)]
(callback contract)
(let [registry (get ens/ens-registries chain)]
(ens/get-owner
registry
domain
(fn [addr]
(let [addr (or addr (get old-registrars chain))]
(swap! registrars-cache assoc chain addr)
(callback addr)))))))
(ens/owner
(ethereum/chain-keyword->chain-id chain)
domain
(fn [addr]
(let [addr (or addr (get old-registrars chain))]
(swap! registrars-cache assoc chain addr)
(callback addr))))))
(defn get-cached-registrar [chain]
(get @registrars-cache chain (get old-registrars chain)))
@ -58,14 +57,9 @@
(and (lower-case? username)
(re-find #"^[a-z0-9]+$" username))))
(defn get-expiration-time
[registrar label-hash cb]
(json-rpc/eth-call
{:contract registrar
:method "getExpirationTime(bytes32)"
:params [label-hash]
:outputs ["uint256"]
:on-success
(fn [[release-time]]
;;NOTE: returns a timestamp in s and we want ms
(cb (* release-time 1000)))}))
(defn ens-name-parse [contact-identity]
(when (string? contact-identity)
(string/lower-case
(if (ens/is-valid-eth-name? contact-identity)
contact-identity
(subdomain contact-identity)))))

View File

@ -7,12 +7,12 @@
[status-im.utils.security :as security]
[status-im.ethereum.eip681 :as eip681]
[status-im.ethereum.ens :as ens]
[status-im.ethereum.resolver :as resolver]
[cljs.spec.alpha :as spec]
[status-im.ethereum.core :as ethereum]
[status-im.utils.db :as utils.db]
[status-im.utils.http :as http]
[status-im.chat.models :as chat.models]))
[status-im.chat.models :as chat.models]
[status-im.ethereum.stateofus :as stateofus]))
(def ethereum-scheme "ethereum:")
@ -61,12 +61,6 @@
(defn match-uri [uri]
(assoc (bidi/match-route routes uri) :uri uri :query-params (parse-query-params uri)))
(defn resolve-public-key
[{:keys [chain contact-identity cb]}]
(let [registry (get ens/ens-registries chain)
ens-name (resolver/ens-name-parse contact-identity)]
(resolver/pubkey registry ens-name cb)))
(defn match-contact-async
[chain {:keys [user-id]} callback]
(let [valid-key (and (spec/valid? :global/public-key user-id)
@ -78,10 +72,10 @@
(and (not valid-key) (string? user-id) (not (string/blank? user-id))
(not= user-id "0x"))
(let [registry (get ens/ens-registries chain)
ens-name (resolver/ens-name-parse user-id)
(let [chain-id (ethereum/chain-keyword->chain-id chain)
ens-name (stateofus/ens-name-parse user-id)
on-success #(match-contact-async chain {:user-id %} callback)]
(resolver/pubkey registry ens-name on-success))
(ens/pubkey chain-id ens-name on-success))
:else
(callback {:type :contact

View File

@ -1,185 +0,0 @@
(ns status-im.utils.multihash
"Core multihash type definition and helper methods."
(:require
[alphabase.base58 :as b58]
[alphabase.bytes :as bytes]
[alphabase.hex :as hex]))
(def algorithm-codes
"Map of information about the available content hashing algorithms."
{:sha1 0x11
:sha2-256 0x12
:sha2-512 0x13
:sha3 0x14
:blake2b 0x40
:blake2s 0x41})
(defn app-code?
"True if the given code number is assigned to the application-specfic range.
Returns nil if the argument is not an integer."
[code]
(when (integer? code)
(< 0 code 0x10)))
(defn get-algorithm
"Looks up an algorithm by keyword name or code number. Returns `nil` if the
value does not map to any valid algorithm."
[value]
(cond
(keyword? value)
(when-let [code (get algorithm-codes value)]
{:code code, :name value})
(not (integer? value))
nil
(app-code? value)
{:code value, :name (keyword (str "app-" value))}
:else
(some #(when (= value (val %))
{:code value, :name (key %)})
algorithm-codes)))
;; ## Multihash Type
;; Multihash identifiers have two properties:
;;
;; - `code` is a numeric code for an algorithm entry in `algorithm-codes` or an
;; application-specific algorithm code.
;; - `hex-digest` is a string holding the hex-encoded algorithm output.
;;
;; Multihash values also support metadata.
(deftype Multihash [code hex-digest _meta]
Object
(toString
[this]
(str "hash:" (name (:name (get-algorithm code))) \: hex-digest))
(-equiv
[this that]
(cond
(identical? this that) true
(instance? Multihash that)
(and (= code (:code that))
(= hex-digest (:hex-digest that)))
:else false))
IHash
(-hash
[this]
(hash-combine code hex-digest))
IComparable
(-compare
[this that]
(cond
(= this that) 0
(< code (:code that)) -1
(> code (:code that)) 1
:else (compare hex-digest (:hex-digest that))))
ILookup
(-lookup
[this k]
(-lookup this k nil))
(-lookup
[this k not-found]
(case k
:code code
:algorithm (:name (get-algorithm code))
:length (/ (count hex-digest) 2)
:digest (hex/decode hex-digest)
:hex-digest hex-digest
not-found))
IMeta
(-meta
[this]
_meta)
IWithMeta
(-with-meta
[this meta-map]
(Multihash. code hex-digest meta-map)))
(defn create
"Constructs a new Multihash identifier. Accepts either a numeric algorithm
code or a keyword name as the first argument. The digest may either by a byte
array or a hex string."
[algorithm digest]
(let [algo (get-algorithm algorithm)]
(when-not (integer? (:code algo))
(throw (ex-info
(str "Argument " (pr-str algorithm) " does not "
"represent a valid hash algorithm.")
{:algorithm algorithm})))
(let [hex-digest (if (string? digest) digest (hex/encode digest))
byte-len (/ (count hex-digest) 2)]
(when (< 127 byte-len)
(throw (ex-info (str "Digest length must be less than 128 bytes: "
byte-len)
{:length byte-len})))
(when-let [err (hex/validate hex-digest)]
(throw (ex-info err {:hex-digest hex-digest})))
(->Multihash (:code algo) hex-digest nil))))
;; ## Encoding and Decoding
(defn encode
"Encodes a multihash into a binary representation."
^bytes
[mhash]
(let [length (:length mhash)
encoded (bytes/byte-array (+ length 2))]
(bytes/set-byte encoded 0 (:code mhash))
(bytes/set-byte encoded 1 length)
(bytes/copy (:digest mhash) 0 encoded 2 length)
encoded))
(defn hex
"Encodes a multihash into a hexadecimal string."
[mhash]
(when mhash
(hex/encode (encode mhash))))
(defn base58
"Encodes a multihash into a Base-58 string."
[mhash]
(when mhash
(b58/encode (encode mhash))))
(defn decode-array
"Decodes a byte array directly into multihash. Throws `ex-info` with a `:type`
of `:multihash/bad-input` if the data is malformed or invalid."
[^bytes encoded]
(let [encoded-size (alength encoded)
min-size 3]
(when (< encoded-size min-size)
(throw (ex-info
(str "Cannot read multihash from byte array: " encoded-size
" is less than the minimum of " min-size)
{:type :multihash/bad-input}))))
(let [code (bytes/get-byte encoded 0)
length (bytes/get-byte encoded 1)
payload (- (alength encoded) 2)]
(when-not (pos? length)
(throw (ex-info
(str "Encoded length " length " is invalid")
{:type :multihash/bad-input})))
(when (< payload length)
(throw (ex-info
(str "Encoded digest length " length " exceeds actual "
"remaining payload of " payload " bytes")
{:type :multihash/bad-input})))
(let [digest (bytes/byte-array length)]
(bytes/copy encoded 2 digest 0 length)
(create code digest))))

View File

@ -21,11 +21,10 @@
[taoensso.timbre :as log]
[status-im.wallet.prices :as prices]
[status-im.utils.hex :as hex]
[status-im.ethereum.ens :as ens]
[status-im.ens.core :as ens.core]
[status-im.ethereum.resolver :as resolver]
[status-im.utils.mobile-sync :as utils.mobile-sync]
[status-im.multiaccounts.key-storage.core :as key-storage]))
[status-im.multiaccounts.key-storage.core :as key-storage]
[status-im.ethereum.stateofus :as stateofus]))
(fx/defn start-adding-new-account
{:events [:wallet.accounts/start-adding-new-account]}
@ -242,21 +241,18 @@
(fx/defn set-account-to-watch
{:events [:wallet.accounts/set-account-to-watch]}
[{:keys [db] :as cofx} account]
[{:keys [db]} account]
(let [name? (and (>= (count account) 3)
(not (hex/valid-hex? account)))
chain (ethereum/chain-keyword db)]
(not (hex/valid-hex? account)))]
(log/debug "[wallet] set-account-to-watch" account
"name?" name?)
(cond-> {:db (assoc-in db [:add-account :address] account)}
name?
(assoc ::ens.core/resolve-address
(let [registry (get ens/ens-registries chain)
ens-name (resolver/ens-name-parse account)]
[registry
ens-name
#(re-frame/dispatch
[:wallet.accounts/set-account-to-watch %])])))))
[(ethereum/chain-id db)
(stateofus/ens-name-parse account)
#(re-frame/dispatch
[:wallet.accounts/set-account-to-watch %])]))))
(fx/defn add-new-account
{:events [:wallet.accounts/add-new-account]}

View File

@ -36,14 +36,14 @@
(re-frame/reg-fx
::resolve-addresses
(fn [{:keys [registry ens-names callback]}]
(fn [{:keys [chain-id ens-names callback]}]
;; resolve all addresses then call the callback function with the array of
;;addresses as parameter
(-> (js/Promise.all
(clj->js (mapv (fn [ens-name]
(js/Promise.
(fn [resolve _]
(ens/get-addr registry ens-name resolve))))
(ens/address chain-id ens-name resolve))))
ens-names)))
(.then callback)
(.catch (fn [error]
@ -108,7 +108,7 @@
;; if there are no ens-names, we dispatch request-uri-parsed immediately
(request-uri-parsed cofx message uri)
{::resolve-addresses
{:registry (get ens/ens-registries (ethereum/chain-keyword db))
{:chain-id (ethereum/chain-id db)
:ens-names ens-names
:callback
(fn [addresses]

View File

@ -538,8 +538,8 @@
(re-frame/reg-fx
::resolve-address
(fn [{:keys [registry ens-name cb]}]
(ens/get-addr registry ens-name cb)))
(fn [{:keys [chain-id ens-name cb]}]
(ens/address chain-id ens-name cb)))
(fx/defn on-recipient-address-resolved
{:events [::recipient-address-resolved]}
@ -554,8 +554,7 @@
(fx/defn prepare-transaction-from-chat
{:events [:wallet/prepare-transaction-from-chat]}
[{:keys [db]}]
(let [chain (ethereum/chain-keyword db)
identity (:current-chat-id db)
(let [identity (:current-chat-id db)
{:keys [ens-verified name] :as contact}
(or (get-in db [:contacts/contacts identity])
(-> identity
@ -571,7 +570,7 @@
:dispatch [:open-modal :prepare-send-transaction]}
ens-verified
(assoc ::resolve-address
{:registry (get ens/ens-registries chain)
{:chain-id (ethereum/chain-id db)
:ens-name (if (= (.indexOf ^js name ".") -1)
(stateofus/subdomain name)
name)

View File

@ -18,8 +18,8 @@
(re-frame/reg-fx
::resolve-address
(fn [{:keys [registry ens-name cb]}]
(ens/get-addr registry ens-name cb)))
(fn [{:keys [chain-id ens-name cb]}]
(ens/address chain-id ens-name cb)))
(re-frame/reg-fx
:wallet.recipient/address-paste
@ -37,8 +37,7 @@
[{:keys [db] :as cofx} raw-recipient id]
(when (or (not id) (= id @resolve-last-id))
(reset! resolve-last-id nil)
(let [chain (ethereum/chain-keyword db)
recipient (utils/safe-trim raw-recipient)]
(let [recipient (utils/safe-trim raw-recipient)]
(cond
(ethereum/address? recipient)
(let [checksum (eip55/address->checksum recipient)]
@ -65,7 +64,7 @@
(do
(reset! resolve-last-id (random/id))
{::resolve-address
{:registry (get ens/ens-registries chain)
{:chain-id (ethereum/chain-id db)
:ens-name ens-name
:cb #(re-frame/dispatch [::recipient-address-resolved % @resolve-last-id])}})
{:db (assoc-in db [:wallet/recipient :searching] false)}))