web3 opt-in updates
Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
This commit is contained in:
parent
a79eca1e23
commit
a20facd895
|
@ -6,6 +6,17 @@ function bridgeSend(data){
|
|||
WebViewBridge.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
window.addEventListener('message', function (event) {
|
||||
if (!event.data || !event.data.type) { return; }
|
||||
if (event.data.type === 'STATUS_API_REQUEST') {
|
||||
bridgeSend({
|
||||
type: 'status-api-request',
|
||||
permissions: event.data.permissions,
|
||||
host: window.location.hostname
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
WebViewBridge.onMessage = function (message) {
|
||||
data = JSON.parse(message);
|
||||
|
||||
|
@ -13,18 +24,11 @@ WebViewBridge.onMessage = function (message) {
|
|||
window.location.href = "about:blank";
|
||||
|
||||
else if (data.type === "status-api-success")
|
||||
{
|
||||
if (data.keys == 'WEB3')
|
||||
{
|
||||
window.dispatchEvent(new CustomEvent('ethereumprovider', { detail: { ethereum: new StatusHttpProvider("")} }));
|
||||
}
|
||||
else
|
||||
{
|
||||
window.dispatchEvent(new CustomEvent('statusapi', { detail: { permissions: data.keys,
|
||||
data: data.data
|
||||
} }));
|
||||
}
|
||||
}
|
||||
|
||||
else if (data.type === "web3-send-async-callback")
|
||||
{
|
||||
|
@ -113,6 +117,10 @@ StatusHttpProvider.prototype.sendAsync = function (payload, callback) {
|
|||
|
||||
}
|
||||
};
|
||||
|
||||
StatusHttpProvider.prototype.enable = function () {
|
||||
return new Promise(function (resolve, reject) { setTimeout(resolve, 1000);});
|
||||
};
|
||||
}
|
||||
|
||||
var protocol = window.location.protocol
|
||||
|
@ -120,7 +128,8 @@ if (typeof web3 === "undefined") {
|
|||
//why do we need this condition?
|
||||
if (protocol == "https:" || protocol == "http:") {
|
||||
console.log("StatusHttpProvider");
|
||||
web3 = new Web3(new StatusHttpProvider());
|
||||
web3.eth.defaultAccount = currentAccountAddress; // currentAccountAddress - injected from status-react
|
||||
ethereum = new StatusHttpProvider();
|
||||
web3 = new Web3(ethereum);
|
||||
web3.eth.defaultAccount = currentAccountAddress;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
if(typeof ReadOnlyProvider === "undefined"){
|
||||
var callbackId = 0;
|
||||
var callbacks = {};
|
||||
var ethereumPromise = {};
|
||||
|
||||
function bridgeSend(data){
|
||||
WebViewBridge.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
window.addEventListener('message', function (event) {
|
||||
if (!event.data || !event.data.type) { return; }
|
||||
if (event.data.type === 'STATUS_API_REQUEST') {
|
||||
bridgeSend({
|
||||
type: 'status-api-request',
|
||||
permissions: event.data.permissions,
|
||||
host: window.location.hostname
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
WebViewBridge.onMessage = function (message) {
|
||||
data = JSON.parse(message);
|
||||
|
||||
if (data.type === "navigate-to-blank")
|
||||
window.location.href = "about:blank";
|
||||
|
||||
else if (data.type === "status-api-success")
|
||||
{
|
||||
if (data.keys == 'WEB3')
|
||||
{
|
||||
ethereumPromise.allowed = true;
|
||||
window.currentAccountAddress = data.data["WEB3"];
|
||||
ethereumPromise.resolve();
|
||||
}
|
||||
else
|
||||
{
|
||||
window.dispatchEvent(new CustomEvent('statusapi', { detail: { permissions: data.keys,
|
||||
data: data.data
|
||||
} }));
|
||||
}
|
||||
}
|
||||
|
||||
else if (data.type === "web3-permission-request-denied")
|
||||
{
|
||||
ethereumPromise.reject(new Error("Denied"));
|
||||
}
|
||||
|
||||
else if (data.type === "web3-send-async-callback")
|
||||
{
|
||||
var id = data.messageId;
|
||||
var callback = callbacks[id];
|
||||
if (callback) {
|
||||
if (callback.results)
|
||||
{
|
||||
callback.results.push(data.error || data.result);
|
||||
if (callback.results.length == callback.num)
|
||||
callback.callback(undefined, callback.results);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback.callback(data.error, data.result);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function web3Response (payload, result){
|
||||
return {id: payload.id,
|
||||
jsonrpc: "2.0",
|
||||
result: result};
|
||||
}
|
||||
|
||||
function getSyncResponse (payload) {
|
||||
console.log("getSyncResponse " + payload.method + " !")
|
||||
if (payload.method == "eth_accounts" && currentAccountAddress){
|
||||
return web3Response(payload, [currentAccountAddress])
|
||||
} else if (payload.method == "eth_coinbase" && currentAccountAddress){
|
||||
return web3Response(payload, currentAccountAddress)
|
||||
} else if (payload.method == "net_version"){
|
||||
return web3Response(payload, networkId)
|
||||
} else if (payload.method == "eth_uninstallFilter"){
|
||||
return web3Response(payload, true);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var ReadOnlyProvider = function () {};
|
||||
|
||||
ReadOnlyProvider.prototype.isConnected = function () { return true; };
|
||||
|
||||
ReadOnlyProvider.prototype.send = function (payload) {
|
||||
if (payload.method == "eth_uninstallFilter"){
|
||||
this.sendAsync(payload, function (res, err) {})
|
||||
}
|
||||
var syncResponse = getSyncResponse(payload);
|
||||
if (syncResponse){
|
||||
return syncResponse;
|
||||
} else {
|
||||
return web3Response(payload, null);
|
||||
}
|
||||
};
|
||||
|
||||
ReadOnlyProvider.prototype.enable = function () {
|
||||
bridgeSend({
|
||||
type: 'status-api-request',
|
||||
permissions: ['WEB3'],
|
||||
host: window.location.hostname
|
||||
});
|
||||
return new Promise(function (resolve, reject) {
|
||||
ethereumPromise.resolve = resolve;
|
||||
ethereumPromise.reject = reject;
|
||||
});
|
||||
};
|
||||
|
||||
ReadOnlyProvider.prototype.sendAsync = function (payload, callback) {
|
||||
|
||||
var syncResponse = getSyncResponse(payload);
|
||||
if (syncResponse && callback){
|
||||
callback(null, syncResponse);
|
||||
}
|
||||
else {
|
||||
var messageId = callbackId++;
|
||||
|
||||
if (Array.isArray(payload))
|
||||
{
|
||||
callbacks[messageId] = {num: payload.length,
|
||||
results: [],
|
||||
callback: callback};
|
||||
for (var i in payload) {
|
||||
bridgeSend({type: 'web3-send-async-read-only',
|
||||
messageId: messageId,
|
||||
payload: payload[i],
|
||||
host: window.location.hostname});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
callbacks[messageId] = {callback: callback};
|
||||
bridgeSend({type: 'web3-send-async-read-only',
|
||||
messageId: messageId,
|
||||
payload: payload,
|
||||
host: window.location.hostname});
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
console.log("ReadOnlyProvider");
|
||||
ethereum = new ReadOnlyProvider();
|
|
@ -1,8 +1,4 @@
|
|||
(function () {
|
||||
function bridgeSend(data){
|
||||
WebViewBridge.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
var history = window.history;
|
||||
var pushState = history.pushState;
|
||||
history.pushState = function(state) {
|
||||
|
@ -14,22 +10,4 @@
|
|||
}, 100);
|
||||
return pushState.apply(history, arguments);
|
||||
};
|
||||
|
||||
window.addEventListener('message', function (event) {
|
||||
if (!event.data || !event.data.type) { return; }
|
||||
if (event.data.type === 'STATUS_API_REQUEST') {
|
||||
bridgeSend({
|
||||
type: 'status-api-request',
|
||||
permissions: event.data.permissions,
|
||||
host: window.location.hostname
|
||||
});
|
||||
}
|
||||
else if (event.data.type === 'ETHEREUM_PROVIDER_REQUEST') {
|
||||
bridgeSend({
|
||||
type: 'status-api-request',
|
||||
permissions: ['WEB3'],
|
||||
host: window.location.hostname
|
||||
});
|
||||
}
|
||||
});
|
||||
}());
|
|
@ -43,3 +43,9 @@
|
|||
(if dev-mode?
|
||||
{:dev-server/start nil}
|
||||
{:dev-server/stop nil})))
|
||||
|
||||
(defn switch-web3-opt-in-mode [opt-in {:keys [db] :as cofx}]
|
||||
(let [settings (get-in db [:account/account :settings])]
|
||||
(accounts.update/update-settings
|
||||
(assoc settings :web3-opt-in? opt-in)
|
||||
cofx)))
|
||||
|
|
|
@ -193,6 +193,8 @@
|
|||
(def ^:const dapp-permission-web3 "WEB3")
|
||||
(def ^:const status-api-success "status-api-success")
|
||||
(def ^:const status-api-request "status-api-request")
|
||||
(def ^:const web3-permission-request-denied "web3-permission-request-denied")
|
||||
(def ^:const history-state-changed "history-state-changed")
|
||||
(def ^:const web3-send-async "web3-send-async")
|
||||
(def ^:const web3-send-async-read-only "web3-send-async-read-only")
|
||||
(def ^:const web3-send-async-callback "web3-send-async-callback")
|
||||
|
|
|
@ -107,6 +107,11 @@
|
|||
(fn [cofx [_ dev-mode?]]
|
||||
(accounts/switch-dev-mode dev-mode? cofx)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:accounts.ui/web3-opt-in-mode-switched
|
||||
(fn [cofx [_ opt-in]]
|
||||
(accounts/switch-web3-opt-in-mode opt-in cofx)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:accounts.ui/wallet-set-up-confirmed
|
||||
(fn [cofx [_ modal?]]
|
||||
|
|
|
@ -123,6 +123,10 @@
|
|||
:keys (keys permissions-allowed)}
|
||||
(:webview-bridge db)])
|
||||
|
||||
(and (zero? (count permissions-allowed)) (= constants/dapp-permission-web3 (first requested-permissions)))
|
||||
(assoc :send-to-bridge-fx [{:type constants/web3-permission-request-denied}
|
||||
(:webview-bridge db)])
|
||||
|
||||
true
|
||||
(assoc :dispatch [:check-permissions-queue]))))
|
||||
|
||||
|
@ -148,6 +152,17 @@
|
|||
:error %1
|
||||
:result %2}])]}))
|
||||
|
||||
(defn web3-send-async-read-only [dapp-name {:keys [method] :as payload} message-id {:keys [db] :as cofx}]
|
||||
(let [{:dapps/keys [permissions]} db]
|
||||
(if (and (#{"eth_accounts" "eth_coinbase" "eth_sendTransaction" "eth_sign"
|
||||
"eth_signTypedData" "personal_sign" "personal_ecRecover"} method)
|
||||
(not (some #{"WEB3"} (get-in permissions [dapp-name :permissions]))))
|
||||
{:dispatch [:send-to-bridge
|
||||
{:type constants/web3-send-async-callback
|
||||
:messageId message-id
|
||||
:error "Denied"}]}
|
||||
(web3-send-async payload message-id cofx))))
|
||||
|
||||
(defn initialize-browsers
|
||||
[{:keys [db all-stored-browsers]}]
|
||||
(let [browsers (into {} (map #(vector (:browser-id %) %) all-stored-browsers))]
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
[status-im.utils.types :as types]
|
||||
[status-im.utils.universal-links.core :as utils.universal-links]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.utils.ethereum.resolver :as resolver]))
|
||||
[status-im.utils.ethereum.resolver :as resolver]
|
||||
[status-im.utils.ethereum.core :as ethereum]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:browse
|
||||
|
@ -127,7 +128,9 @@
|
|||
{:keys [browser-id]} options
|
||||
browser (get browsers browser-id)
|
||||
data (types/json->clj message)
|
||||
{{:keys [url]} :navState :keys [type host permissions payload messageId]} data]
|
||||
{{:keys [url]} :navState :keys [type host permissions payload messageId]} data
|
||||
{:keys [dapp? name]} browser
|
||||
dapp-name (if dapp? name host)]
|
||||
(cond
|
||||
|
||||
(and (= type constants/history-state-changed) platform/ios? (not= "about:blank" url))
|
||||
|
@ -136,12 +139,13 @@
|
|||
(= type constants/web3-send-async)
|
||||
(model/web3-send-async payload messageId cofx)
|
||||
|
||||
(= type constants/web3-send-async-read-only)
|
||||
(model/web3-send-async-read-only dapp-name payload messageId cofx)
|
||||
|
||||
(= type constants/status-api-request)
|
||||
(let [{:keys [dapp? name]} browser
|
||||
dapp-name (if dapp? name host)]
|
||||
{:db (update-in db [:browser/options :permissions-queue] conj {:dapp-name dapp-name
|
||||
:permissions permissions})
|
||||
:dispatch [:check-permissions-queue]})))))
|
||||
:dispatch [:check-permissions-queue]}))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:check-permissions-queue
|
||||
|
@ -158,7 +162,9 @@
|
|||
:index 0
|
||||
:user-permissions (get-in db [:dapps/permissions dapp-name :permissions])
|
||||
:requested-permissions permissions
|
||||
:permissions-data {constants/dapp-permission-contact-code (:public-key account)}})))))))
|
||||
:permissions-data {constants/dapp-permission-contact-code (:public-key account)
|
||||
constants/dapp-permission-web3 (ethereum/normalized-address
|
||||
(:address account))}})))))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:next-dapp-permission
|
||||
|
|
|
@ -114,14 +114,15 @@
|
|||
|
||||
(views/defview browser []
|
||||
(views/letsubs [webview (atom nil)
|
||||
{:keys [address]} [:get-current-account]
|
||||
{:keys [address settings]} [:get-current-account]
|
||||
{:keys [browser-id dapp? name] :as browser} [:get-current-browser]
|
||||
{:keys [error? loading? url-editing? show-tooltip show-permission resolving?]} [:get :browser/options]
|
||||
rpc-url [:get :rpc-url]
|
||||
network-id [:get-network-id]]
|
||||
(let [can-go-back? (model/can-go-back? browser)
|
||||
can-go-forward? (model/can-go-forward? browser)
|
||||
url (model/get-current-url browser)]
|
||||
url (model/get-current-url browser)
|
||||
opt-in? (:web3-opt-in? settings)]
|
||||
[react/view styles/browser
|
||||
[status-bar/status-bar]
|
||||
[toolbar webview error? url browser browser-id url-editing?]
|
||||
|
@ -142,12 +143,14 @@
|
|||
:on-load #(re-frame/dispatch [:update-browser-options {:error? false}])
|
||||
:on-error #(re-frame/dispatch [:update-browser-options {:error? true
|
||||
:loading? false}])
|
||||
:injected-on-start-loading-java-script (str js-res/web3
|
||||
:injected-on-start-loading-java-script (str (not opt-in?) js-res/web3
|
||||
(get-inject-js url)
|
||||
(if opt-in?
|
||||
(js-res/web3-opt-in-init (str network-id))
|
||||
(js-res/web3-init
|
||||
rpc-url
|
||||
(ethereum/normalized-address address)
|
||||
(str network-id)))
|
||||
(str network-id))))
|
||||
:injected-java-script js-res/webview-js}]
|
||||
(when (or loading? resolving?)
|
||||
[react/view styles/web-view-loading
|
||||
|
|
|
@ -136,8 +136,7 @@
|
|||
:hide-arrow? true
|
||||
:action-fn #(re-frame/dispatch [:accounts.logout.ui/logout-pressed])}]]]]))
|
||||
|
||||
(defview advanced-settings [{:keys [network networks dev-mode?]} on-show]
|
||||
(letsubs [{:keys [sharing-usage-data?]} [:get-current-account]]
|
||||
(defview advanced-settings [{:keys [network networks dev-mode? settings]} on-show]
|
||||
{:component-did-mount on-show}
|
||||
[react/view
|
||||
(when (and config/extensions-enabled? dev-mode?)
|
||||
|
@ -173,11 +172,16 @@
|
|||
{:label-kw :t/bootnodes
|
||||
:action-fn #(re-frame/dispatch [:navigate-to :bootnodes-settings])
|
||||
:accessibility-label :bootnodes-settings-button}])
|
||||
(when dev-mode?
|
||||
[profile.components/settings-switch-item
|
||||
{:label-kw :t/web3-opt-in
|
||||
:value (:web3-opt-in? settings)
|
||||
:action-fn #(re-frame/dispatch [:accounts.ui/web3-opt-in-mode-switched %])}])
|
||||
[profile.components/settings-item-separator]
|
||||
[profile.components/settings-switch-item
|
||||
{:label-kw :t/dev-mode
|
||||
:value dev-mode?
|
||||
:action-fn #(re-frame/dispatch [:accounts.ui/dev-mode-switched %])}]]))
|
||||
:action-fn #(re-frame/dispatch [:accounts.ui/dev-mode-switched %])}]])
|
||||
|
||||
(defview advanced [params on-show]
|
||||
(letsubs [advanced? [:get :my-profile/advanced?]]
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
"var networkId = \"" network-id "\";"
|
||||
(slurp "resources/js/web3_init.js")))
|
||||
|
||||
(defn web3-opt-in-init [network-id]
|
||||
(str "var networkId = \"" network-id "\";"
|
||||
(slurp "resources/js/web3_opt_in.js")))
|
||||
|
||||
(defn local-storage-data [data]
|
||||
(str "var localStorageData = " (or data "{}") ";"))
|
||||
|
||||
|
|
|
@ -683,5 +683,6 @@
|
|||
"gwei": "Gwei",
|
||||
"cost-fee": "Cost/Fee",
|
||||
"currency-display-name-usd": "United States Dollar",
|
||||
"currency-display-name-uah": "Ukraine Hryvnia"
|
||||
"currency-display-name-uah": "Ukraine Hryvnia",
|
||||
"web3-opt-in": "Opt-in web3 provider access"
|
||||
}
|
Loading…
Reference in New Issue