diff --git a/components/brave_wallet/common/BUILD.gn b/components/brave_wallet/common/BUILD.gn index e17b1cd4b4b7..e6a6a5cc9bd0 100644 --- a/components/brave_wallet/common/BUILD.gn +++ b/components/brave_wallet/common/BUILD.gn @@ -7,6 +7,17 @@ source_set("common") { "features.cc", "features.h", ] + deps = [ + "//base", + ":common_constants", + ] +} + +source_set("common_constants") { + sources = [ + "web3_provider_constants.cc", + "web3_provider_constants.h", + ] deps = [ ":mojom" ] } diff --git a/components/brave_wallet/common/web3_provider_constants.cc b/components/brave_wallet/common/web3_provider_constants.cc new file mode 100644 index 000000000000..6fa49acc94d9 --- /dev/null +++ b/components/brave_wallet/common/web3_provider_constants.cc @@ -0,0 +1,15 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_wallet/common/web3_provider_constants.h" + +namespace brave_wallet { + +const char kConnectEvent[] = "connect"; +const char kDisconnectEvent[] = "disconnect"; +const char kChainChangedEvent[] = "chainChanged"; +const char kAccountsChangedEvent[] = "accountsChanged"; + +} // namespace brave_wallet diff --git a/components/brave_wallet/renderer/web3_provider_constants.h b/components/brave_wallet/common/web3_provider_constants.h similarity index 70% rename from components/brave_wallet/renderer/web3_provider_constants.h rename to components/brave_wallet/common/web3_provider_constants.h index 688cc6fb6768..8655925f7048 100644 --- a/components/brave_wallet/renderer/web3_provider_constants.h +++ b/components/brave_wallet/common/web3_provider_constants.h @@ -3,11 +3,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef BRAVE_COMPONENTS_BRAVE_WALLET_RENDERER_WEB3_PROVIDER_CONSTANTS_H_ -#define BRAVE_COMPONENTS_BRAVE_WALLET_RENDERER_WEB3_PROVIDER_CONSTANTS_H_ +#ifndef BRAVE_COMPONENTS_BRAVE_WALLET_COMMON_WEB3_PROVIDER_CONSTANTS_H_ +#define BRAVE_COMPONENTS_BRAVE_WALLET_COMMON_WEB3_PROVIDER_CONSTANTS_H_ namespace brave_wallet { +extern const char kConnectEvent[]; +extern const char kDisconnectEvent[]; +extern const char kChainChangedEvent[]; +extern const char kAccountsChangedEvent[]; + enum class ProviderErrors { kUserRejectedRequest = 4001, // User rejected the request kUnauthorized = 4100, // The requested account and/or method has not @@ -21,4 +26,4 @@ enum class ProviderErrors { } // namespace brave_wallet -#endif // BRAVE_COMPONENTS_BRAVE_WALLET_RENDERER_WEB3_PROVIDER_CONSTANTS_H_ +#endif // BRAVE_COMPONENTS_BRAVE_WALLET_COMMON_WEB3_PROVIDER_CONSTANTS_H_ diff --git a/components/brave_wallet/renderer/BUILD.gn b/components/brave_wallet/renderer/BUILD.gn index 14709fd62dca..4d254def75f1 100644 --- a/components/brave_wallet/renderer/BUILD.gn +++ b/components/brave_wallet/renderer/BUILD.gn @@ -4,12 +4,13 @@ source_set("renderer") { "brave_wallet_js_handler.h", "brave_wallet_response_helpers.cc", "brave_wallet_response_helpers.h", - "web3_provider_constants.h", ] deps = [ "//base", + "//brave/components/brave_wallet/common:common_constants", "//brave/components/brave_wallet/common:mojom", + "//brave/components/brave_wallet/resources:ethereum_provider_generated_resources", "//content/public/renderer", "//gin", "//mojo/public/cpp/bindings", diff --git a/components/brave_wallet/renderer/DEPS b/components/brave_wallet/renderer/DEPS index 45b1fb883757..af4ab54a334c 100644 --- a/components/brave_wallet/renderer/DEPS +++ b/components/brave_wallet/renderer/DEPS @@ -3,4 +3,5 @@ include_rules = [ "+gin", "+third_party/blink/public", "+v8/include", + "+ui/base", ] diff --git a/components/brave_wallet/renderer/brave_wallet_js_handler.cc b/components/brave_wallet/renderer/brave_wallet_js_handler.cc index 740aa0fa2f2e..b7efc68d542f 100644 --- a/components/brave_wallet/renderer/brave_wallet_js_handler.cc +++ b/components/brave_wallet/renderer/brave_wallet_js_handler.cc @@ -6,13 +6,16 @@ #include "brave/components/brave_wallet/renderer/brave_wallet_js_handler.h" #include +#include #include "base/json/json_writer.h" #include "base/no_destructor.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "brave/components/brave_wallet/common/web3_provider_constants.h" #include "brave/components/brave_wallet/renderer/brave_wallet_response_helpers.h" -#include "brave/components/brave_wallet/renderer/web3_provider_constants.h" +#include "brave/components/brave_wallet/resources/grit/brave_wallet_script_generated.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/v8_value_converter.h" #include "gin/arguments.h" @@ -21,12 +24,75 @@ #include "third_party/blink/public/web/blink.h" #include "third_party/blink/public/web/web_local_frame.h" #include "third_party/blink/public/web/web_script_source.h" +#include "ui/base/resource/resource_bundle.h" +namespace { + +static base::NoDestructor g_provider_script(""); + +// Hardcode id to 1 as it is unused +const uint32_t kRequestId = 1; +const char kRequestJsonRPC[] = "2.0"; + +std::string LoadDataResource(const int id) { + auto& resource_bundle = ui::ResourceBundle::GetSharedInstance(); + if (resource_bundle.IsGzipped(id)) { + return resource_bundle.LoadDataResourceString(id); + } + + return resource_bundle.GetRawDataResource(id).as_string(); +} + +v8::MaybeLocal GetProperty(v8::Local context, + v8::Local object, + const std::u16string& name) { + v8::Isolate* isolate = context->GetIsolate(); + v8::Local name_str = + gin::ConvertToV8(isolate, name).As(); + v8::Local object_obj; + if (!object->ToObject(context).ToLocal(&object_obj)) { + return v8::MaybeLocal(); + } + + return object_obj->Get(context, name_str); +} + +void CallMethodOfObject(blink::WebLocalFrame* web_frame, + const std::u16string& object_name, + const std::u16string& method_name, + base::Value arguments) { + if (web_frame->IsProvisional()) + return; + v8::Local context = web_frame->MainWorldScriptContext(); + v8::Context::Scope context_scope(context); + v8::Local object; + v8::Local method; + if (!GetProperty(context, context->Global(), object_name).ToLocal(&object) || + !GetProperty(context, object, method_name).ToLocal(&method)) { + return; + } + std::vector> args; + for (auto const& argument : arguments.GetList()) { + args.push_back(content::V8ValueConverter::Create()->ToV8Value(&argument, + context)); + } + + web_frame->ExecuteMethodAndReturnValue( + v8::Local::Cast(method), object, + static_cast(args.size()), args.data()).ToLocalChecked(); +} + +} // namespace namespace brave_wallet { BraveWalletJSHandler::BraveWalletJSHandler(content::RenderFrame* render_frame) - : render_frame_(render_frame) {} + : render_frame_(render_frame) { + if (g_provider_script->empty()) { + *g_provider_script = + LoadDataResource(IDR_BRAVE_WALLET_SCRIPT_BRAVE_WALLET_SCRIPT_BUNDLE_JS); + } +} BraveWalletJSHandler::~BraveWalletJSHandler() = default; @@ -49,6 +115,7 @@ void BraveWalletJSHandler::AddJavaScriptObjectToFrame( v8::Context::Scope context_scope(context); CreateEthereumObject(isolate, context); + InjectInitScript(); } void BraveWalletJSHandler::CreateEthereumObject( @@ -107,6 +174,9 @@ v8::Local BraveWalletJSHandler::Request( if (!out || !out->is_dict() || !out->GetAsDictionary(&out_dict)) return v8::Local(); + // Hardcode id to 1 as it is unused + ALLOW_UNUSED_LOCAL(out_dict->SetIntPath("id", kRequestId)); + ALLOW_UNUSED_LOCAL(out_dict->SetStringPath("jsonrpc", kRequestJsonRPC)); std::string formed_input; if (!base::JSONWriter::Write(*out_dict, &formed_input)) return v8::Local(); @@ -165,4 +235,43 @@ void BraveWalletJSHandler::OnRequest( } } +void BraveWalletJSHandler::ExecuteScript(const std::string script) { + blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame(); + if (web_frame->IsProvisional()) + return; + + web_frame->ExecuteScript(blink::WebString::FromUTF8(script)); +} + +void BraveWalletJSHandler::InjectInitScript() { + ExecuteScript(*g_provider_script); +} + +void BraveWalletJSHandler::FireEvent(const std::string& event, + const std::string& event_args) { + base::Value args = base::Value(base::Value::Type::LIST); + args.Append(event); + args.Append(event_args); + CallMethodOfObject(render_frame_->GetWebFrame(), + u"ethereum", + u"emit", + std::move(args)); +} + +void BraveWalletJSHandler::ConnectEvent(const std::string& chain_id) { + FireEvent(kConnectEvent, chain_id); +} + +void BraveWalletJSHandler::DisconnectEvent(const std::string& message) { + FireEvent(kDisconnectEvent, message); +} + +void BraveWalletJSHandler::ChainChangedEvent(const std::string& chain_id) { + FireEvent(kChainChangedEvent, chain_id); +} + +void BraveWalletJSHandler::AccountsChangedEvent(const std::string& accounts) { + FireEvent(kAccountsChangedEvent, accounts); +} + } // namespace brave_wallet diff --git a/components/brave_wallet/renderer/brave_wallet_js_handler.h b/components/brave_wallet/renderer/brave_wallet_js_handler.h index f6f6fc7977d5..8e2639f84cd9 100644 --- a/components/brave_wallet/renderer/brave_wallet_js_handler.h +++ b/components/brave_wallet/renderer/brave_wallet_js_handler.h @@ -22,6 +22,11 @@ class BraveWalletJSHandler { ~BraveWalletJSHandler(); void AddJavaScriptObjectToFrame(v8::Local context); + void FireEvent(const std::string& event, const std::string& event_args); + void ConnectEvent(const std::string& chain_id); + void DisconnectEvent(const std::string& message); + void ChainChangedEvent(const std::string& chain_id); + void AccountsChangedEvent(const std::string& accounts); private: void BindFunctionsToObject(v8::Isolate* isolate, @@ -37,6 +42,8 @@ class BraveWalletJSHandler { void CreateEthereumObject(v8::Isolate* isolate, v8::Local context); bool EnsureConnected(); + void InjectInitScript(); + void ExecuteScript(const std::string script); // A function to be called from JS v8::Local Request(v8::Isolate* isolate, diff --git a/components/brave_wallet/renderer/brave_wallet_response_helpers.cc b/components/brave_wallet/renderer/brave_wallet_response_helpers.cc index 16bc362ae897..efdab6700b31 100644 --- a/components/brave_wallet/renderer/brave_wallet_response_helpers.cc +++ b/components/brave_wallet/renderer/brave_wallet_response_helpers.cc @@ -8,6 +8,7 @@ #include #include "base/json/json_reader.h" +#include "base/json/json_writer.h" namespace brave_wallet { @@ -53,4 +54,33 @@ std::unique_ptr FormProviderResponse( return base::Value::ToUniquePtrValue(result->Clone()); } +std::string FormProviderErrorResponse(const std::string& controller_response) { + base::JSONReader::ValueWithError value_with_error = + base::JSONReader::ReadAndReturnValueWithError( + controller_response, base::JSONParserOptions::JSON_PARSE_RFC); + base::Optional& response = value_with_error.value; + + if (response) { + const base::Value* error = response->FindKey("error"); + if (error) { + std::string error_response; + if (!base::JSONWriter::Write(*error, &error_response)) + return ""; + + return error_response; + } + } + + ProviderErrors code = ProviderErrors::kUnsupportedMethod; + std::string message = + "Invalid response, could not parse JSON: " + controller_response; + + std::string error_response; + if (!base::JSONWriter::Write(*FormProviderResponse(code, message), + &error_response)) + return ""; + + return error_response; +} + } // namespace brave_wallet diff --git a/components/brave_wallet/renderer/brave_wallet_response_helpers.h b/components/brave_wallet/renderer/brave_wallet_response_helpers.h index 3c72b7017df8..d5370274c9a6 100644 --- a/components/brave_wallet/renderer/brave_wallet_response_helpers.h +++ b/components/brave_wallet/renderer/brave_wallet_response_helpers.h @@ -10,7 +10,7 @@ #include #include "base/values.h" -#include "brave/components/brave_wallet/renderer/web3_provider_constants.h" +#include "brave/components/brave_wallet/common/web3_provider_constants.h" namespace brave_wallet { @@ -19,6 +19,7 @@ std::unique_ptr FormProviderResponse(ProviderErrors code, std::unique_ptr FormProviderResponse( const std::string& controller_response, bool* reject); +std::string FormProviderErrorResponse(const std::string& controller_response); } // namespace brave_wallet diff --git a/components/brave_wallet/resources/BUILD.gn b/components/brave_wallet/resources/BUILD.gn new file mode 100644 index 000000000000..c817a6cea9b7 --- /dev/null +++ b/components/brave_wallet/resources/BUILD.gn @@ -0,0 +1,18 @@ +import("//brave/components/common/typescript.gni") +import("//tools/grit/grit_rule.gni") +import("//tools/grit/repack.gni") + +transpile_web_ui("brave_wallet_script_resources") { + entry_points = [ [ + "brave_wallet_script", + rebase_path("brave_wallet_provider.js"), + ] ] + + resource_name = "brave_wallet_script" +} + +pack_web_resources("ethereum_provider_generated_resources") { + resource_name = "brave_wallet_script" + output_dir = "$root_gen_dir/brave/components/brave_wallet/resources" + deps = [ ":brave_wallet_script_resources" ] +} diff --git a/components/brave_wallet/resources/brave_wallet_provider.js b/components/brave_wallet/resources/brave_wallet_provider.js new file mode 100644 index 000000000000..601cd3075bc3 --- /dev/null +++ b/components/brave_wallet/resources/brave_wallet_provider.js @@ -0,0 +1,16 @@ +// Copyright (c) 2021 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// you can obtain one at http://mozilla.org/MPL/2.0/. + +(function() { + if (!window.ethereum) { + return + } + var EventEmitter = require('events') + var BraveWeb3ProviderEventEmitter = new EventEmitter() + window.ethereum.on = BraveWeb3ProviderEventEmitter.on + window.ethereum.emit = BraveWeb3ProviderEventEmitter.emit + window.ethereum.removeListener = + BraveWeb3ProviderEventEmitter.removeListener +})() diff --git a/components/resources/BUILD.gn b/components/resources/BUILD.gn index a3a19e4ebdfc..0bc62f1ed0b4 100644 --- a/components/resources/BUILD.gn +++ b/components/resources/BUILD.gn @@ -89,11 +89,14 @@ repack("resources") { ] } - if (brave_wallet_enabled && !is_android) { - deps += [ "//brave/components/brave_wallet_ui:resources" ] - sources += [ - "$root_gen_dir/brave/components/brave_wallet/resources/brave_wallet.pak", - ] + if (brave_wallet_enabled) { + if (!is_android) { + deps += [ "//brave/components/brave_wallet_ui:resources" ] + sources += [ "$root_gen_dir/brave/components/brave_wallet/resources/brave_wallet.pak" ] + } + + deps += [ "//brave/components/brave_wallet/resources:ethereum_provider_generated_resources" ] + sources += [ "$root_gen_dir/brave/components/brave_wallet/resources/brave_wallet_script_generated.pak" ] } output = "$root_gen_dir/components/brave_components_resources.pak"