Allow dApps to suggest change of RPC (EIP-3085 EIP-3326) (#13716)
This commit is contained in:
parent
af3ba74e30
commit
a74a44e492
|
@ -22,7 +22,9 @@
|
||||||
[status-im.bottom-sheet.core :as bottom-sheet]
|
[status-im.bottom-sheet.core :as bottom-sheet]
|
||||||
[status-im.browser.webview-ref :as webview-ref]
|
[status-im.browser.webview-ref :as webview-ref]
|
||||||
["eth-phishing-detect" :as eth-phishing-detect]
|
["eth-phishing-detect" :as eth-phishing-detect]
|
||||||
[status-im.utils.debounce :as debounce]))
|
[status-im.utils.debounce :as debounce]
|
||||||
|
[status-im.browser.eip3085 :as eip3085]
|
||||||
|
[status-im.browser.eip3326 :as eip3326]))
|
||||||
|
|
||||||
(fx/defn update-browser-option
|
(fx/defn update-browser-option
|
||||||
[{:keys [db]} option-key option-value]
|
[{:keys [db]} option-key option-value]
|
||||||
|
@ -345,7 +347,7 @@
|
||||||
constants/web3-eth-sign constants/web3-keycard-sign-typed-data} method))
|
constants/web3-eth-sign constants/web3-keycard-sign-typed-data} method))
|
||||||
|
|
||||||
(fx/defn web3-send-async
|
(fx/defn web3-send-async
|
||||||
[cofx {:keys [method params id] :as payload} message-id]
|
[cofx dapp-name {:keys [method params id] :as payload} message-id]
|
||||||
(let [message? (web3-sign-message? method)
|
(let [message? (web3-sign-message? method)
|
||||||
dapps-address (get-in cofx [:db :multiaccount :dapps-address])
|
dapps-address (get-in cofx [:db :multiaccount :dapps-address])
|
||||||
typed? (and (not= constants/web3-personal-sign method) (not= constants/web3-eth-sign method))]
|
typed? (and (not= constants/web3-personal-sign method) (not= constants/web3-eth-sign method))]
|
||||||
|
@ -371,25 +373,33 @@
|
||||||
(dissoc :gasPrice))})
|
(dissoc :gasPrice))})
|
||||||
{:on-result [:browser.dapp/transaction-on-result message-id id]
|
{:on-result [:browser.dapp/transaction-on-result message-id id]
|
||||||
:on-error [:browser.dapp/transaction-on-error message-id]}))))
|
:on-error [:browser.dapp/transaction-on-error message-id]}))))
|
||||||
(if (#{"eth_accounts" "eth_coinbase"} method)
|
(cond
|
||||||
|
(#{"eth_accounts" "eth_coinbase"} method)
|
||||||
(send-to-bridge cofx {:type constants/web3-send-async-callback
|
(send-to-bridge cofx {:type constants/web3-send-async-callback
|
||||||
:messageId message-id
|
:messageId message-id
|
||||||
:result {:jsonrpc "2.0"
|
:result {:jsonrpc "2.0"
|
||||||
:id (int id)
|
:id (int id)
|
||||||
:result (if (= method "eth_coinbase") dapps-address [dapps-address])}})
|
:result (if (= method "eth_coinbase") dapps-address [dapps-address])}})
|
||||||
(if (= method "personal_ecRecover")
|
(= method "personal_ecRecover")
|
||||||
{:signing.fx/recover-message {:params {:message (first params)
|
{:signing.fx/recover-message {:params {:message (first params)
|
||||||
:signature (second params)}
|
:signature (second params)}
|
||||||
:on-completed #(re-frame/dispatch [:browser.callback/call-rpc
|
:on-completed #(re-frame/dispatch [:browser.callback/call-rpc
|
||||||
{:type constants/web3-send-async-callback
|
{:type constants/web3-send-async-callback
|
||||||
:messageId message-id
|
:messageId message-id
|
||||||
:result (types/json->clj %)}])}}
|
:result (types/json->clj %)}])}}
|
||||||
|
(= method "wallet_switchEthereumChain")
|
||||||
|
(eip3326/handle-switch-ethereum-chain cofx dapp-name id message-id (first params))
|
||||||
|
|
||||||
|
(= method "wallet_addEthereumChain")
|
||||||
|
(eip3085/handle-add-ethereum-chain cofx dapp-name id message-id (first params))
|
||||||
|
|
||||||
|
:else
|
||||||
{:browser/call-rpc [payload
|
{:browser/call-rpc [payload
|
||||||
#(re-frame/dispatch [:browser.callback/call-rpc
|
#(re-frame/dispatch [:browser.callback/call-rpc
|
||||||
{:type constants/web3-send-async-callback
|
{:type constants/web3-send-async-callback
|
||||||
:messageId message-id
|
:messageId message-id
|
||||||
:error %1
|
:error %1
|
||||||
:result %2}])]})))))
|
:result %2}])]}))))
|
||||||
|
|
||||||
(fx/defn handle-no-permissions [cofx {:keys [method id]} message-id]
|
(fx/defn handle-no-permissions [cofx {:keys [method id]} message-id]
|
||||||
(if (= method "eth_accounts")
|
(if (= method "eth_accounts")
|
||||||
|
@ -419,7 +429,7 @@
|
||||||
[{:keys [db] :as cofx} dapp-name {:keys [method] :as payload} message-id]
|
[{:keys [db] :as cofx} dapp-name {:keys [method] :as payload} message-id]
|
||||||
(if (has-permissions? db dapp-name method)
|
(if (has-permissions? db dapp-name method)
|
||||||
(handle-no-permissions cofx payload message-id)
|
(handle-no-permissions cofx payload message-id)
|
||||||
(web3-send-async cofx payload message-id)))
|
(web3-send-async cofx dapp-name payload message-id)))
|
||||||
|
|
||||||
(fx/defn handle-scanned-qr-code
|
(fx/defn handle-scanned-qr-code
|
||||||
{:events [:browser.bridge.callback/qr-code-scanned]}
|
{:events [:browser.bridge.callback/qr-code-scanned]}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
;reference https://eips.ethereum.org/EIPS/eip-3085 EIP-3085: Wallet Add Ethereum Chain RPC Method (`wallet_addEthereumChain`)
|
||||||
|
(ns status-im.browser.eip3085
|
||||||
|
(:require [status-im.constants :as constants]
|
||||||
|
[clojure.string :as string]
|
||||||
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im.utils.fx :as fx]
|
||||||
|
[status-im.network.core :as network]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[status-im.utils.random :as random]
|
||||||
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
|
[status-im.ui.screens.browser.eip3085.sheet :as sheet]))
|
||||||
|
|
||||||
|
(fx/defn send-success-call-to-bridge
|
||||||
|
{:events [:eip3085/send-success-call-to-bridge]}
|
||||||
|
[_ id messageId]
|
||||||
|
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||||
|
:messageId messageId
|
||||||
|
:result {:jsonrpc "2.0"
|
||||||
|
:id (int id)
|
||||||
|
:result nil}}})
|
||||||
|
|
||||||
|
(fx/defn allow-permission
|
||||||
|
{:events [:eip3085.ui/dapp-permission-allowed]}
|
||||||
|
[{:keys [db] :as cofx} message-id {:keys [new-networks id]}]
|
||||||
|
{:db (assoc db :networks/networks new-networks)
|
||||||
|
::json-rpc/call [{:method "settings_saveSetting"
|
||||||
|
:params [:networks/networks (vals new-networks)]
|
||||||
|
:on-success #(re-frame/dispatch [:eip3085/send-success-call-to-bridge cofx id message-id])
|
||||||
|
:on-error #(log/error "failed to perform settings_saveSetting" %)}]
|
||||||
|
:dispatch [:bottom-sheet/hide]})
|
||||||
|
|
||||||
|
(fx/defn deny-permission
|
||||||
|
{:events [:eip3085.ui/dapp-permission-denied]}
|
||||||
|
[_ message-id _]
|
||||||
|
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||||
|
:messageId message-id
|
||||||
|
:error {:code 4001
|
||||||
|
:message "User rejected the request."}}
|
||||||
|
:dispatch [:bottom-sheet/hide]})
|
||||||
|
|
||||||
|
(fx/defn handle-add-ethereum-chain
|
||||||
|
{:events [:eip3085/handle-add-ethereum-chain]}
|
||||||
|
[{{:networks/keys [networks] :as db} :db :as cofx}
|
||||||
|
dapp-name id message-id {:keys [chainId blockExplorerUrls chainName iconUrls nativeCurrency rpcUrls] :as params}]
|
||||||
|
(let [manage {:name {:value chainName}
|
||||||
|
:symbol {:value (:symbol nativeCurrency)}
|
||||||
|
:url {:value (first rpcUrls)}
|
||||||
|
:network-id {:value chainId}
|
||||||
|
:chain {:value :custom}}]
|
||||||
|
(if (network/valid-manage? manage)
|
||||||
|
(let [{:keys [name url chain network-id symbol]} manage
|
||||||
|
random-id (string/replace (random/id) "-" "")
|
||||||
|
network (network/new-network random-id
|
||||||
|
(:value name)
|
||||||
|
(:value symbol)
|
||||||
|
(:value url)
|
||||||
|
(:value chain)
|
||||||
|
(:value network-id))
|
||||||
|
new-networks (assoc networks random-id network)
|
||||||
|
params (assoc params :new-networks new-networks :id id :new-network network)]
|
||||||
|
(if (network/chain-id-available? networks network)
|
||||||
|
{:dispatch [:bottom-sheet/show-sheet {:content (fn []
|
||||||
|
[sheet/permissions-panel dapp-name message-id params])}]}
|
||||||
|
(send-success-call-to-bridge cofx id message-id)))
|
||||||
|
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||||
|
:messageId message-id
|
||||||
|
:error {:code -32602
|
||||||
|
:message "invalid network parameters"}}})))
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
;reference https://eips.ethereum.org/EIPS/eip-3326 EIP-3326: Wallet Switch Ethereum Chain RPC Method (`wallet_switchEthereumChain`)
|
||||||
|
(ns status-im.browser.eip3326
|
||||||
|
(:require [status-im.constants :as constants]
|
||||||
|
[status-im.utils.fx :as fx]
|
||||||
|
[status-im.ethereum.core :as ethereum]
|
||||||
|
[status-im.ui.screens.browser.eip3326.sheet :as sheet]))
|
||||||
|
|
||||||
|
(fx/defn deny-permission
|
||||||
|
{:events [:eip3326.ui/dapp-permission-denied]}
|
||||||
|
[{:keys [db] :as cofx} message-id _]
|
||||||
|
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||||
|
:messageId message-id
|
||||||
|
:error {:code 4001
|
||||||
|
:message "User rejected the request."}}
|
||||||
|
:dispatch [:bottom-sheet/hide]})
|
||||||
|
|
||||||
|
(fx/defn handle-switch-ethereum-chain
|
||||||
|
{:events [:eip3326/handle-switch-ethereum-chain]}
|
||||||
|
[{:keys [db] :as cofx} dapp-name id message-id {:keys [chainId] :as params}]
|
||||||
|
(let [target-chain-id (js/parseInt chainId 16)
|
||||||
|
networks (vals (get-in db [:networks/networks]))
|
||||||
|
exist-chain-ids (set (map ethereum/network->chain-id networks))
|
||||||
|
current-chain-id (ethereum/chain-id db)]
|
||||||
|
(if (exist-chain-ids target-chain-id)
|
||||||
|
(if (= current-chain-id target-chain-id)
|
||||||
|
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||||
|
:messageId message-id
|
||||||
|
:result {:jsonrpc "2.0"
|
||||||
|
:id (int id)
|
||||||
|
:result nil}}}
|
||||||
|
(let [target-network (first (filter #(= (ethereum/network->chain-id %1) target-chain-id) networks))
|
||||||
|
target-network-id (:id target-network)
|
||||||
|
current-network (ethereum/current-network db)
|
||||||
|
network-from (:name current-network)
|
||||||
|
network-to (:name target-network)
|
||||||
|
params (assoc params :target-network-id target-network-id :network-from network-from :network-to network-to)]
|
||||||
|
{:dispatch [:bottom-sheet/show-sheet {:content (fn []
|
||||||
|
[sheet/permissions-panel dapp-name message-id params])}]}))
|
||||||
|
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||||
|
:messageId message-id
|
||||||
|
:error {:code 4902
|
||||||
|
:message (str "Unrecognized chain ID: " target-chain-id ". Try adding the chain using wallet_addEthereumChain first.")}}})))
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
(ns status-im.ui.screens.browser.eip3085.sheet
|
||||||
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||||
|
[status-im.ui.components.icons.icons :as icons]
|
||||||
|
[status-im.ui.components.react :as react]
|
||||||
|
[status-im.ui.screens.browser.styles :as styles]
|
||||||
|
[quo.design-system.colors :as colors]
|
||||||
|
[quo.core :as quo]
|
||||||
|
[status-im.ui.components.copyable-text :as copyable-text])
|
||||||
|
(:require-macros [status-im.utils.views :as views]))
|
||||||
|
|
||||||
|
(views/defview permissions-panel [dapp-name message-id params]
|
||||||
|
(views/letsubs [{:keys [dapp? dapp]} [:get-current-browser]]
|
||||||
|
[react/view {}
|
||||||
|
[react/view styles/permissions-panel-icons-container
|
||||||
|
(if dapp?
|
||||||
|
[chat-icon.screen/dapp-icon-permission dapp 40]
|
||||||
|
[react/view styles/permissions-panel-dapp-icon-container
|
||||||
|
[icons/icon :main-icons/dapp {:color colors/gray}]])
|
||||||
|
[react/view {:margin-left 8 :margin-right 4}
|
||||||
|
[react/view styles/dot]]
|
||||||
|
[react/view {:margin-right 4}
|
||||||
|
[react/view styles/dot]]
|
||||||
|
[react/view {:margin-right 8}
|
||||||
|
[react/view styles/dot]]
|
||||||
|
[react/view styles/permissions-panel-ok-icon-container
|
||||||
|
[icons/icon :tiny-icons/tiny-check styles/permissions-panel-ok-ico]]
|
||||||
|
[react/view {:margin-left 8 :margin-right 4}
|
||||||
|
[react/view styles/dot]]
|
||||||
|
[react/view {:margin-right 4}
|
||||||
|
[react/view styles/dot]]
|
||||||
|
[react/view {:margin-right 8}
|
||||||
|
[react/view styles/dot]]
|
||||||
|
[react/view styles/permissions-panel-wallet-icon-container
|
||||||
|
[icons/icon :main-icons/wallet {:color colors/white}]]]
|
||||||
|
[react/text {:style styles/permissions-panel-title-label :number-of-lines 2}
|
||||||
|
(str "\"" dapp-name "\" Allow this site to add a network?")]
|
||||||
|
[react/text {:style styles/permissions-panel-description-label :number-of-lines 4} "This will allow this network to be used within Status.Status does not verify custom networks.Learn about scams and network security risks."]
|
||||||
|
[react/scroll-view
|
||||||
|
[copyable-text/copyable-text-view
|
||||||
|
{:copied-text (:name (:new-network params))}
|
||||||
|
[quo/list-item
|
||||||
|
{:size :small
|
||||||
|
:accessibility-label :network-name
|
||||||
|
:title "Network Name"
|
||||||
|
:accessory :text
|
||||||
|
:accessory-text (:name (:new-network params))}]]
|
||||||
|
[copyable-text/copyable-text-view
|
||||||
|
{:copied-text (get-in params [:new-network :config :UpstreamConfig :URL])}
|
||||||
|
[quo/list-item
|
||||||
|
{:size :small
|
||||||
|
:accessibility-label :network-url
|
||||||
|
:title "Network URL"
|
||||||
|
:accessory :text
|
||||||
|
:accessory-text (get-in params [:new-network :config :UpstreamConfig :URL])}]]
|
||||||
|
[copyable-text/copyable-text-view
|
||||||
|
{:copied-text (str (get-in params [:new-network :config :NetworkId]))}
|
||||||
|
[quo/list-item
|
||||||
|
{:size :small
|
||||||
|
:accessibility-label :network-id
|
||||||
|
:title "Chain ID"
|
||||||
|
:accessory :text
|
||||||
|
:accessory-text (str (get-in params [:new-network :config :NetworkId]))}]]]
|
||||||
|
[react/view {:style {:flex-direction :row
|
||||||
|
:justify-content :center
|
||||||
|
:margin-horizontal 8
|
||||||
|
:margin-top 24}}
|
||||||
|
[react/view {:flex 1
|
||||||
|
:margin-horizontal 8}
|
||||||
|
[quo/button
|
||||||
|
{:theme :negative
|
||||||
|
:on-press #(re-frame/dispatch [:eip3085.ui/dapp-permission-denied message-id params])}
|
||||||
|
(i18n/label :t/deny)]]
|
||||||
|
[react/view {:flex 1
|
||||||
|
:margin-horizontal 8}
|
||||||
|
[quo/button
|
||||||
|
{:theme :positive
|
||||||
|
:style {:margin-horizontal 8}
|
||||||
|
:on-press #(re-frame/dispatch [:eip3085.ui/dapp-permission-allowed message-id params])}
|
||||||
|
(i18n/label :t/allow)]]]]))
|
|
@ -0,0 +1,58 @@
|
||||||
|
(ns status-im.ui.screens.browser.eip3326.sheet
|
||||||
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[status-im.i18n.i18n :as i18n]
|
||||||
|
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||||
|
[status-im.ui.components.icons.icons :as icons]
|
||||||
|
[status-im.ui.components.react :as react]
|
||||||
|
[status-im.ui.screens.browser.styles :as styles]
|
||||||
|
[status-im.utils.debounce :as debounce]
|
||||||
|
[status-im.network.core :as network]
|
||||||
|
[quo.design-system.colors :as colors]
|
||||||
|
[quo.core :as quo])
|
||||||
|
(:require-macros [status-im.utils.views :as views]))
|
||||||
|
|
||||||
|
(views/defview permissions-panel [dapp-name message-id {:keys [network-from network-to target-network-id] :as params}]
|
||||||
|
(views/letsubs [{:keys [dapp? dapp]} [:get-current-browser]]
|
||||||
|
[react/view {}
|
||||||
|
[react/view styles/permissions-panel-icons-container
|
||||||
|
(if dapp?
|
||||||
|
[chat-icon.screen/dapp-icon-permission dapp 40]
|
||||||
|
[react/view styles/permissions-panel-dapp-icon-container
|
||||||
|
[icons/icon :main-icons/dapp {:color colors/gray}]])
|
||||||
|
[react/view {:margin-left 8 :margin-right 4}
|
||||||
|
[react/view styles/dot]]
|
||||||
|
[react/view {:margin-right 4}
|
||||||
|
[react/view styles/dot]]
|
||||||
|
[react/view {:margin-right 8}
|
||||||
|
[react/view styles/dot]]
|
||||||
|
[react/view styles/permissions-panel-ok-icon-container
|
||||||
|
[icons/icon :tiny-icons/tiny-check styles/permissions-panel-ok-ico]]
|
||||||
|
[react/view {:margin-left 8 :margin-right 4}
|
||||||
|
[react/view styles/dot]]
|
||||||
|
[react/view {:margin-right 4}
|
||||||
|
[react/view styles/dot]]
|
||||||
|
[react/view {:margin-right 8}
|
||||||
|
[react/view styles/dot]]
|
||||||
|
[react/view styles/permissions-panel-wallet-icon-container
|
||||||
|
[icons/icon :main-icons/wallet {:color colors/white}]]]
|
||||||
|
[react/text {:style styles/permissions-panel-title-label :number-of-lines 2}
|
||||||
|
(str "\"" dapp-name "\" Allow this site to switch the network?")]
|
||||||
|
[react/text {:style styles/permissions-panel-description-label :number-of-lines 5}
|
||||||
|
(str "This will switch the selected network within Status to a previously added network:\n" network-from " -> " network-to "\nit will require login/logout")]
|
||||||
|
[react/view {:style {:flex-direction :row
|
||||||
|
:justify-content :center
|
||||||
|
:margin-horizontal 8
|
||||||
|
:margin-top 24}}
|
||||||
|
[react/view {:flex 1
|
||||||
|
:margin-horizontal 8}
|
||||||
|
[quo/button
|
||||||
|
{:theme :negative
|
||||||
|
:on-press #(re-frame/dispatch [:eip3326.ui/dapp-permission-denied message-id params])}
|
||||||
|
(i18n/label :t/deny)]]
|
||||||
|
[react/view {:flex 1
|
||||||
|
:margin-horizontal 8}
|
||||||
|
[quo/button
|
||||||
|
{:theme :positive
|
||||||
|
:style {:margin-horizontal 8}
|
||||||
|
:on-press #(debounce/dispatch-and-chill [::network/connect-network-pressed target-network-id] 1000)}
|
||||||
|
(i18n/label :t/allow)]]]]))
|
Loading…
Reference in New Issue