From 5ba5395d57aef9fdb2bade5ab9747a6f33ad8c96 Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Fri, 19 Oct 2018 10:07:55 +0200 Subject: [PATCH] [extensions] ethereum events Signed-off-by: Andrey Shovkoplyas --- src/status_im/chat/commands/core.cljs | 2 +- src/status_im/extensions/core.cljs | 48 +++++------ src/status_im/extensions/ethereum.cljs | 39 +++++++++ src/status_im/models/wallet.cljs | 84 ++++++++++++++----- src/status_im/ui/screens/wallet/send/db.cljs | 5 +- .../ui/screens/wallet/send/events.cljs | 43 +++++----- 6 files changed, 148 insertions(+), 73 deletions(-) create mode 100644 src/status_im/extensions/ethereum.cljs diff --git a/src/status_im/chat/commands/core.cljs b/src/status_im/chat/commands/core.cljs index 3b4361fef2..beb23e603c 100644 --- a/src/status_im/chat/commands/core.cljs +++ b/src/status_im/chat/commands/core.cljs @@ -139,7 +139,7 @@ :parameters [{:id :keyword :type {:one-of #{:text :phone :password :number}} :placeholder :string - :suggestions :view}]} + :suggestions? :view}]} :hook (reify hooks/Hook (hook-in [_ id {:keys [description scope parameters preview short-preview on-send on-receive]} cofx] diff --git a/src/status_im/extensions/core.cljs b/src/status_im/extensions/core.cljs index 039a65ac64..9d33547a95 100644 --- a/src/status_im/extensions/core.cljs +++ b/src/status_im/extensions/core.cljs @@ -16,13 +16,14 @@ [status-im.ui.components.colors :as colors] [status-im.ui.screens.navigation :as navigation] [status-im.utils.handlers :as handlers] - [status-im.utils.fx :as fx])) + [status-im.utils.fx :as fx] + status-im.extensions.ethereum)) (re-frame/reg-fx ::alert (fn [value] (js/alert value))) -(re-frame/reg-event-fx +(handlers/register-handler-fx :alert (fn [_ [_ {:keys [value]}]] {::alert value})) @@ -31,7 +32,7 @@ ::log (fn [value] (js/console.log value))) -(re-frame/reg-event-fx +(handlers/register-handler-fx :log (fn [_ [_ {:keys [value]}]] {::log value})) @@ -148,7 +149,7 @@ 'transaction-status {:value transactions/transaction-status :properties {:outgoing :string :tx-hash :string}} 'asset-selector {:value transactions/choose-nft-asset-suggestion} 'token-selector {:value transactions/choose-nft-token-suggestion}} - :queries {'store/get {:value :store/get :arguments {:key :string}} + :queries {'store/get {:value :store/get :arguments {:key :string}} 'wallet/collectibles {:value :get-collectible-token :arguments {:token :string :symbol :string}}} :events {'alert {:permissions [:read] @@ -191,30 +192,25 @@ :arguments {:hash :string :on-success :event :on-failure? :event}} - 'ethereum/sign - {:arguments - {:account :string - :message :string - :on-result :event}} 'ethereum/send-transaction - {:arguments - {:from :string - :to :string - :gas? :string - :gas-price? :string - :value? :string - :data? :string - :nonce? :string}} + {:permissions [:read] + :value :extensions/ethereum-send-transaction + :arguments {:to :string + :gas? :string + :gas-price? :string + :value? :string + :method? :string + :params? :vector + :nonce? :string + :on-result? :event}} 'ethereum/call - {:arguments - {:from? :string - :to :string - :gas? :string - :gas-price? :string - :value? :string - :data? :string - :block :string}}} - :hooks {:commands commands/command-hook}}) + {:permissions [:read] + :value :extensions/ethereum-call + :arguments {:to :string + :method :string + :params? :vector + :on-result? :event}}} + :hooks {:commands commands/command-hook}}) (defn read-extension [{:keys [value]}] (when (seq value) diff --git a/src/status_im/extensions/ethereum.cljs b/src/status_im/extensions/ethereum.cljs new file mode 100644 index 0000000000..91daaa91eb --- /dev/null +++ b/src/status_im/extensions/ethereum.cljs @@ -0,0 +1,39 @@ +(ns status-im.extensions.ethereum + (:require [status-im.utils.handlers :as handlers] + [re-frame.core :as re-frame] + [status-im.models.wallet :as models.wallet] + [status-im.utils.ethereum.abi-spec :as abi-spec] + [status-im.utils.fx :as fx] + [status-im.ui.screens.navigation :as navigation])) + +(handlers/register-handler-fx + :extensions/transaction-on-result + (fn [cofx [_ on-result id result method]] + (fx/merge cofx + (when on-result + {:dispatch (on-result {:error nil :result result})}) + (navigation/navigate-to-clean :wallet-transaction-sent nil)))) + +(handlers/register-handler-fx + :extensions/transaction-on-error + (fn [{db :db} [_ on-result message]] + (when on-result {:dispatch (on-result {:error message :result nil})}))) + +(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 (models.wallet/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-call + (fn [_ [_ {:keys [to method params 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"]} + #(when on-result + (re-frame/dispatch (on-result {:error %1 :result (when %2 + (get (js->clj %2) "result"))})))]}))) \ No newline at end of file diff --git a/src/status_im/models/wallet.cljs b/src/status_im/models/wallet.cljs index 3f84e4b33f..07f76a830e 100644 --- a/src/status_im/models/wallet.cljs +++ b/src/status_im/models/wallet.cljs @@ -63,7 +63,7 @@ {:db (update-in db [:wallet :edit] build-edit key value)}) ;; DAPP TRANSACTION -> SEND TRANSACTION -(defn prepare-dapp-transaction [{{:keys [id method params]} :payload :as queued-transaction} contacts] +(defn prepare-dapp-transaction [{{:keys [id method params]} :payload message-id :message-id} contacts] (let [{:keys [to value data gas gasPrice nonce]} (first params) contact (get contacts (utils.hex/normalize-hex to))] (cond-> {:id (str id) @@ -72,7 +72,6 @@ contact) :symbol :ETH :method method - :dapp-transaction queued-transaction :to to :amount (money/bignumber (or value 0)) :gas (cond @@ -82,7 +81,34 @@ (money/bignumber 21000)) :gas-price (when gasPrice (money/bignumber gasPrice)) - :data data} + :data data + :on-result [:wallet.dapp/transaction-on-result message-id] + :on-error [:wallet.dapp/transaction-on-error message-id]} + nonce + (assoc :nonce nonce)))) + +;; EXTENSION TRANSACTION -> SEND TRANSACTION +(defn prepare-extension-transaction [params contacts on-result] + (let [{:keys [to value data gas gasPrice nonce]} params + contact (get contacts (utils.hex/normalize-hex to))] + (cond-> {:id "extension-id" + :to-name (or (when (nil? to) + (i18n/label :t/new-contract)) + contact) + :symbol :ETH + :method constants/web3-send-transaction + :to to + :amount (money/bignumber (or value 0)) + :gas (cond + gas + (money/bignumber gas) + (and value (empty? data)) + (money/bignumber 21000)) + :gas-price (when gasPrice + (money/bignumber gasPrice)) + :data data + :on-result [:extensions/transaction-on-result on-result] + :on-error [:extensions/transaction-on-error on-result]} nonce (assoc :nonce nonce)))) @@ -110,7 +136,7 @@ [first_param second_param] [second_param first_param])))) -(defn web3-error-callback [fx {:keys [webview-bridge]} {:keys [message-id]} message] +(defn web3-error-callback [fx {:keys [webview-bridge]} message-id message] (assoc fx :browser/send-to-bridge {:message {:type constants/web3-send-async-callback :messageId message-id :error message} @@ -131,15 +157,15 @@ (= method constants/web3-send-transaction) (assoc :dispatch [:navigate-to-clean :wallet-transaction-sent]))) -(defn discard-transaction +(fx/defn discard-transaction [{:keys [db]}] - (let [{:keys [dapp-transaction]} (get-in db [:wallet :send-transaction])] - (cond-> {:db (update db :wallet - assoc - :send-transaction {} - :transactions-queue nil)} - dapp-transaction - (web3-error-callback db dapp-transaction "discarded")))) + (let [{:keys [on-error]} (get-in db [:wallet :send-transaction])] + (merge {:db (update db :wallet + assoc + :send-transaction {} + :transactions-queue nil)} + (when on-error + {:dispatch (conj on-error "transaction was cancelled by user")})))) (defn prepare-unconfirmed-transaction [db now hash] (let [transaction (get-in db [:wallet :send-transaction])] @@ -157,7 +183,7 @@ (dissoc :message-id :id :gas))))) (defn handle-transaction-error [{:keys [db]} {:keys [code message]}] - (let [{:keys [dapp-transaction]} (get-in db [:wallet :send-transaction])] + (let [{:keys [on-error]} (get-in db [:wallet :send-transaction])] (case code ;;WRONG PASSWORD @@ -165,16 +191,16 @@ {:db (-> db (assoc-in [:wallet :send-transaction :wrong-password?] true))} - (cond-> (let [cofx {:db - (-> db - (assoc-in [:wallet :transactions-queue] nil) - (assoc-in [:wallet :send-transaction] {})) - :wallet/show-transaction-error - message}] - (navigation/navigate-back cofx)) + (merge (let [cofx {:db + (-> db + (assoc-in [:wallet :transactions-queue] nil) + (assoc-in [:wallet :send-transaction] {})) + :wallet/show-transaction-error + message}] + (navigation/navigate-back cofx)) - dapp-transaction - (web3-error-callback db dapp-transaction message))))) + (when on-error + {:dispatch (conj on-error message)}))))) (defn transform-data-for-message [{:keys [method] :as transaction}] (cond-> transaction @@ -216,3 +242,17 @@ (clear-error-message :balance-update) (assoc-in [:wallet :balance-loading?] true) (assoc :prices-loading? true))}))) + +(defn open-modal-wallet-for-transaction [db transaction tx-object] + (let [{:keys [gas gas-price]} transaction + {:keys [wallet-set-up-passed?]} (:account/account db)] + {:db (assoc-in db [:wallet :send-transaction] transaction) + :dispatch-n [[:update-wallet] + (when-not gas + [:wallet/update-estimated-gas tx-object]) + (when-not gas-price + [:wallet/update-gas-price]) + [:navigate-to + (if wallet-set-up-passed? + :wallet-send-modal-stack + :wallet-send-modal-stack-with-onboarding)]]})) diff --git a/src/status_im/ui/screens/wallet/send/db.cljs b/src/status_im/ui/screens/wallet/send/db.cljs index fd517ff9a7..f276291414 100644 --- a/src/status_im/ui/screens/wallet/send/db.cljs +++ b/src/status_im/ui/screens/wallet/send/db.cljs @@ -32,11 +32,12 @@ (spec/def ::whisper-identity (spec/nilable string?)) (spec/def ::method (spec/nilable string?)) (spec/def ::tx-hash (spec/nilable string?)) -(spec/def ::dapp-transaction (spec/nilable any?)) +(spec/def ::on-result (spec/nilable any?)) +(spec/def ::on-error (spec/nilable any?)) (spec/def :wallet/send-transaction (allowed-keys :opt-un [::amount ::to ::to-name ::amount-error ::asset-error ::amount-text ::password ::show-password-input? ::id ::from ::data ::nonce - ::camera-flashlight ::in-progress? ::dapp-transaction + ::camera-flashlight ::in-progress? ::on-result ::on-error ::wrong-password? ::from-chat? ::symbol ::advanced? ::gas ::gas-price ::whisper-identity ::method ::tx-hash])) diff --git a/src/status_im/ui/screens/wallet/send/events.cljs b/src/status_im/ui/screens/wallet/send/events.cljs index 9099e2efe6..b17db74fc5 100644 --- a/src/status_im/ui/screens/wallet/send/events.cljs +++ b/src/status_im/ui/screens/wallet/send/events.cljs @@ -83,7 +83,7 @@ (handlers/register-handler-fx ::transaction-completed (fn [{:keys [db now] :as cofx} [_ {:keys [result error]}]] - (let [{:keys [id method whisper-identity to symbol amount-text dapp-transaction]} (get-in db [:wallet :send-transaction]) + (let [{:keys [id method whisper-identity to symbol amount-text on-result]} (get-in db [:wallet :send-transaction]) db' (assoc-in db [:wallet :send-transaction :in-progress?] false)] (if error ;; ERROR @@ -96,10 +96,8 @@ (assoc-in [:wallet :transactions result] (models.wallet/prepare-unconfirmed-transaction db now result)))} - (if dapp-transaction - (let [{:keys [message-id]} dapp-transaction - webview (:webview-bridge db)] - (models.wallet/dapp-complete-transaction (int id) result method message-id webview)) + (if on-result + {:dispatch (conj on-result id result method)} {:dispatch [:send-transaction-message whisper-identity {:address to :asset (name symbol) :amount amount-text @@ -111,6 +109,17 @@ (fn [cofx _] (models.wallet/discard-transaction cofx))) +(handlers/register-handler-fx + :wallet.dapp/transaction-on-result + (fn [{db :db} [_ message-id id result method]] + (let [webview (:webview-bridge db)] + (models.wallet/dapp-complete-transaction (int id) result method message-id webview)))) + +(handlers/register-handler-fx + :wallet.dapp/transaction-on-error + (fn [{db :db} [_ message-id message]] + (models.wallet/web3-error-callback {} db message-id message))) + ;; DAPP TRANSACTIONS QUEUE ;; NOTE(andrey) We need this queue because dapp can send several transactions in a row, this is bad behaviour ;; but we need to support it @@ -126,19 +135,8 @@ ;;SEND TRANSACTION (= method constants/web3-send-transaction) - (let [{:keys [gas gas-price] :as transaction} (models.wallet/prepare-dapp-transaction - queued-transaction (:contacts/contacts db)) - {:keys [wallet-set-up-passed?]} (:account/account db)] - {:db (assoc-in db' [:wallet :send-transaction] transaction) - :dispatch-n [[:update-wallet] - (when-not gas - [:wallet/update-estimated-gas (first params)]) - (when-not gas-price - [:wallet/update-gas-price]) - [:navigate-to - (if wallet-set-up-passed? - :wallet-send-modal-stack - :wallet-send-modal-stack-with-onboarding)]]}) + (let [transaction (models.wallet/prepare-dapp-transaction queued-transaction (:contacts/contacts db))] + (models.wallet/open-modal-wallet-for-transaction db' transaction (first params))) ;;SIGN MESSAGE (= method constants/web3-personal-sign) @@ -148,7 +146,8 @@ {:id (str (or id message-id)) :from address :data data - :dapp-transaction queued-transaction + :on-result [:wallet.dapp/transaction-on-result message-id] + :on-error [:wallet.dapp/transaction-on-error message-id] :method method})] (navigation/navigate-to-cofx {:db db''} :wallet-sign-message-modal nil)) {:db db'}))))))) @@ -181,9 +180,9 @@ (handlers/register-handler-fx :wallet/discard-transaction-navigate-back (fn [cofx _] - (-> cofx - models.wallet/discard-transaction - (assoc :dispatch [:navigate-back])))) + (fx/merge cofx + (navigation/navigate-back) + (models.wallet/discard-transaction)))) (defn update-gas-price ([db edit? success-event]