Reintroduced broken PR #7092 with fix

Signed-off-by: Igor Mandrigin <i@mandrigin.ru>
This commit is contained in:
Julien Eluard 2018-12-21 14:11:16 +01:00 committed by Igor Mandrigin
parent dfbc0eb435
commit 5db9aa9ac7
No known key found for this signature in database
GPG Key ID: 4A0EDDE26E66BC8B
9 changed files with 350 additions and 311 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-5"}
status-im/pluto {:mvn/version "iteration-4-6"}
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-5"]
[status-im/pluto "iteration-4-6"]
[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}
: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 :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}]}
: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] (short-preview props))
(preview [_ props] (preview props))
(short-preview [_ props] (when short-preview (short-preview props)))
(preview [_ props] (when preview (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] (short-preview props))
(preview [_ props] (preview props))
(short-preview [_ props] (when short-preview (short-preview props)))
(preview [_ props] (when preview (preview props)))
protocol/Extension
(extension-id [_] extension-id)))]
(load-commands cofx [new-command])))

View File

@ -8,6 +8,7 @@
[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]
@ -21,8 +22,7 @@
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.ui.components.icons.vector-icons :as icons]))
[status-im.chat.commands.sending :as commands-sending]))
(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 (get balance (keyword token))]
value (or (get balance (keyword token)) (money/bignumber 0))]
{:value (money/token->unit value decimals)
:value-in-wei value})))
@ -98,20 +98,26 @@
:extensions.wallet/token
:<- [:wallet/all-tokens]
:<- [:network]
(fn [[all-tokens network] [_ _ {token :token amount :amount}]]
(fn [[all-tokens network] [_ _ {token :token amount :amount amount-in-wei :amount-in-wei}]]
(let [{:keys [decimals] :as m} (get-token-for network all-tokens token)]
(merge m
(when amount {:amount (money/unit->token amount decimals)})))))
(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))
(re-frame/reg-sub
:extensions.wallet/tokens
:<- [:wallet/all-tokens]
:<- [:wallet/visible-tokens-symbols]
:<- [:network]
(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)))))
(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))))
(re-frame/reg-sub
:store/get
@ -360,43 +366,57 @@
(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)
[react/text o children]
(into [react/text {} o] children)))
(into [react/text o] (map wrap-text-child children))
(into [react/text {} o] (map wrap-text-child children))))
(defn- wrap-view-child [child]
(if (vector? child) child [text {} child]))
(defn view [o & children]
(defn abstract-view [type 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))))
(into [type o] (map wrap-view-child children))
(into [type {} (wrap-view-child o)] (map wrap-view-child children))))
(defn icon [o]
[icons/icon (:key o) o])
(defn view [o & children]
(apply abstract-view react/view o 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])
(def capacities
{: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}}}
{: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}}}
: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? :numeric}}
'wallet/tokens {:value :extensions.wallet/tokens :arguments {:filter :vector}}}
'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}}}
:events {'identity
{:permissions [:read]
:value :extensions/identity-event
@ -437,7 +457,7 @@
{:permissions [:read]
:value :extensions/arithmetic
:arguments {:values :vector
:operation :keyword
:operation {:one-of #{:plus :minus :times :divide}}
:on-result :event}}
'schedule/start
{:permissions [:read]
@ -505,140 +525,158 @@
'ethereum/transaction-receipt
{:permissions [:read]
:value :extensions/ethereum-transaction-receipt
:arguments {:value :string
:on-result :event}}
:arguments {:value :string
:on-success :event
:on-failure? :event}}
'ethereum/sign
{:permissions [:read]
:value :extensions/ethereum-sign
:arguments {:message? :string
:data? :string
:on-result :event}}
:arguments {:message? :string
:data? :string
:on-success :event
:on-failure? :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-result :event}}
:arguments {:to :string
:gas? :string
:gas-price? :string
:value? :string
:method? :string
:params? :vector
:nonce? :string
:on-success :event
:on-failure? :event}}
'ethereum/logs
{:permissions [:read]
:value :extensions/ethereum-logs
: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}}
:arguments {:from? :string
:to? :string
:address? :vector
:topics? :vector
:block-hash? :string
:on-success :event
:on-failure? :event}}
'ethereum/create-filter
{:permissions [:read]
:value :extensions/ethereum-create-filter
:arguments {:filter-type :string
:from? :string
:to? :string
:address? :vector
:topics? :vector
:arguments {:type {:one-of #{:filter :block :pending-transaction}}
:from? :string
:to? :string
:address? :vector
:topics? :vector
:block-hash? :string
:on-result :event}}
:on-success :event
:on-failure? :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-result :event}}
:on-success :event
:on-failure? :event}}
'ethereum.erc20/balance-of
{:permissions [:read]
:value :extensions/ethereum-erc20-balance-of
:arguments {:contract :string
:token-owner :string
:on-result :event}}
:on-success :event
:on-failure? :event}}
'ethereum.erc20/transfer
{:permissions [:read]
:value :extensions/ethereum-erc20-transfer
:arguments {:contract :string
:to :string
:value :number
:on-result :event}}
:arguments {:contract :string
:to :string
:value :number
:on-success :event
:on-failure? :event}}
'ethereum.erc20/transfer-from
{:permissions [:read]
:value :extensions/ethereum-erc20-transfer-from
:arguments {:contract :string
:from :string
:to :string
:value :number
:on-result :event}}
:arguments {:contract :string
:from :string
:to :string
:value :number
:on-success :event
:on-failure? :event}}
'ethereum.erc20/approve
{:permissions [:read]
:value :extensions/ethereum-erc20-approve
:arguments {:contract :string
:spender :string
:value :number
:on-result :event}}
:on-success :event
:on-failure? :event}}
'ethereum.erc20/allowance
{:permissions [:read]
:value :extensions/ethereum-erc20-allowance
:arguments {:contract :string
:token-owner :string
:spender :string
:on-result :event}}
:on-success :event
:on-failure? :event}}
'ethereum.erc721/owner-of
{:permissions [:read]
:value :extensions/ethereum-erc721-owner-of
:arguments {:contract :string
:token-id :string
:on-result :event}}
:on-success :event
:on-failure? :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-result :event}}
:arguments {:contract :string
:owner :string
:operator :string
:on-success :event
:on-failure? :event}}
'ethereum.erc721/get-approved
{:permissions [:read]
:value :extensions/ethereum-erc721-get-approved
:arguments {:contract :string
:token-id :string
:on-result :event}}
:arguments {:contract :string
:token-id :string
:on-success :event
:on-failure? :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-result :event}}
:arguments {:contract :string
:operator :string
:approved :boolean
:on-success :event
:on-failure? :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-result :event}}
:arguments {:contract :string
:from :string
:to :string
:token-id :string
:data? :string
:on-success :event
:on-failure? :event}}
'ethereum/call
{:permissions [:read]
:value :extensions/ethereum-call
:arguments {:to :string
:method :string
:params? :vector
:outputs? :vector
:on-result :event}}}
:arguments {:to :string
:method :string
:params? :vector
:outputs? :vector
:on-success :event
:on-failure? :event}}}
:hooks {:chat.command commands/command-hook
:wallet.settings settings/hook}})

View File

@ -17,23 +17,20 @@
[status-im.native-module.core :as status]))
(handlers/register-handler-fx
:extensions/wallet-ui-on-result
(fn [cofx [_ on-result id result method]]
:extensions/wallet-ui-on-success
(fn [cofx [_ on-success _ result _]]
(fx/merge cofx
(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)))))
{:dispatch (on-success {:value result})}
(navigation/navigate-back))))
(handlers/register-handler-fx
:extensions/wallet-ui-on-error
(fn [{db :db} [_ on-result message]]
(when on-result {:dispatch (on-result {:error message :result nil})})))
:extensions/wallet-ui-on-failure
(fn [_ [_ on-failure message]]
(when on-failure {:dispatch (on-failure {:value message})})))
(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"
"function 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)
@ -46,8 +43,7 @@
(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]
(defn prepare-extension-transaction [params contacts on-success on-failure]
(let [{:keys [to value data gas gasPrice nonce]} params
contact (get contacts (hex/normalize-hex to))]
(cond-> {:id "extension-id"
@ -66,15 +62,15 @@
:gas-price (when gasPrice
(money/bignumber gasPrice))
:data data
:on-result [:extensions/wallet-ui-on-result on-result]
:on-error [:extensions/wallet-ui-on-error on-result]}
:on-result [:extensions/wallet-ui-on-success on-success]
:on-error [:extensions/wallet-ui-on-failure on-failure]}
nonce
(assoc :nonce nonce))))
(defn- execute-send-transaction [db {:keys [method params on-result] :as arguments}]
(defn- execute-send-transaction [db {:keys [method params on-success on-failure] :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)]
transaction (prepare-extension-transaction tx-object (:contacts/contacts db) on-success on-failure)]
(models.wallet/open-modal-wallet-for-transaction db transaction tx-object)))
(handlers/register-handler-fx
@ -82,143 +78,173 @@
(fn [{db :db} [_ _ arguments]]
(wrap-with-resolution db arguments :to execute-send-transaction)))
(defn- execute-ethcall [_ {:keys [to method params outputs on-result]}]
(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]}]
(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})))))]}))
{: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)]}))
(handlers/register-handler-fx
:extensions/ethereum-call
(fn [{db :db} [_ _ {:keys [to] :as arguments}]]
(fn [{db :db} [_ _ arguments]]
(wrap-with-resolution db arguments :to execute-ethcall)))
(handlers/register-handler-fx
:extensions/ethereum-erc20-total-supply
(fn [{db :db} [_ _ {:keys [contract on-result]}]]
(fn [{db :db} [_ _ {:keys [contract on-success on-failure]}]]
(let [json-rpc-args {:to contract
:method "totalSupply()"
:outputs ["uint256"]
:on-result on-result}]
:method "totalSupply()"
:outputs ["uint256"]
:on-success on-success
:on-failure on-failure}]
(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-result]}]]
(fn [{db :db} [_ _ {:keys [contract token-owner on-success on-failure]}]]
(let [json-rpc-args {:to contract
:method "balanceOf(address)"
:params [token-owner]
:outputs ["uint256"]
:on-result on-result}]
:method "balanceOf(address)"
:params [token-owner]
:outputs ["uint256"]
:on-success on-success
:on-failure on-failure}]
(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-result]}]]
(fn [{db :db} [_ _ {:keys [contract token-owner spender on-success on-failure]}]]
(let [json-rpc-args {:to contract
:method "allowance(address,address)"
:params [token-owner spender]
:outputs ["uint256"]
:on-result on-result}]
:method "allowance(address,address)"
:params [token-owner spender]
:outputs ["uint256"]
:on-success on-success
:on-failure on-failure}]
(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-result]}]]
(fn [{db :db} [_ _ {:keys [contract to value on-success on-failure]}]]
(let [json-rpc-args {:to contract
:method "transfer(address,uint256)"
:params [to value]
:on-result on-result}]
:method "transfer(address,uint256)"
:params [to value]
:on-success on-success
:on-failure on-failure}]
(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-result]}]]
(fn [{db :db} [_ _ {:keys [contract from to value on-success on-failure]}]]
(let [json-rpc-args {:to contract
:method "transferFrom(address,address,uint256)"
:params [from to value]
:on-result on-result}]
:method "transferFrom(address,address,uint256)"
:params [from to value]
:on-success on-success
:on-failure on-failure}]
(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-result]}]]
(fn [{db :db} [_ _ {:keys [contract spender value on-success on-failure]}]]
(let [json-rpc-args {:to contract
:method "approve(address,uint256)"
:params [spender value]
:on-result on-result}]
:method "approve(address,uint256)"
:params [spender value]
:on-success on-success
:on-failure on-failure}]
(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-result]}]]
(fn [{db :db} [_ _ {:keys [contract token-id on-success on-failure]}]]
(let [json-rpc-args {:to contract
:method "ownerOf(uint256)"
:params [token-id]
:outputs ["address"]
:on-result on-result}]
:method "ownerOf(uint256)"
:params [token-id]
:outputs ["address"]
:on-success on-success
:on-failure on-failure}]
(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-result]}]]
(fn [{db :db} [_ _ {:keys [contract owner operator on-success on-failure]}]]
(let [json-rpc-args {:to contract
:method "isApprovedForAll(address,address)"
:params [owner operator]
:outputs ["bool"]
:on-result on-result}]
:method "isApprovedForAll(address,address)"
:params [owner operator]
:outputs ["bool"]
:on-success on-success
:on-failure on-failure}]
(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-result]}]]
(fn [{db :db} [_ _ {:keys [contract token-id on-success on-failure]}]]
(let [json-rpc-args {:to contract
:method "getApproved(uint256)"
:params [token-id]
:outputs ["address"]
:on-result on-result}]
:method "getApproved(uint256)"
:params [token-id]
:outputs ["address"]
:on-success on-success
:on-failure on-failure}]
(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-result]}]]
(fn [{db :db} [_ _ {:keys [contract to approved on-success on-failure]}]]
(let [json-rpc-args {:to contract
:method "setApprovalForAll(address,bool)"
:params [to approved]
:on-result on-result}]
:method "setApprovalForAll(address,bool)"
:params [to approved]
:on-success on-success
:on-failure on-failure}]
(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-result]}]]
(fn [{db :db} [_ _ {:keys [contract from to token-id data on-success on-failure]}]]
(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-result on-result}]
: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}]
(wrap-with-resolution db json-rpc-args :to execute-send-transaction))))
(defn- parse-log [{:keys [address transactionHash blockHash transactionIndex topics blockNumber logIndex removed data]}]
{: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})
(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)})))
(defn- parse-receipt [m]
(when m
@ -238,16 +264,8 @@
(handlers/register-handler-fx
:extensions/ethereum-transaction-receipt
(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
(fn [_ [_ _ {:keys [value] :as m}]]
(rpc-call constants/web3-transaction-receipt [value] parse-receipt m)))
(defn- event-topic-enc [event params]
(let [eventid (str event "(" (string/join "," params) ")")]
@ -264,17 +282,16 @@
:else :bytes))
(defn- values-topic-enc [type values]
(let [mapped-type (types-mapping type)]
(mapv #(str "0x" (abi-spec/enc {:type mapped-type :value %})) values)))
(mapv #(str "0x" (abi-spec/enc {:type (types-mapping type) :value %})) values))
(defn- parse-topic [t]
(defn- generate-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 parse-topic t) ;; descend in vector elements
(vector? t) (mapv generate-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
(some? event) (event-topic-enc event params);; event params topic {:event "Transfer" :params ["uint"]}
(some? type) (values-topic-enc type values) ;; indexed values topic
:else nil)) ;; error
:else nil))
@ -285,19 +302,13 @@
(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))))))
(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)))
(handlers/register-handler-fx
:extensions/ethereum-logs
@ -306,71 +317,59 @@
(handlers/register-handler-fx
:extensions/ethereum-resolve-ens
(fn [{db :db} [_ _ {:keys [name on-result]}]]
(fn [{db :db} [_ _ {:keys [name on-success on-failure]}]]
(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")})))))
(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")}))))))
;; EXTENSION SIGN -> SIGN MESSAGE
(handlers/register-handler-fx
:extensions/ethereum-sign
(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"})}
(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"})})
(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-result on-result]
:on-error [:extensions/wallet-ui-on-error on-result]
:on-result [:extensions/wallet-ui-on-success on-success]
:on-error [:extensions/wallet-ui-on-failure on-failure]
: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 [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))))))
(fn [_ [_ _ {:keys [id] :as m}]]
(rpc-call constants/web3-get-filter-changes [(abi-spec/number-to-hex id)] #(map parse-log %) m)))
(handlers/register-handler-fx
:extensions/ethereum-cancel-filter
(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)))))))
(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}]))
(handlers/register-handler-fx
:extensions/ethereum-create-filter
(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)))))))
(fn [_ [_ _ {:keys [type] :as m}]]
(rpc-call (create-filter-method type) (create-filter-arguments type m) abi-spec/hex-to-number m)))

View File

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

View File

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

View File

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

View File

@ -8,34 +8,34 @@
(testing "topic parsing check - events"
(is (= ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
"0x29f31b934498b0deabbe211b01cc30eee6475abf0f0d553e7eb8ca71deeb24b3"]
(ethereum/parse-topic [{:event "Transfer" :params ["address" "address" "uint256"]}
{:event "drawBet" :params ["uint256" "uint8" "int8" "address" "uint256"]}])))))
(ethereum/generate-topic [{:event "Transfer" :params ["address" "address" "uint256"]}
{:event "drawBet" :params ["uint256" "uint8" "int8" "address" "uint256"]}])))))
(deftest test-parse-topic-indexed-values-address
(testing "topic parsing check - indexed values address"
(is (= ["0x000000000000000000000000299b18709d4aacbda99048721448f65893a0c73a"
"0x00000000000000000000000094eaa5fa6b313968b2abd6da375ef28077d95d53"]
(ethereum/parse-topic {:type "address" :values ["0x299b18709d4aacbda99048721448f65893a0c73a" "0x94eaa5fa6b313968b2abd6da375ef28077d95d53"]})))))
(ethereum/generate-topic {:type "address" :values ["0x299b18709d4aacbda99048721448f65893a0c73a" "0x94eaa5fa6b313968b2abd6da375ef28077d95d53"]})))))
(deftest test-parse-topic-indexed-values-uint256
(testing "topic parsing check - indexed values uint256"
(is (= ["0x00000000000000000000000000000000000000000000000000000000000003fd"
"0x0000000000000000000000000000000000000000000000000000000000000078"]
(ethereum/parse-topic {:type "uint256" :values ["0x3fd" "120"]})))))
(ethereum/generate-topic {:type "uint256" :values ["0x3fd" "120"]})))))
(deftest test-parse-topic-indexed-values-direct
(testing "topic parsing check - indexed values direct"
(is (= ["0x00000000000000000000000000000000000000000000000000000000000003fd"
"0x0000000000000000000000000000000000000000000000000000000000000078"]
(ethereum/parse-topic ["0x00000000000000000000000000000000000000000000000000000000000003fd"
"0x0000000000000000000000000000000000000000000000000000000000000078"])))))
(ethereum/generate-topic ["0x00000000000000000000000000000000000000000000000000000000000003fd"
"0x0000000000000000000000000000000000000000000000000000000000000078"])))))
(deftest test-parse-topic-indexed-nil
(testing "topic parsing check - nil"
(is (= ["0x00000000000000000000000000000000000000000000000000000000000003fd"
nil]
(ethereum/parse-topic ["0x00000000000000000000000000000000000000000000000000000000000003fd"
nil])))))
(ethereum/generate-topic ["0x00000000000000000000000000000000000000000000000000000000000003fd"
nil])))))
(deftest test-ensure-hex-bn-nonnumber
(is (= "latest" (ethereum/ensure-hex-bn "latest"))))
@ -47,4 +47,4 @@
(is (= "0xf" (ethereum/ensure-hex-bn "0xf"))))
(deftest test-ensure-hex-bn-nil
(is (= nil (ethereum/ensure-hex-bn nil))))
(is (= nil (ethereum/ensure-hex-bn nil))))