diff --git a/components/brave_wallet/renderer/js_ethereum_provider.cc b/components/brave_wallet/renderer/js_ethereum_provider.cc index dbc284f77db1..bbd963b42b46 100644 --- a/components/brave_wallet/renderer/js_ethereum_provider.cc +++ b/components/brave_wallet/renderer/js_ethereum_provider.cc @@ -64,22 +64,6 @@ constexpr char kIsUnlocked[] = "isUnlocked"; namespace brave_wallet { -void JSEthereumProvider::OnIsUnlocked( - v8::Global global_context, - v8::Global promise_resolver, - v8::Isolate* isolate, - bool locked) { - v8::HandleScope handle_scope(isolate); - v8::Local resolver = promise_resolver.Get(isolate); - v8::Local context = global_context.Get(isolate); - v8::MicrotasksScope microtasks(isolate, context->GetMicrotaskQueue(), - v8::MicrotasksScope::kDoNotRunMicrotasks); - base::Value result = base::Value(!locked); - v8::Local local_result = - content::V8ValueConverter::Create()->ToV8Value(result, context); - std::ignore = resolver->Resolve(context, local_result); -} - void JSEthereumProvider::SendResponse( base::Value id, v8::Global global_context, @@ -234,26 +218,6 @@ void JSEthereumProvider::Install(bool allow_overwrite_window_ethereum_provider, SetOwnPropertyWritable(context, provider_object, gin::StringToV8(isolate, kIsMetaMask), true); - // Set non-writable _metamask obj with non-writable isUnlocked method. - v8::Local metamask_value; - v8::Local metamask_obj = v8::Object::New(isolate); - provider_object - ->Set(context, gin::StringToSymbol(isolate, kMetaMask), metamask_obj) - .Check(); - SetOwnPropertyWritable(context, provider_object, - gin::StringToV8(isolate, kMetaMask), false); - - metamask_obj - ->Set(context, gin::StringToSymbol(isolate, kIsUnlocked), - gin::CreateFunctionTemplate( - isolate, base::BindRepeating(&JSEthereumProvider::IsUnlocked, - base::Unretained(provider.get()))) - ->GetFunction(context) - .ToLocalChecked()) - .Check(); - SetOwnPropertyWritable(context, metamask_obj, - gin::StringToV8(isolate, kIsUnlocked), false); - ExecuteScript(web_frame, LoadDataResource( IDR_BRAVE_WALLET_SCRIPT_ETHEREUM_PROVIDER_SCRIPT_BUNDLE_JS), @@ -268,6 +232,78 @@ bool JSEthereumProvider::GetIsMetaMask() { return true; } +gin::WrapperInfo JSEthereumProvider::MetaMask::kWrapperInfo = { + gin::kEmbedderNativeGin}; + +JSEthereumProvider::MetaMask::MetaMask(content::RenderFrame* render_frame) + : render_frame_(render_frame) {} +JSEthereumProvider::MetaMask::~MetaMask() = default; + +gin::ObjectTemplateBuilder +JSEthereumProvider::MetaMask::GetObjectTemplateBuilder(v8::Isolate* isolate) { + return gin::Wrappable::GetObjectTemplateBuilder(isolate).SetMethod( + kIsUnlocked, &JSEthereumProvider::MetaMask::IsUnlocked); +} + +const char* JSEthereumProvider::MetaMask::GetTypeName() { + return kMetaMask; +} + +v8::Local JSEthereumProvider::MetaMask::IsUnlocked( + v8::Isolate* isolate) { + if (!ethereum_provider_.is_bound()) { + render_frame_->GetBrowserInterfaceBroker()->GetInterface( + ethereum_provider_.BindNewPipeAndPassReceiver()); + } + + v8::MaybeLocal resolver = + v8::Promise::Resolver::New(isolate->GetCurrentContext()); + if (resolver.IsEmpty()) { + return v8::Local(); + } + + auto global_context( + v8::Global(isolate, isolate->GetCurrentContext())); + auto promise_resolver( + v8::Global(isolate, resolver.ToLocalChecked())); + auto context(v8::Global(isolate, isolate->GetCurrentContext())); + ethereum_provider_->IsLocked(base::BindOnce( + &JSEthereumProvider::MetaMask::OnIsUnlocked, base::Unretained(this), + std::move(global_context), std::move(promise_resolver), isolate)); + + return resolver.ToLocalChecked()->GetPromise(); +} + +void JSEthereumProvider::MetaMask::OnIsUnlocked( + v8::Global global_context, + v8::Global promise_resolver, + v8::Isolate* isolate, + bool locked) { + v8::HandleScope handle_scope(isolate); + v8::Local resolver = promise_resolver.Get(isolate); + v8::Local context = global_context.Get(isolate); + v8::MicrotasksScope microtasks(isolate, context->GetMicrotaskQueue(), + v8::MicrotasksScope::kDoNotRunMicrotasks); + base::Value result = base::Value(!locked); + v8::Local local_result = + content::V8ValueConverter::Create()->ToV8Value(result, context); + std::ignore = resolver->Resolve(context, local_result); +} + +v8::Local JSEthereumProvider::GetMetaMask(v8::Isolate* isolate) { + // Set non-writable _metamask obj with non-writable isUnlocked method. + gin::Handle metamask = + gin::CreateHandle(isolate, new MetaMask(render_frame())); + if (metamask.IsEmpty()) { + return v8::Undefined(isolate); + } + v8::Local metamask_value = metamask.ToV8(); + SetOwnPropertyWritable(isolate->GetCurrentContext(), + metamask_value.As(), + gin::StringToV8(isolate, kIsUnlocked), false); + return metamask_value; +} + std::string JSEthereumProvider::GetChainId() { return chain_id_; } @@ -304,6 +340,7 @@ gin::ObjectTemplateBuilder JSEthereumProvider::GetObjectTemplateBuilder( return gin::Wrappable::GetObjectTemplateBuilder(isolate) .SetProperty(kIsBraveWallet, &JSEthereumProvider::GetIsBraveWallet) .SetProperty(kIsMetaMask, &JSEthereumProvider::GetIsMetaMask) + .SetProperty(kMetaMask, &JSEthereumProvider::GetMetaMask) .SetProperty("chainId", &JSEthereumProvider::GetChainId) .SetProperty("networkVersion", &JSEthereumProvider::GetNetworkVersion) .SetProperty("selectedAddress", &JSEthereumProvider::GetSelectedAddress) @@ -529,29 +566,6 @@ v8::Local JSEthereumProvider::Enable(v8::Isolate* isolate) { return resolver.ToLocalChecked()->GetPromise(); } -v8::Local JSEthereumProvider::IsUnlocked(v8::Isolate* isolate) { - if (!EnsureConnected()) { - return v8::Local(); - } - - v8::MaybeLocal resolver = - v8::Promise::Resolver::New(isolate->GetCurrentContext()); - if (resolver.IsEmpty()) { - return v8::Local(); - } - - auto global_context( - v8::Global(isolate, isolate->GetCurrentContext())); - auto promise_resolver( - v8::Global(isolate, resolver.ToLocalChecked())); - auto context(v8::Global(isolate, isolate->GetCurrentContext())); - ethereum_provider_->IsLocked(base::BindOnce( - &JSEthereumProvider::OnIsUnlocked, weak_ptr_factory_.GetWeakPtr(), - std::move(global_context), std::move(promise_resolver), isolate)); - - return resolver.ToLocalChecked()->GetPromise(); -} - void JSEthereumProvider::FireEvent(const std::string& event, base::ValueView event_args) { if (!render_frame()) { diff --git a/components/brave_wallet/renderer/js_ethereum_provider.h b/components/brave_wallet/renderer/js_ethereum_provider.h index 457affbde2df..dbd49705b7a9 100644 --- a/components/brave_wallet/renderer/js_ethereum_provider.h +++ b/components/brave_wallet/renderer/js_ethereum_provider.h @@ -51,6 +51,30 @@ class JSEthereumProvider final : public gin::Wrappable, explicit JSEthereumProvider(content::RenderFrame* render_frame); ~JSEthereumProvider() override; + class MetaMask final : public gin::Wrappable { + public: + static gin::WrapperInfo kWrapperInfo; + + explicit MetaMask(content::RenderFrame*); + ~MetaMask() override; + MetaMask(const MetaMask&) = delete; + MetaMask& operator=(const MetaMask&) = delete; + + // gin::WrappableBase + gin::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) override; + const char* GetTypeName() override; + v8::Local IsUnlocked(v8::Isolate* isolate); + + private: + void OnIsUnlocked(v8::Global global_context, + v8::Global promise_resolver, + v8::Isolate* isolate, + bool locked); + raw_ptr render_frame_; + mojo::Remote ethereum_provider_; + }; + // content::RenderFrameObserver void OnDestruct() override {} void WillReleaseScriptContext(v8::Local, @@ -66,6 +90,7 @@ class JSEthereumProvider final : public gin::Wrappable, bool GetIsBraveWallet(); bool GetIsMetaMask(); + v8::Local GetMetaMask(v8::Isolate* isolate); std::string GetChainId(); v8::Local GetNetworkVersion(v8::Isolate* isolate); v8::Local GetSelectedAddress(v8::Isolate* isolate); @@ -75,7 +100,6 @@ class JSEthereumProvider final : public gin::Wrappable, v8::Local input); bool IsConnected(); v8::Local Enable(v8::Isolate* isolate); - v8::Local IsUnlocked(v8::Isolate* isolate); v8::Local SendMethod(gin::Arguments* args); void SendAsync(gin::Arguments* args); @@ -89,10 +113,6 @@ class JSEthereumProvider final : public gin::Wrappable, const std::string& first_allowed_account, const bool update_bind_js_properties); - void OnIsUnlocked(v8::Global global_context, - v8::Global promise_resolver, - v8::Isolate* isolate, - bool locked); void SendResponse(base::Value id, v8::Global global_context, std::unique_ptr> callback,