Revert "[Fixes #7052 and #7037] Improved extensions ethereum support"

This reverts commit 6a8c9bf14f.

Signed-off-by: Igor Mandrigin <i@mandrigin.ru>
This commit is contained in:
Igor Mandrigin 2018-12-21 13:34:11 +01:00
parent 6a8c9bf14f
commit 794313dbee
No known key found for this signature in database
GPG Key ID: 4A0EDDE26E66BC8B
8 changed files with 302 additions and 341 deletions

View File

@ -11,7 +11,7 @@
com.taoensso/timbre {:mvn/version "4.10.0"}
hickory {:mvn/version "0.7.1"}
com.cognitect/transit-cljs {:mvn/version "0.8.248"}
status-im/pluto {:mvn/version "iteration-4-6"}
status-im/pluto {:mvn/version "iteration-4-5"}
mvxcvi/alphabase {:mvn/version "1.0.0"}
rasom/cljs-react-navigation {:mvn/version "0.1.4"}}

View File

@ -11,7 +11,7 @@
[com.taoensso/timbre "4.10.0"]
[hickory "0.7.1"]
[com.cognitect/transit-cljs "0.8.248"]
[status-im/pluto "iteration-4-6"]
[status-im/pluto "iteration-4-5"]
[mvxcvi/alphabase "1.0.0"]
[rasom/cljs-react-navigation "0.1.4"]]
:plugins [[lein-cljsbuild "1.1.7"]

View File

@ -114,17 +114,17 @@
(def command-hook
"Hook for extensions"
{:properties
{:description? :string
:scope #{:personal-chats :public-chats :group-chats}
:short-preview? :view
:preview? :view
:on-send? :event
:on-receive? :event
:on-send-sync? :event
:parameters? [{:id :keyword
:type {:one-of #{:text :phone :password :number}}
:placeholder :string
:suggestions? :view}]}
{:description? :string
:scope #{:personal-chats :public-chats}
:short-preview :view
:preview :view
:on-send? :event
:on-receive? :event
:on-send-sync? :event
:parameters? [{:id :keyword
:type {:one-of #{:text :phone :password :number}}
:placeholder :string
:suggestions? :view}]}
:hook
(reify hooks/Hook
(hook-in [_ id {extension-id :id} {:keys [description scope parameters preview short-preview
@ -138,8 +138,8 @@
(validate [_ _ _])
(on-send [_ command-message _] (when on-send {:dispatch (on-send command-message)}))
(on-receive [_ command-message _] (when on-receive {:dispatch (on-receive command-message)}))
(short-preview [_ props] (when short-preview (short-preview props)))
(preview [_ props] (when preview (preview props)))
(short-preview [_ props] (short-preview props))
(preview [_ props] (preview props))
protocol/Yielding
(yield-control [_ props _] {:dispatch (on-send-sync props)})
protocol/Extension
@ -152,8 +152,8 @@
(validate [_ _ _])
(on-send [_ command-message _] (when on-send {:dispatch (on-send command-message)}))
(on-receive [_ command-message _] (when on-receive {:dispatch (on-receive command-message)}))
(short-preview [_ props] (when short-preview (short-preview props)))
(preview [_ props] (when preview (preview props)))
(short-preview [_ props] (short-preview props))
(preview [_ props] (preview props))
protocol/Extension
(extension-id [_] extension-id)))]
(load-commands cofx [new-command])))

View File

@ -8,7 +8,6 @@
[status-im.chat.commands.impl.transactions :as transactions]
[status-im.ui.components.button.view :as button]
[status-im.ui.components.checkbox.view :as checkbox]
[status-im.ui.components.icons.vector-icons :as icons]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.react :as react]
[status-im.ui.screens.wallet.settings.views :as settings]
@ -22,7 +21,8 @@
status-im.extensions.ethereum
[status-im.utils.ethereum.tokens :as tokens]
[status-im.utils.ethereum.core :as ethereum]
[status-im.chat.commands.sending :as commands-sending]))
[status-im.chat.commands.sending :as commands-sending]
[status-im.ui.components.icons.vector-icons :as icons]))
(re-frame/reg-fx
::identity-event
@ -90,7 +90,7 @@
:<- [:balance]
(fn [[all-tokens network balance] [_ _ {token :token}]]
(let [{:keys [decimals]} (get-token-for network all-tokens token)
value (or (get balance (keyword token)) (money/bignumber 0))]
value (get balance (keyword token))]
{:value (money/token->unit value decimals)
:value-in-wei value})))
@ -98,26 +98,20 @@
:extensions.wallet/token
:<- [:wallet/all-tokens]
:<- [:network]
(fn [[all-tokens network] [_ _ {token :token amount :amount amount-in-wei :amount-in-wei}]]
(fn [[all-tokens network] [_ _ {token :token amount :amount}]]
(let [{:keys [decimals] :as m} (get-token-for network all-tokens token)]
(merge m
(when amount {:amount-in-wei (money/unit->token amount decimals)})
(when amount-in-wei {:amount (money/token->unit amount-in-wei decimals)})))))
(defn normalize-token [m]
(update m :symbol name))
(when amount {:amount (money/unit->token amount decimals)})))))
(re-frame/reg-sub
:extensions.wallet/tokens
:<- [:wallet/all-tokens]
:<- [:wallet/visible-tokens-symbols]
:<- [:network]
(fn [[all-tokens visible-tokens-symbols network] [_ _ {filter-vector :filter visible :visible}]]
(let [tokens (map normalize-token (filter #(and (not (:nft? %)) (if visible (contains? visible-tokens-symbols (:symbol %)) true))
(tokens/sorted-tokens-for all-tokens (ethereum/network->chain-keyword network))))]
(if filter-vector
(filter #((set filter-vector) (:symbol %)) tokens)
tokens))))
(fn [[all-tokens network] [_ _ {filter-vector :filter}]]
(let [tokens (tokens/sorted-tokens-for all-tokens (ethereum/network->chain-keyword network))]
(if (= :all (first filter-vector))
tokens
(filter #((set filter-vector) (:symbol %)) tokens)))))
(re-frame/reg-sub
:store/get
@ -366,57 +360,43 @@
(defn picker [{:keys [style on-change selected enabled data]}]
[react/picker {:style style :on-change #(re-frame/dispatch (on-change {:value %})) :selected selected :enabled enabled :data data}])
(defn- wrap-text-child [o]
(if (ifn? o) o (str o)))
(defn text [o & children]
(if (map? o)
(into [react/text o] (map wrap-text-child children))
(into [react/text {} o] (map wrap-text-child children))))
[react/text o children]
(into [react/text {} o] children)))
(defn- wrap-view-child [child]
(if (vector? child) child [text {} child]))
(defn abstract-view [type o & children]
(if (map? o)
(into [type o] (map wrap-view-child children))
(into [type {} (wrap-view-child o)] (map wrap-view-child children))))
(defn view [o & children]
(apply abstract-view react/view o children))
(if (map? o)
(into [react/view o] (map wrap-view-child children))
(into [react/view {} (wrap-view-child o)] (map wrap-view-child children))))
(defn scroll-view [o & children]
(apply abstract-view react/scroll-view o children))
(defn keyboard-avoiding-view [o & children]
(apply abstract-view react/keyboard-avoiding-view o children))
(defn icon [{:keys [key] :as o}]
[icons/icon key o])
(defn icon [o]
[icons/icon (:key o) o])
(def capacities
{:components {'view {:value view}
'scroll-view {:value scroll-view}
'keyboard-avoiding-view {:value react/keyboard-avoiding-view}
'text {:value text}
'touchable-opacity {:value touchable-opacity :properties {:on-press :event}}
'icon {:value icon :properties {:key :keyword :color :any}}
'image {:value image :properties {:uri :string :source :string}}
'input {:value input :properties {:on-change :event :placeholder :string :keyboard-type :keyword :change-delay? :number :placeholder-text-color :any}}
'button {:value button :properties {:enabled :boolean :disabled :boolean :on-click :event}}
'link {:value link :properties {:uri :string}}
'list {:value list :properties {:data :vector :item-view :view :key? :keyword}}
'checkbox {:value checkbox :properties {:on-change :event :checked :boolean}}
'activity-indicator {:value activity-indicator :properties {:animating :boolean :color :string :size :keyword :hides-when-stopped :boolean}}
'picker {:value picker :properties {:on-change :event :selected :string :enabled :boolean :data :vector}}
'nft-token-viewer {:value transactions/nft-token :properties {:token :string}}
'transaction-status {:value transactions/transaction-status :properties {:outgoing :string :tx-hash :string}}}
{:components {'view {:value view}
'text {:value text}
'touchable-opacity {:value touchable-opacity :properties {:on-press :event}}
'icon {:value icon :properties {:key :keyword :color :any}}
'image {:value image :properties {:uri :string :source :numeric}}
'input {:value input :properties {:on-change :event :change-delay :number :placeholder :string :keyboard-type :keyword :placeholder-text-color :any}}
'button {:value button :properties {:enabled :boolean :disabled :boolean :on-click :event}}
'link {:value link :properties {:uri :string}}
'list {:value list :properties {:data :vector :item-view :view :key? :keyword}}
'checkbox {:value checkbox :properties {:on-change :event :checked :boolean}}
'activity-indicator {:value activity-indicator :properties {:animating :boolean :color :string :size :keyword :hides-when-stopped :boolean}}
'picker {:value picker :properties {:on-change :event :selected :string :enabled :boolean :data :vector}}
'nft-token-viewer {:value transactions/nft-token :properties {:token :string}}
'transaction-status {:value transactions/transaction-status :properties {:outgoing :string :tx-hash :string}}}
:queries {'identity {:value :extensions/identity :arguments {:value :map}}
'store/get {:value :store/get :arguments {:key :string}}
'wallet/collectibles {:value :get-collectible-token :arguments {:token :string :symbol :string}}
'wallet/balance {:value :extensions.wallet/balance :arguments {:token :string}}
'wallet/token {:value :extensions.wallet/token :arguments {:token :string :amount? :number :amount-in-wei? :number}}
'wallet/tokens {:value :extensions.wallet/tokens :arguments {:filter? :vector :visible? :boolean}}}
'wallet/token {:value :extensions.wallet/token :arguments {:token :string :amount? :numeric}}
'wallet/tokens {:value :extensions.wallet/tokens :arguments {:filter :vector}}}
:events {'identity
{:permissions [:read]
:value :extensions/identity-event
@ -457,7 +437,7 @@
{:permissions [:read]
:value :extensions/arithmetic
:arguments {:values :vector
:operation {:one-of #{:plus :minus :times :divide}}
:operation :keyword
:on-result :event}}
'schedule/start
{:permissions [:read]
@ -525,158 +505,140 @@
'ethereum/transaction-receipt
{:permissions [:read]
:value :extensions/ethereum-transaction-receipt
:arguments {:value :string
:on-success :event
:on-failure? :event}}
:arguments {:value :string
:on-result :event}}
'ethereum/sign
{:permissions [:read]
:value :extensions/ethereum-sign
:arguments {:message? :string
:data? :string
:on-success :event
:on-failure? :event}}
:arguments {:message? :string
:data? :string
:on-result :event}}
'ethereum/send-transaction
{:permissions [:read]
:value :extensions/ethereum-send-transaction
:arguments {:to :string
:gas? :string
:gas-price? :string
:value? :string
:method? :string
:params? :vector
:nonce? :string
:on-success :event
:on-failure? :event}}
:arguments {:to :string
:gas? :string
:gas-price? :string
:value? :string
:method? :string
:params? :vector
:nonce? :string
:on-result :event}}
'ethereum/logs
{:permissions [:read]
:value :extensions/ethereum-logs
:arguments {:from? :string
:to? :string
:address? :vector
:topics? :vector
:block-hash? :string
:on-success :event
:on-failure? :event}}
:arguments {:fromBlock? :string
:toBlock? :string
:address? :vector
:topics? :vector
:blockhash? :string
:on-result :event}}
'ethereum/resolve-ens
{:permissions [:read]
:value :extensions/ethereum-resolve-ens
:arguments {:name :string
:on-result :event}}
'ethereum/create-filter
{:permissions [:read]
:value :extensions/ethereum-create-filter
:arguments {:type {:one-of #{:filter :block :pending-transaction}}
:from? :string
:to? :string
:address? :vector
:topics? :vector
:arguments {:filter-type :string
:from? :string
:to? :string
:address? :vector
:topics? :vector
:block-hash? :string
:on-success :event
:on-failure? :event}}
:on-result :event}}
'ethereum/logs-changes
{:permissions [:read]
:value :extensions/ethereum-logs-changes
:arguments {:id :string}}
:arguments {:id :string}}
'ethereum/cancel-filter
{:permissions [:read]
:value :extensions/ethereum-cancel-filter
:arguments {:id :string}}
'ethereum.ens/resolve
{:permissions [:read]
:value :extensions/ethereum-resolve-ens
:arguments {:name :string
:on-success :event
:on-failure? :event}}
'ethereum.erc20/total-supply
{:permissions [:read]
:value :extensions/ethereum-erc20-total-supply
:arguments {:contract :string
:on-success :event
:on-failure? :event}}
:on-result :event}}
'ethereum.erc20/balance-of
{:permissions [:read]
:value :extensions/ethereum-erc20-balance-of
:arguments {:contract :string
:token-owner :string
:on-success :event
:on-failure? :event}}
:on-result :event}}
'ethereum.erc20/transfer
{:permissions [:read]
:value :extensions/ethereum-erc20-transfer
:arguments {:contract :string
:to :string
:value :number
:on-success :event
:on-failure? :event}}
:arguments {:contract :string
:to :string
:value :number
:on-result :event}}
'ethereum.erc20/transfer-from
{:permissions [:read]
:value :extensions/ethereum-erc20-transfer-from
:arguments {:contract :string
:from :string
:to :string
:value :number
:on-success :event
:on-failure? :event}}
:arguments {:contract :string
:from :string
:to :string
:value :number
:on-result :event}}
'ethereum.erc20/approve
{:permissions [:read]
:value :extensions/ethereum-erc20-approve
:arguments {:contract :string
:spender :string
:value :number
:on-success :event
:on-failure? :event}}
:on-result :event}}
'ethereum.erc20/allowance
{:permissions [:read]
:value :extensions/ethereum-erc20-allowance
:arguments {:contract :string
:token-owner :string
:spender :string
:on-success :event
:on-failure? :event}}
:on-result :event}}
'ethereum.erc721/owner-of
{:permissions [:read]
:value :extensions/ethereum-erc721-owner-of
:arguments {:contract :string
:token-id :string
:on-success :event
:on-failure? :event}}
:on-result :event}}
'ethereum.erc721/is-approved-for-all
{:permissions [:read]
:value :extensions/ethereum-erc721-is-approved-for-all
:arguments {:contract :string
:owner :string
:operator :string
:on-success :event
:on-failure? :event}}
:arguments {:contract :string
:owner :string
:operator :string
:on-result :event}}
'ethereum.erc721/get-approved
{:permissions [:read]
:value :extensions/ethereum-erc721-get-approved
:arguments {:contract :string
:token-id :string
:on-success :event
:on-failure? :event}}
:arguments {:contract :string
:token-id :string
:on-result :event}}
'ethereum.erc721/set-approval-for-all
{:permissions [:read]
:value :extensions/ethereum-erc721-set-approval-for-all
:arguments {:contract :string
:operator :string
:approved :boolean
:on-success :event
:on-failure? :event}}
:arguments {:contract :string
:operator :string
:approved :boolean
:on-result :event}}
'ethereum.erc721/safe-transfer-from
{:permissions [:read]
:value :extensions/ethereum-erc721-safe-transfer-from
:arguments {:contract :string
:from :string
:to :string
:token-id :string
:data? :string
:on-success :event
:on-failure? :event}}
:arguments {:contract :string
:from :string
:to :string
:token-id :string
:data? :string
:on-result :event}}
'ethereum/call
{:permissions [:read]
:value :extensions/ethereum-call
:arguments {:to :string
:method :string
:params? :vector
:outputs? :vector
:on-success :event
:on-failure? :event}}}
:arguments {:to :string
:method :string
:params? :vector
:outputs? :vector
:on-result :event}}}
:hooks {:chat.command commands/command-hook
:wallet.settings settings/hook}})

View File

@ -17,20 +17,23 @@
[status-im.native-module.core :as status]))
(handlers/register-handler-fx
:extensions/wallet-ui-on-success
(fn [cofx [_ on-success _ result _]]
:extensions/wallet-ui-on-result
(fn [cofx [_ on-result id result method]]
(fx/merge cofx
{:dispatch (on-success {:value result})}
(navigation/navigate-back))))
(when on-result
{:dispatch (on-result {:error nil :result result})})
(cond
(= method constants/web3-send-transaction) (navigation/navigate-to-clean :wallet-transaction-sent nil)
(= method constants/web3-personal-sign) (navigation/navigate-back)))))
(handlers/register-handler-fx
:extensions/wallet-ui-on-failure
(fn [_ [_ on-failure message]]
(when on-failure {:dispatch (on-failure {:value message})})))
:extensions/wallet-ui-on-error
(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]
"function responsible to resolve ens taken from argument
and call the specified function with resolved address"
"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)
@ -43,7 +46,8 @@
(ens/get-addr web3 registry first-address #(f db (assoc arguments address-keyword %))))
(f db arguments))))
(defn prepare-extension-transaction [params contacts on-success on-failure]
;; EXTENSION TRANSACTION -> SEND TRANSACTION
(defn prepare-extension-transaction [params contacts on-result]
(let [{:keys [to value data gas gasPrice nonce]} params
contact (get contacts (hex/normalize-hex to))]
(cond-> {:id "extension-id"
@ -62,15 +66,15 @@
:gas-price (when gasPrice
(money/bignumber gasPrice))
:data data
:on-result [:extensions/wallet-ui-on-success on-success]
:on-error [:extensions/wallet-ui-on-failure on-failure]}
:on-result [:extensions/wallet-ui-on-result on-result]
:on-error [:extensions/wallet-ui-on-error on-result]}
nonce
(assoc :nonce nonce))))
(defn- execute-send-transaction [db {:keys [method params on-success on-failure] :as arguments}]
(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-success on-failure)]
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
@ -78,173 +82,143 @@
(fn [{db :db} [_ _ arguments]]
(wrap-with-resolution db arguments :to execute-send-transaction)))
(defn- rpc-args [method params]
{:jsonrpc "2.0"
:method method
:params params})
(defn- rpc-dispatch [error result f on-success on-failure]
(when result
(re-frame/dispatch (on-success {:result (f result)})))
(when (and error on-failure)
(re-frame/dispatch (on-failure {:result error}))))
(defn- rpc-handler [o f on-success on-failure]
(let [{:keys [error result]} (types/json->clj o)]
(rpc-dispatch error result f on-success on-failure)))
(defn- rpc-call [method params f {:keys [on-success on-failure]}]
(let [payload (types/clj->json (rpc-args method params))]
(status/call-private-rpc payload #(rpc-handler % f on-success on-failure))))
(defn parse-call-result [o outputs]
(let [result (get (js->clj o) "result")]
(cond
(= "0x" result) nil
(and outputs result)
(abi-spec/decode (string/replace result #"^0x" "") outputs)
:else result)))
(defn- execute-ethcall [_ {:keys [to method params outputs on-success on-failure]}]
(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 [(rpc-args "eth_call" [tx-object "latest"])
#(rpc-dispatch %1 %2 (fn [o] (parse-call-result o outputs)) on-success on-failure)]}))
{: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 [{db :db} [_ _ arguments]]
(fn [{db :db} [_ _ {:keys [to] :as arguments}]]
(wrap-with-resolution db arguments :to execute-ethcall)))
(handlers/register-handler-fx
:extensions/ethereum-erc20-total-supply
(fn [{db :db} [_ _ {:keys [contract on-success on-failure]}]]
(fn [{db :db} [_ _ {:keys [contract on-result]}]]
(let [json-rpc-args {:to contract
:method "totalSupply()"
:outputs ["uint256"]
:on-success on-success
:on-failure on-failure}]
:method "totalSupply()"
:outputs ["uint256"]
:on-result on-result}]
(wrap-with-resolution db json-rpc-args :to execute-ethcall))))
(handlers/register-handler-fx
:extensions/ethereum-erc20-balance-of
(fn [{db :db} [_ _ {:keys [contract token-owner on-success on-failure]}]]
(fn [{db :db} [_ _ {:keys [contract token-owner on-result]}]]
(let [json-rpc-args {:to contract
:method "balanceOf(address)"
:params [token-owner]
:outputs ["uint256"]
:on-success on-success
:on-failure on-failure}]
:method "balanceOf(address)"
:params [token-owner]
:outputs ["uint256"]
:on-result on-result}]
(wrap-with-resolution db json-rpc-args :to execute-ethcall))))
(handlers/register-handler-fx
:extensions/ethereum-erc20-allowance
(fn [{db :db} [_ _ {:keys [contract token-owner spender on-success on-failure]}]]
(fn [{db :db} [_ _ {:keys [contract token-owner spender on-result]}]]
(let [json-rpc-args {:to contract
:method "allowance(address,address)"
:params [token-owner spender]
:outputs ["uint256"]
:on-success on-success
:on-failure on-failure}]
:method "allowance(address,address)"
:params [token-owner spender]
:outputs ["uint256"]
:on-result on-result}]
(wrap-with-resolution db json-rpc-args :to execute-ethcall))))
(handlers/register-handler-fx
:extensions/ethereum-erc20-transfer
(fn [{db :db} [_ _ {:keys [contract to value on-success on-failure]}]]
(fn [{db :db} [_ _ {:keys [contract to value on-result]}]]
(let [json-rpc-args {:to contract
:method "transfer(address,uint256)"
:params [to value]
:on-success on-success
:on-failure on-failure}]
:method "transfer(address,uint256)"
:params [to value]
:on-result on-result}]
(wrap-with-resolution db json-rpc-args :to execute-send-transaction))))
(handlers/register-handler-fx
:extensions/ethereum-erc20-transfer-from
(fn [{db :db} [_ _ {:keys [contract from to value on-success on-failure]}]]
(fn [{db :db} [_ _ {:keys [contract from to value on-result]}]]
(let [json-rpc-args {:to contract
:method "transferFrom(address,address,uint256)"
:params [from to value]
:on-success on-success
:on-failure on-failure}]
:method "transferFrom(address,address,uint256)"
:params [from to value]
:on-result on-result}]
(wrap-with-resolution db json-rpc-args :to execute-send-transaction))))
(handlers/register-handler-fx
:extensions/ethereum-erc20-approve
(fn [{db :db} [_ _ {:keys [contract spender value on-success on-failure]}]]
(fn [{db :db} [_ _ {:keys [contract spender value on-result]}]]
(let [json-rpc-args {:to contract
:method "approve(address,uint256)"
:params [spender value]
:on-success on-success
:on-failure on-failure}]
:method "approve(address,uint256)"
:params [spender value]
:on-result on-result}]
(wrap-with-resolution db json-rpc-args :to execute-send-transaction))))
(handlers/register-handler-fx
:extensions/ethereum-erc721-owner-of
(fn [{db :db} [_ _ {:keys [contract token-id on-success on-failure]}]]
(fn [{db :db} [_ _ {:keys [contract token-id on-result]}]]
(let [json-rpc-args {:to contract
:method "ownerOf(uint256)"
:params [token-id]
:outputs ["address"]
:on-success on-success
:on-failure on-failure}]
:method "ownerOf(uint256)"
:params [token-id]
:outputs ["address"]
:on-result on-result}]
(wrap-with-resolution db json-rpc-args :to execute-ethcall))))
(handlers/register-handler-fx
:extensions/ethereum-erc721-is-approved-for-all
(fn [{db :db} [_ _ {:keys [contract owner operator on-success on-failure]}]]
(fn [{db :db} [_ _ {:keys [contract owner operator on-result]}]]
(let [json-rpc-args {:to contract
:method "isApprovedForAll(address,address)"
:params [owner operator]
:outputs ["bool"]
:on-success on-success
:on-failure on-failure}]
:method "isApprovedForAll(address,address)"
:params [owner operator]
:outputs ["bool"]
:on-result on-result}]
(wrap-with-resolution db json-rpc-args :to execute-ethcall))))
(handlers/register-handler-fx
:extensions/ethereum-erc721-get-approved
(fn [{db :db} [_ _ {:keys [contract token-id on-success on-failure]}]]
(fn [{db :db} [_ _ {:keys [contract token-id on-result]}]]
(let [json-rpc-args {:to contract
:method "getApproved(uint256)"
:params [token-id]
:outputs ["address"]
:on-success on-success
:on-failure on-failure}]
:method "getApproved(uint256)"
:params [token-id]
:outputs ["address"]
:on-result on-result}]
(wrap-with-resolution db json-rpc-args :to execute-ethcall))))
(handlers/register-handler-fx
:extensions/ethereum-erc721-set-approval-for-all
(fn [{db :db} [_ _ {:keys [contract to approved on-success on-failure]}]]
(fn [{db :db} [_ _ {:keys [contract to approved on-result]}]]
(let [json-rpc-args {:to contract
:method "setApprovalForAll(address,bool)"
:params [to approved]
:on-success on-success
:on-failure on-failure}]
:method "setApprovalForAll(address,bool)"
:params [to approved]
:on-result on-result}]
(wrap-with-resolution db json-rpc-args :to execute-send-transaction))))
(handlers/register-handler-fx
:extensions/ethereum-erc721-safe-transfer-from
(fn [{db :db} [_ _ {:keys [contract from to token-id data on-success on-failure]}]]
(fn [{db :db} [_ _ {:keys [contract from to token-id data on-result]}]]
(let [json-rpc-args {:to contract
:method (if data
"safeTransferFrom(address,address,uint256,bytes)"
"safeTransferFrom(address,address,uint256)")
:params (if data
[from to token-id data]
[from to token-id])
:on-success on-success
:on-failure on-failure}]
:method (if data
"safeTransferFrom(address,address,uint256,bytes)"
"safeTransferFrom(address,address,uint256)")
:params (if data
[from to token-id data]
[from to token-id])
:on-result on-result}]
(wrap-with-resolution db json-rpc-args :to execute-send-transaction))))
(defn- parse-log [{:keys [address transactionHash blockHash transactionIndex topics blockNumber logIndex removed data]}]
(merge {:data data
:topics topics
:address address
:removed removed}
;; TODO parse data and topics, filter useless solidity first topic, aggregate as events ?
(when logIndex {:log-index (abi-spec/hex-to-number logIndex)})
(when transactionIndex {:transaction-index (abi-spec/hex-to-number transactionIndex)})
(when transactionHash {:transaction-hash transactionHash})
(when blockHash {:block-hash blockHash})
(when blockNumber {:block-number (abi-spec/hex-to-number blockNumber)})))
{:address address
:transaction-hash transactionHash
:blockHash blockHash
:transaction-index (abi-spec/hex-to-number transactionIndex)
:topics topics ;; TODO parse topics
:block-number (abi-spec/hex-to-number blockNumber)
:log-index (abi-spec/hex-to-number logIndex)
:removed removed
:data data})
(defn- parse-receipt [m]
(when m
@ -264,8 +238,16 @@
(handlers/register-handler-fx
:extensions/ethereum-transaction-receipt
(fn [_ [_ _ {:keys [value] :as m}]]
(rpc-call constants/web3-transaction-receipt [value] parse-receipt m)))
(fn [_ [_ _ {:keys [value on-result]}]]
(let [args {:jsonrpc "2.0"
:method constants/web3-transaction-receipt
:params [value]}
payload (types/clj->json args)]
(status/call-private-rpc payload #(let [{:keys [error result]} (types/json->clj %1)
response (merge {:result (parse-receipt result)} (when error {:error error}))]
(re-frame/dispatch (on-result response)))))))
;; eth_getLogs implementation
(defn- event-topic-enc [event params]
(let [eventid (str event "(" (string/join "," params) ")")]
@ -282,16 +264,17 @@
:else :bytes))
(defn- values-topic-enc [type values]
(mapv #(str "0x" (abi-spec/enc {:type (types-mapping type) :value %})) values))
(let [mapped-type (types-mapping type)]
(mapv #(str "0x" (abi-spec/enc {:type mapped-type :value %})) values)))
(defn- generate-topic [t]
(defn- parse-topic [t]
(cond
(or (nil? t) (string? t)) t ;; nil topic ;; immediate topic (extension encode topic by its own) ;; vector of immediate topics
(vector? t) (mapv generate-topic t) ;; descend in vector elements
(vector? t) (mapv parse-topic t) ;; descend in vector elements
(map? t) ;; simplified topic interface, we need to encode
(let [{:keys [event params type values]} t]
(cond
(some? event) (event-topic-enc event params);; event params topic {:event "Transfer" :params ["uint"]}
(some? event) (event-topic-enc event params);; event params topic
(some? type) (values-topic-enc type values) ;; indexed values topic
:else nil)) ;; error
:else nil))
@ -302,13 +285,19 @@
(re-matches #"^[0-9]+$" block) (str "0x" (abi-spec/number-to-hex block))
:else block))
(defn- execute-get-logs [_ {:keys [from to address topics block-hash] :as m}]
(let [params [{:from (ensure-hex-bn from)
:to (ensure-hex-bn to)
:address address
:topics (generate-topic topics)
:blockhash block-hash}]]
(rpc-call constants/web3-get-logs params #(map parse-log %) m)))
(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
@ -317,59 +306,71 @@
(handlers/register-handler-fx
:extensions/ethereum-resolve-ens
(fn [{db :db} [_ _ {:keys [name on-success on-failure]}]]
(fn [{db :db} [_ _ {:keys [name on-result]}]]
(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-success {:value %}))))
(when on-failure
(re-frame/dispatch (on-failure {:value (str "'" name "' is not a valid name")}))))))
(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")})))))
;; EXTENSION SIGN -> SIGN MESSAGE
(handlers/register-handler-fx
:extensions/ethereum-sign
(fn [{db :db :as cofx} [_ _ {:keys [message data id on-success on-failure]}]]
(if (and message data)
(when on-failure
{:dispatch (on-failure {:error "only one of :message and :data can be used"})})
(fn [{db :db :as cofx} [_ _ {:keys [message data id on-result]}]]
(if (= (nil? message) (nil? data))
{:dispatch (on-result {:error "only one of :message and :data can be used"})}
(fx/merge cofx
{:db (assoc-in db [:wallet :send-transaction]
{:id id
:from (ethereum/normalized-address (get-in db [:account/account :address]))
:from (ethereum/normalized-address (get-in db [:account/account :address]))
:data (or data (str "0x" (abi-spec/from-utf8 message)))
:on-result [:extensions/wallet-ui-on-success on-success]
:on-error [:extensions/wallet-ui-on-failure on-failure]
:on-result [:extensions/wallet-ui-on-result on-result]
:on-error [:extensions/wallet-ui-on-error on-result]
:method constants/web3-personal-sign})}
(navigation/navigate-to-cofx :wallet-sign-message-modal nil)))))
;; poll logs implementation
(handlers/register-handler-fx
:extensions/ethereum-logs-changes
(fn [_ [_ _ {:keys [id] :as m}]]
(rpc-call constants/web3-get-filter-changes [(abi-spec/number-to-hex id)] #(map parse-log %) m)))
(fn [_ [_ _ {:keys [filterId on-result]}]]
(let [args {:jsonrpc "2.0"
:method constants/web3-get-filter-changes
:params [filterId]}
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}))]
(mapv (fn [one-result]
(re-frame/dispatch (on-result one-result))) result))))))
(handlers/register-handler-fx
:extensions/ethereum-cancel-filter
(fn [_ [_ _ {:keys [id] :as m}]]
(rpc-call constants/web3-uninstall-filter [(abi-spec/number-to-hex id)] #(abi-spec/hex-to-value % "bool") m)))
(defn create-filter-method [type]
(case type
:filter constants/web3-new-filter
:block constants/web3-new-block-filter
:pending-transaction constants/web3-new-pending-transaction-filter))
(defn create-filter-arguments [type {:keys [from to address block-hash topics]}]
(case type
:filter
[{:fromBlock (ensure-hex-bn from)
:toBlock (ensure-hex-bn to)
:address address
:topics (mapv generate-topic topics)
:blockhash block-hash}]))
(fn [_ [_ _ {:keys [filterId on-result]}]]
(let [args {:jsonrpc "2.0"
:method constants/web3-uninstall-filter
:params [filterId]}
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-create-filter
(fn [_ [_ _ {:keys [type] :as m}]]
(rpc-call (create-filter-method type) (create-filter-arguments type m) abi-spec/hex-to-number m)))
(fn [_ [_ _ {:keys [filter-type from to address topics block-hash on-result]}]]
(let [parsed-topics (mapv parse-topic topics)
args (case filter-type
"filter" {:jsonrpc "2.0"
:method constants/web3-new-filter
:params [{:fromBlock (ensure-hex-bn from)
:toBlock (ensure-hex-bn to)
:address address
:topics parsed-topics
:blockhash block-hash}]}
"block" {:jsonrpc "2.0"
:method constants/web3-new-block-filter}
"pendingTransaction" {:jsonrpc "2.0"
:method constants/web3-new-pending-transaction-filter})
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)))))))

View File

@ -15,9 +15,8 @@
hooks (get-in account [:extensions extension-id :hooks])]
(apply fx/merge cofx
(mapcat (fn [[_ extension-hooks]]
(map (fn [[hook-id {parsed :parsed {hook :hook} :hook-ref}]]
(when hook
(partial hook-fn hook hook-id {:id extension-id} parsed)))
(map (fn [[hook-id {:keys [hook-ref parsed]}]]
(partial hook-fn (:hook hook-ref) hook-id {:id extension-id} parsed))
extension-hooks))
hooks))))

View File

@ -18,12 +18,13 @@
"Hook for extensions"
{:properties
{:label :string
:view :view}
:view :view
:on-click? :event}
:hook
(reify hooks/Hook
(hook-in [_ id _ {:keys [label view _]} {:keys [db]}]
{:db (assoc-in db [:wallet :settings id] {:label label :view view})})
(unhook [_ id _ _ {:keys [db]}]
(hook-in [_ id env {:keys [label view on-click]} {:keys [db]}]
{:db (assoc-in db [:wallet :settings id] {:label label :view view :on-click on-click})})
(unhook [_ id env _ {:keys [db]}]
{:db (update-in db [:wallet :settings] dissoc id)}))})
(defn- render-token [{:keys [symbol name icon]} visible-tokens]
@ -56,8 +57,7 @@
:render-fn #(render-token % visible-tokens)}]]]))
(defview settings-hook []
(letsubs [{:keys [label view]} [:get-screen-params :wallet-settings-hook]
{address :address} [:account/account]]
(letsubs [{:keys [label view]} [:get-screen-params :wallet-settings-hook]]
[react/view {:style {:flex 1 :background-color colors/white}}
[status-bar/status-bar {:type :modal-wallet}]
[toolbar/toolbar {:style wallet.styles/toolbar}
@ -65,11 +65,14 @@
(re-frame/dispatch [:navigate-back])))]
[toolbar/content-title {:color colors/white}
label]]
[view {:address (ethereum/normalized-address address)}]]))
[view]]))
(defn- setting->action [{:keys [label] :as m}]
(defn- setting->action [{:keys [label on-click] :as m}]
{:label label
:action #(re-frame/dispatch [:navigate-to :wallet-settings-hook m])})
:action #(do
(when on-click
(re-frame/dispatch (on-click {})))
(re-frame/dispatch [:navigate-to :wallet-settings-hook m]))})
(defview toolbar-view []
(letsubs [settings [:wallet/settings]]

View File

@ -22,20 +22,16 @@
(.leftPad utils x (+ len to-pad)))))
(defn to-two-complement [x]
(when x
(subs (.toTwosComplement utils x) 2)))
(subs (.toTwosComplement utils x) 2))
(defn from-utf8 [x]
(when x
(subs (.fromUtf8 utils x) 2)))
(subs (.fromUtf8 utils x) 2))
(defn bytes-to-hex [x]
(when x
(subs (.bytesToHex utils x) 2)))
(subs (.bytesToHex utils x) 2))
(defn number-to-hex [x]
(when x
(subs (.numberToHex utils x) 2)))
(subs (.numberToHex utils x) 2))
(defn hex-to-utf8 [x]
(.hexToUtf8 utils (str "0x" x)))