diff --git a/src/status_im/extensions/core.cljs b/src/status_im/extensions/core.cljs index faa11e68cb..85a14ab852 100644 --- a/src/status_im/extensions/core.cljs +++ b/src/status_im/extensions/core.cljs @@ -366,6 +366,11 @@ :topics? :vector :blockhash? :string :on-result :event}} + 'ethereum/resolve-ens + {:permissions [:read] + :value :extensions/ethereum-resolve-ens + :arguments {:name :string + :on-result :event}} 'ethereum/call {:permissions [:read] :value :extensions/ethereum-call diff --git a/src/status_im/extensions/ethereum.cljs b/src/status_im/extensions/ethereum.cljs index d2fc505f9b..5b851a0358 100644 --- a/src/status_im/extensions/ethereum.cljs +++ b/src/status_im/extensions/ethereum.cljs @@ -8,6 +8,8 @@ [status-im.ui.screens.navigation :as navigation] [status-im.utils.ethereum.abi-spec :as abi-spec] [status-im.utils.fx :as fx] + [status-im.utils.ethereum.ens :as ens] + [status-im.utils.ethereum.core :as ethereum] [status-im.utils.handlers :as handlers] [status-im.utils.money :as money] [clojure.string :as string] @@ -27,6 +29,21 @@ (fn [{db :db} [_ on-result message]] (when on-result {:dispatch (on-result {:error message :result nil})}))) +(defn- wrap-with-resolution [db arguments address-keyword f] + "funtction responsible to resolve ens taken from argument + and call the specified function with resolved address" + (let [address (get arguments address-keyword) + first-address (if (vector? address) ;; currently we only support one ens for address + (first address) + address)] + (if (ens/is-valid-eth-name? first-address) + (let [{:keys [web3 network]} db + network-info (get-in db [:account/account :networks network]) + chain (ethereum/network->chain-keyword network-info) + registry (get ens/ens-registries chain)] + (ens/get-addr web3 registry first-address #(f db (assoc arguments address-keyword %)))) + (f db arguments)))) + ;; EXTENSION TRANSACTION -> SEND TRANSACTION (defn prepare-extension-transaction [params contacts on-result] (let [{:keys [to value data gas gasPrice nonce]} params @@ -52,29 +69,35 @@ nonce (assoc :nonce nonce)))) +(defn- execute-send-transaction [db {:keys [method params on-result] :as arguments}] + (let [tx-object (assoc (select-keys arguments [:to :gas :gas-price :value :nonce]) + :data (when (and method params) (abi-spec/encode method params))) + transaction (prepare-extension-transaction tx-object (:contacts/contacts db) on-result)] + (models.wallet/open-modal-wallet-for-transaction db transaction tx-object))) + (handlers/register-handler-fx :extensions/ethereum-send-transaction - (fn [{db :db} [_ _ {:keys [method params on-result] :as arguments}]] - (let [tx-object (assoc (select-keys arguments [:to :gas :gas-price :value :nonce]) - :data (when (and method params) (abi-spec/encode method params))) - transaction (prepare-extension-transaction tx-object (:contacts/contacts db) on-result)] - (models.wallet/open-modal-wallet-for-transaction db transaction tx-object)))) + (fn [{db :db} [_ _ arguments]] + (wrap-with-resolution db arguments :to execute-send-transaction))) + +(defn- execute-ethcall [_ {:keys [to method params outputs on-result]}] + (let [tx-object {:to to :data (when method (abi-spec/encode method params))}] + {:browser/call-rpc [{"jsonrpc" "2.0" + "method" "eth_call" + "params" [tx-object "latest"]} + #(let [result-str (when %2 + (get (js->clj %2) "result")) + result (cond + (= "0x" result-str) nil + (and outputs result-str) + (abi-spec/decode (string/replace result-str #"0x" "") outputs) + :else result-str)] + (re-frame/dispatch (on-result (merge {:result result} (when %1 {:error %1})))))]})) (handlers/register-handler-fx :extensions/ethereum-call - (fn [_ [_ _ {:keys [to method params outputs on-result]}]] - (let [tx-object {:to to :data (when method (abi-spec/encode method params))}] - {:browser/call-rpc [{"jsonrpc" "2.0" - "method" "eth_call" - "params" [tx-object "latest"]} - #(let [result-str (when %2 - (get (js->clj %2) "result")) - result (cond - (= "0x" result-str) nil - (and outputs result-str) - (abi-spec/decode (string/replace result-str #"0x" "") outputs) - :else result-str)] - (re-frame/dispatch (on-result (merge {:result result} (when %1 {:error %1})))))]}))) + (fn [{db :db} [_ _ {:keys [to] :as arguments}]] + (wrap-with-resolution db arguments :to execute-ethcall))) ;; eth_getLogs implementation @@ -114,18 +137,32 @@ (re-matches #"^[0-9]+$" block) (str "0x" (abi-spec/number-to-hex block)) :else block)) +(defn- execute-get-logs [_ {:keys [fromBlock toBlock address topics blockhash on-result]}] + (let [parsed-topics (mapv parse-topic topics) + args {:jsonrpc "2.0" + :method constants/web3-get-logs + :params [{:fromBlock (ensure-hex-bn fromBlock) + :toBlock (ensure-hex-bn toBlock) + :address address + :topics parsed-topics + :blockhash blockhash}]} + payload (types/clj->json args)] + (status/call-private-rpc payload #(let [{:keys [error result]} (types/json->clj %1) + response (merge {:result result} (when error {:error error}))] + (re-frame/dispatch (on-result response)))))) + (handlers/register-handler-fx :extensions/ethereum-logs - (fn [_ [_ _ {:keys [fromBlock toBlock address topics blockhash on-result]}]] - (let [parsed-topics (mapv parse-topic topics) - args {:jsonrpc "2.0" - :method constants/web3-get-logs - :params [{:fromBlock (ensure-hex-bn fromBlock) - :toBlock (ensure-hex-bn toBlock) - :address address - :topics parsed-topics - :blockhash blockhash}]} - payload (types/clj->json args)] - (status/call-private-rpc payload #(let [{:keys [error result]} (types/json->clj %1) - response (merge {:result result} (when error {:error error}))] - (re-frame/dispatch (on-result response))))))) \ No newline at end of file + (fn [{db :db} [_ _ arguments]] + (wrap-with-resolution db arguments :address execute-get-logs))) + +(handlers/register-handler-fx + :extensions/ethereum-resolve-ens + (fn [{db :db} [_ _ {:keys [name on-result] :as arguments}]] + (if (ens/is-valid-eth-name? name) + (let [{:keys [web3 network]} db + network-info (get-in db [:account/account :networks network]) + chain (ethereum/network->chain-keyword network-info) + registry (get ens/ens-registries chain)] + (ens/get-addr web3 registry name #(re-frame/dispatch (on-result {:result %})))) + (re-frame/dispatch (on-result {:error (str "'" name "' is not a valid name")}))))) \ No newline at end of file