From 3d572cf155fe00375406a5e38a979db13ec08b0b Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 23 Oct 2025 07:07:01 +0700 Subject: [PATCH 1/2] Add SIWE login async task and improve OAuth browser flow Introduces UAsyncTaskThirdwebLoginWithSiwe for high-level SIWE login handling, including browser widget orchestration and authentication flow. Refactors OAuth browser and external browser classes to support SIWE, corrects parameter order and provider string casing, and improves resource cleanup and thread safety. Increases HTTP request timeout to 15 seconds and updates relevant delegate signatures and logic for SIWE payload/signature handling. --- .../InApp/AsyncTaskThirdwebLoginWithSiwe.cpp | 68 ++++ .../ThirdwebOAuthBrowserUserWidget.cpp | 305 ++++++++--------- .../Browser/ThirdwebOAuthExternalBrowser.cpp | 309 +++++++++--------- Source/Thirdweb/Private/ThirdwebUtils.cpp | 2 +- .../Wallets/ThirdwebInAppWalletHandle.cpp | 6 +- .../InApp/AsyncTaskThirdwebLoginWithSiwe.h | 48 +++ .../Browser/ThirdwebOAuthBrowserUserWidget.h | 12 +- .../Browser/ThirdwebOAuthExternalBrowser.h | 27 +- .../Wallets/ThirdwebInAppWalletHandle.h | 2 +- 9 files changed, 458 insertions(+), 321 deletions(-) create mode 100644 Source/Thirdweb/Private/AsyncTasks/Wallets/InApp/AsyncTaskThirdwebLoginWithSiwe.cpp create mode 100644 Source/Thirdweb/Public/AsyncTasks/Wallets/InApp/AsyncTaskThirdwebLoginWithSiwe.h diff --git a/Source/Thirdweb/Private/AsyncTasks/Wallets/InApp/AsyncTaskThirdwebLoginWithSiwe.cpp b/Source/Thirdweb/Private/AsyncTasks/Wallets/InApp/AsyncTaskThirdwebLoginWithSiwe.cpp new file mode 100644 index 0000000..7639a14 --- /dev/null +++ b/Source/Thirdweb/Private/AsyncTasks/Wallets/InApp/AsyncTaskThirdwebLoginWithSiwe.cpp @@ -0,0 +1,68 @@ +// Copyright (c) 2025 Thirdweb. All Rights Reserved. + +#include "AsyncTasks/Wallets/InApp/AsyncTaskThirdwebLoginWithSiwe.h" + +#include "Async/TaskGraphInterfaces.h" +#include "Blueprint/UserWidget.h" +#include "Browser/ThirdwebOAuthBrowserUserWidget.h" +#include "Engine/World.h" +#include "Kismet/GameplayStatics.h" +#include "ThirdwebLog.h" + +void UAsyncTaskThirdwebLoginWithSiwe::Activate() { + Browser->OnSiweComplete.AddDynamic(this, &ThisClass::HandleSiweComplete); + Browser->OnError.AddDynamic(this, &ThisClass::HandleFailed); + Browser->AddToViewport(10000); + Browser->Authenticate(Wallet); +} + +UAsyncTaskThirdwebLoginWithSiwe *UAsyncTaskThirdwebLoginWithSiwe::LoginWithSiwe( + UObject *WorldContextObject, const FInAppWalletHandle &Wallet) { + if (!WorldContextObject) { + return nullptr; + } + NEW_TASK + Task->Wallet = Wallet; + Task->Browser = CreateWidget( + UGameplayStatics::GetGameInstance(WorldContextObject), + UThirdwebOAuthBrowserUserWidget::StaticClass()); + Task->RegisterWithGameInstance(WorldContextObject); + return Task; +} + +void UAsyncTaskThirdwebLoginWithSiwe::HandleSiweComplete( + const FString &Payload, const FString &Signature) { + if (IsInGameThread()) { + Success.Broadcast(Payload, Signature); + Browser->RemoveFromParent(); + SetReadyToDestroy(); + } else { + // Retry on the GameThread. + TWeakObjectPtr WeakThis = this; + FFunctionGraphTask::CreateAndDispatchWhenReady( + [WeakThis, Payload, Signature]() { + if (WeakThis.IsValid()) { + WeakThis->HandleSiweComplete(Payload, Signature); + } + }, + TStatId(), nullptr, ENamedThreads::GameThread); + } +} + +void UAsyncTaskThirdwebLoginWithSiwe::HandleFailed(const FString &Error) { + if (IsInGameThread()) { + Browser->RemoveFromParent(); + Failed.Broadcast(Error); + SetReadyToDestroy(); + } else { + // Retry on the GameThread. + TWeakObjectPtr WeakThis = this; + FFunctionGraphTask::CreateAndDispatchWhenReady( + [WeakThis, Error]() { + if (WeakThis.IsValid()) { + WeakThis->HandleFailed(Error); + } + }, + TStatId(), nullptr, ENamedThreads::GameThread); + } +} diff --git a/Source/Thirdweb/Private/Browser/ThirdwebOAuthBrowserUserWidget.cpp b/Source/Thirdweb/Private/Browser/ThirdwebOAuthBrowserUserWidget.cpp index f65b26f..e2e680f 100644 --- a/Source/Thirdweb/Private/Browser/ThirdwebOAuthBrowserUserWidget.cpp +++ b/Source/Thirdweb/Private/Browser/ThirdwebOAuthBrowserUserWidget.cpp @@ -2,208 +2,217 @@ #include "Browser/ThirdwebOAuthBrowserUserWidget.h" -#include "ThirdwebLog.h" -#include "ThirdwebRuntimeSettings.h" +#include "Async/TaskGraphInterfaces.h" #include "Blueprint/WidgetTree.h" #include "Browser/ThirdwebOAuthExternalBrowser.h" #include "Components/Overlay.h" #include "Components/OverlaySlot.h" #include "Components/PanelWidget.h" +#include "ThirdwebLog.h" +#include "ThirdwebRuntimeSettings.h" #if PLATFORM_ANDROID #include "Android/AndroidApplication.h" #include "Browser/Android/ThirdwebAndroidJNI.h" #endif -const FString UThirdwebOAuthBrowserUserWidget::BackendUrlPrefix = TEXT("https://embedded-wallet.thirdweb.com/"); -const FString UThirdwebOAuthBrowserUserWidget::DummyUrl = TEXT("http://localhost:8789/callback"); - -TSharedRef UThirdwebOAuthBrowserUserWidget::RebuildWidget() -{ - // RebuildWidget is not called until the widget is first added to the - // viewport. - - UPanelWidget* RootWidget = Cast(GetRootWidget()); - - // Construct root widget if needed - if (!RootWidget) - { - RootWidget = WidgetTree->ConstructWidget(UOverlay::StaticClass(), TEXT("RootWidget")); - WidgetTree->RootWidget = RootWidget; - } - - // Construct children - if (RootWidget) - { - // Construct External browser - ExternalBrowser = NewObject(this); - ExternalBrowser->OnAuthenticated.BindUObject(this, &ThisClass::HandleAuthenticated); - ExternalBrowser->OnError.BindUObject(this, &ThisClass::HandleError); - ExternalBrowser->OnSiweComplete.BindUObject(this, &ThisClass::HandleSiweComplete); - } - - return Super::RebuildWidget(); +const FString UThirdwebOAuthBrowserUserWidget::BackendUrlPrefix = + TEXT("https://embedded-wallet.thirdweb.com/"); +const FString UThirdwebOAuthBrowserUserWidget::DummyUrl = + TEXT("http://localhost:8789/callback"); + +TSharedRef UThirdwebOAuthBrowserUserWidget::RebuildWidget() { + // RebuildWidget is not called until the widget is first added to the + // viewport. + + UPanelWidget *RootWidget = Cast(GetRootWidget()); + + // Construct root widget if needed + if (!RootWidget) { + RootWidget = WidgetTree->ConstructWidget(UOverlay::StaticClass(), + TEXT("RootWidget")); + WidgetTree->RootWidget = RootWidget; + } + + // Construct children + if (RootWidget) { + // Construct External browser + ExternalBrowser = NewObject(this); + ExternalBrowser->OnAuthenticated.BindUObject( + this, &ThisClass::HandleAuthenticated); + ExternalBrowser->OnError.BindUObject(this, &ThisClass::HandleError); + ExternalBrowser->OnSiweComplete.BindUObject(this, + &ThisClass::HandleSiweComplete); + } + + return Super::RebuildWidget(); } #if WITH_EDITOR -const FText UThirdwebOAuthBrowserUserWidget::GetPaletteCategory() -{ - return NSLOCTEXT("Thirdweb", "Thirdweb", "Thirdweb"); +const FText UThirdwebOAuthBrowserUserWidget::GetPaletteCategory() { + return NSLOCTEXT("Thirdweb", "Thirdweb", "Thirdweb"); } #endif -void UThirdwebOAuthBrowserUserWidget::OnWidgetRebuilt() -{ - Super::OnWidgetRebuilt(); - SetVisible(false); +void UThirdwebOAuthBrowserUserWidget::OnWidgetRebuilt() { + Super::OnWidgetRebuilt(); + SetVisible(false); } -void UThirdwebOAuthBrowserUserWidget::BeginDestroy() -{ - if (ExternalBrowser) - { - ExternalBrowser->ConditionalBeginDestroy(); - } - Super::BeginDestroy(); +void UThirdwebOAuthBrowserUserWidget::BeginDestroy() { + if (ExternalBrowser) { + ExternalBrowser->ConditionalBeginDestroy(); + } + Super::BeginDestroy(); } -FString UThirdwebOAuthBrowserUserWidget::GetDummyUrl() -{ +FString UThirdwebOAuthBrowserUserWidget::GetDummyUrl() { #if PLATFORM_ANDROID - return UThirdwebRuntimeSettings::GetAppUri(); + return UThirdwebRuntimeSettings::GetAppUri(); #else - return DummyUrl; + return DummyUrl; #endif } -void UThirdwebOAuthBrowserUserWidget::Authenticate(const FInAppWalletHandle& InAppWallet) -{ - // Validate Wallet - if (!InAppWallet.IsValid()) - { - TW_LOG(Error, TEXT("OAuthBrowserUserWidget::Authenticate::Wallet invalid")); - return HandleError(TEXT("Invalid Wallet")); - } - Wallet = InAppWallet; - TW_LOG(VeryVerbose, TEXT("OAuthBrowserUserWidget::Authenticate::Wallet Type::%s"), Wallet.GetSourceString()); - if (Wallet == FInAppWalletHandle::Siwe) - { - TW_LOG(VeryVerbose, TEXT("OAuthBrowserUserWidget::Authenticate::Authenticating against SIWE")); - ExternalBrowser->Authenticate(TEXT("SIWE")); - return; - } - - // Get Login URL - FString Link; - if (FString Error; !Wallet.FetchOAuthLoginURL(GetDummyUrl(), Link, Error)) - { - return HandleError(Error); - } - TW_LOG(VeryVerbose, TEXT("OAuthBrowserUserWidget::Authenticate::Authenticating against %s"), *Link); +void UThirdwebOAuthBrowserUserWidget::Authenticate( + const FInAppWalletHandle &InAppWallet) { + // Validate Wallet + if (!InAppWallet.IsValid()) { + TW_LOG(Error, TEXT("OAuthBrowserUserWidget::Authenticate::Wallet invalid")); + return HandleError(TEXT("Invalid Wallet")); + } + Wallet = InAppWallet; + TW_LOG(VeryVerbose, + TEXT("OAuthBrowserUserWidget::Authenticate::Wallet Type::%s"), + Wallet.GetSourceString()); + if (Wallet == FInAppWalletHandle::Siwe) { + TW_LOG(VeryVerbose, TEXT("OAuthBrowserUserWidget::Authenticate::" + "Authenticating against %s"), Wallet.GetSourceString()); + ExternalBrowser->Authenticate(Wallet.GetSourceString()); + return; + } + + // Get Login URL + FString Link; + if (FString Error; !Wallet.FetchOAuthLoginURL(GetDummyUrl(), Link, Error)) { + return HandleError(Error); + } + TW_LOG( + VeryVerbose, + TEXT("OAuthBrowserUserWidget::Authenticate::Authenticating against %s"), + *Link); #if PLATFORM_ANDROID - if (JNIEnv *Env = FAndroidApplication::GetJavaEnv()) - { - jstring JUrl = Env->NewStringUTF(TCHAR_TO_UTF8(*Link)); - jclass JClass = FAndroidApplication::FindJavaClass("com/thirdweb/unrealengine/ThirdwebActivity"); - static jmethodID JLaunchUrl = FJavaWrapper::FindStaticMethod(Env, JClass, "startActivity", "(Landroid/app/Activity;Ljava/lang/String;)V", false); - ThirdwebUtils::Internal::Android::CallJniStaticVoidMethod(Env, JClass, JLaunchUrl, FJavaWrapper::GameActivityThis, JUrl); - TW_LOG(Verbose, TEXT("OAuthBrowserUserWidget::Authenticate::Opening CustomTabs")); - return; - } - TW_LOG(Error, TEXT("OAuthBrowserUserWidget::Authenticate::No JNIEnv found")); - return; + if (JNIEnv *Env = FAndroidApplication::GetJavaEnv()) { + jstring JUrl = Env->NewStringUTF(TCHAR_TO_UTF8(*Link)); + jclass JClass = FAndroidApplication::FindJavaClass( + "com/thirdweb/unrealengine/ThirdwebActivity"); + static jmethodID JLaunchUrl = FJavaWrapper::FindStaticMethod( + Env, JClass, "startActivity", + "(Landroid/app/Activity;Ljava/lang/String;)V", false); + ThirdwebUtils::Internal::Android::CallJniStaticVoidMethod( + Env, JClass, JLaunchUrl, FJavaWrapper::GameActivityThis, JUrl); + TW_LOG(Verbose, + TEXT("OAuthBrowserUserWidget::Authenticate::Opening CustomTabs")); + return; + } + TW_LOG(Error, TEXT("OAuthBrowserUserWidget::Authenticate::No JNIEnv found")); + return; #endif - return ExternalBrowser->Authenticate(Link); + return ExternalBrowser->Authenticate(Link); } -void UThirdwebOAuthBrowserUserWidget::HandleUrlChanged(const FString& Url) -{ - TW_LOG(Verbose, TEXT("OAuthBrowserUserWidget::HandleUrlChanged::%s"), *Url); - if (Url.IsEmpty() || (Url.StartsWith(BackendUrlPrefix) && !Url.StartsWith(BackendUrlPrefix + TEXT("sdk/oauth")))) - { - return SetVisible(false); - } - if (Url.StartsWith(GetDummyUrl())) - { - SetVisible(false); - FString Left, Right; - if (Url.Split(TEXT("authResult="), &Left, &Right, ESearchCase::IgnoreCase)) - { - return HandleAuthenticated(Right); - } - return HandleError(TEXT("Failed to match AuthResult in url")); - } - bShouldBeVisible = true; +void UThirdwebOAuthBrowserUserWidget::HandleUrlChanged(const FString &Url) { + TW_LOG(Verbose, TEXT("OAuthBrowserUserWidget::HandleUrlChanged::%s"), *Url); + if (Url.IsEmpty() || + (Url.StartsWith(BackendUrlPrefix) && + !Url.StartsWith(BackendUrlPrefix + TEXT("sdk/oauth")))) { + return SetVisible(false); + } + if (Url.StartsWith(GetDummyUrl())) { + SetVisible(false); + FString Left, Right; + if (Url.Split(TEXT("authResult="), &Left, &Right, + ESearchCase::IgnoreCase)) { + return HandleAuthenticated(Right); + } + return HandleError(TEXT("Failed to match AuthResult in url")); + } + bShouldBeVisible = true; } -void UThirdwebOAuthBrowserUserWidget::HandlePageLoaded(const FString& Url) -{ - if (bShouldBeVisible) - { - SetVisible(true); - } +void UThirdwebOAuthBrowserUserWidget::HandlePageLoaded(const FString &Url) { + if (bShouldBeVisible) { + SetVisible(true); + } } -void UThirdwebOAuthBrowserUserWidget::HandleOnBeforePopup(const FString& Url, const FString& Frame) -{ - return OnPopup.Broadcast(Url, Frame); +void UThirdwebOAuthBrowserUserWidget::HandleOnBeforePopup( + const FString &Url, const FString &Frame) { + return OnPopup.Broadcast(Url, Frame); } -void UThirdwebOAuthBrowserUserWidget::HandleAuthenticated(const FString& AuthResult) -{ - OnAuthenticated.Broadcast(AuthResult); +void UThirdwebOAuthBrowserUserWidget::HandleAuthenticated( + const FString &AuthResult) { + OnAuthenticated.Broadcast(AuthResult); } -void UThirdwebOAuthBrowserUserWidget::HandleSiweComplete(const FString& Signature, const FString& Payload) -{ - OnSiweComplete.Broadcast(Signature, Payload); +void UThirdwebOAuthBrowserUserWidget::HandleSiweComplete( + const FString &Payload, const FString &Signature) { + if (IsInGameThread()) { + OnSiweComplete.Broadcast(Payload, Signature); + } else { + // Dispatch to game thread + TWeakObjectPtr WeakThis = this; + FFunctionGraphTask::CreateAndDispatchWhenReady( + [WeakThis, Payload, Signature]() { + if (WeakThis.IsValid()) { + WeakThis->OnSiweComplete.Broadcast(Payload, Signature); + } + }, + TStatId(), nullptr, ENamedThreads::GameThread); + } } -void UThirdwebOAuthBrowserUserWidget::HandleError(const FString& Error) -{ - OnError.Broadcast(Error); +void UThirdwebOAuthBrowserUserWidget::HandleError(const FString &Error) { + OnError.Broadcast(Error); } #if PLATFORM_ANDROID -void UThirdwebOAuthBrowserUserWidget::HandleDeepLink(const FString &Url) -{ - TW_LOG(VeryVerbose, TEXT("UThirdwebOAuthBrowserUserWidget::HandleDeepLink::%s"), *Url); - HandleUrlChanged(Url); +void UThirdwebOAuthBrowserUserWidget::HandleDeepLink(const FString &Url) { + TW_LOG(VeryVerbose, + TEXT("UThirdwebOAuthBrowserUserWidget::HandleDeepLink::%s"), *Url); + HandleUrlChanged(Url); } -void UThirdwebOAuthBrowserUserWidget::HandleCustomTabsDismissed(const FString &Url) -{ - TW_LOG(VeryVerbose, TEXT("UThirdwebOAuthBrowserUserWidget::HandleCustomTabsDismissed::%s"), *Url); - HandleUrlChanged(Url); +void UThirdwebOAuthBrowserUserWidget::HandleCustomTabsDismissed( + const FString &Url) { + TW_LOG(VeryVerbose, + TEXT("UThirdwebOAuthBrowserUserWidget::HandleCustomTabsDismissed::%s"), + *Url); + HandleUrlChanged(Url); } #endif -void UThirdwebOAuthBrowserUserWidget::SetVisible(const bool bVisible) -{ - // Mobile webview needs to be visible to work - if (bVisible) - { - if (bCollapseWhenBlank) - { +void UThirdwebOAuthBrowserUserWidget::SetVisible(const bool bVisible) { + // Mobile webview needs to be visible to work + if (bVisible) { + if (bCollapseWhenBlank) { #if PLATFORM_IOS | PLATFORM_ANDROID - SetRenderOpacity(1.0f); + SetRenderOpacity(1.0f); #else - SetVisibility(ESlateVisibility::Visible); + SetVisibility(ESlateVisibility::Visible); #endif - } - } - else - { - bShouldBeVisible = false; - if (bCollapseWhenBlank) - { + } + } else { + bShouldBeVisible = false; + if (bCollapseWhenBlank) { #if PLATFORM_IOS | PLATFORM_ANDROID - SetRenderOpacity(0.01f); + SetRenderOpacity(0.01f); #else - SetVisibility(ESlateVisibility::Collapsed); + SetVisibility(ESlateVisibility::Collapsed); #endif - } - } + } + } } diff --git a/Source/Thirdweb/Private/Browser/ThirdwebOAuthExternalBrowser.cpp b/Source/Thirdweb/Private/Browser/ThirdwebOAuthExternalBrowser.cpp index 67dd310..4705c69 100644 --- a/Source/Thirdweb/Private/Browser/ThirdwebOAuthExternalBrowser.cpp +++ b/Source/Thirdweb/Private/Browser/ThirdwebOAuthExternalBrowser.cpp @@ -2,176 +2,189 @@ #include "Browser/ThirdwebOAuthExternalBrowser.h" +#include "Delegates/DelegateSignatureImpl.inl" +#include "GenericPlatform/GenericPlatformHttp.h" +#include "HAL/Event.h" #include "HttpRequestHandler.h" #include "HttpServerModule.h" #include "IHttpRouter.h" +#include "Misc/EngineVersionComparison.h" #include "ThirdwebLog.h" #include "ThirdwebRuntimeSettings.h" -#include "Delegates/DelegateSignatureImpl.inl" -#include "GenericPlatform/GenericPlatformHttp.h" -#include "HAL/Event.h" -#include "Misc/EngineVersionComparison.h" -UThirdwebOAuthExternalBrowser::UThirdwebOAuthExternalBrowser() -{ - AuthEvent = nullptr; - State = Initialized; - bIsSiwe = false; +UThirdwebOAuthExternalBrowser::UThirdwebOAuthExternalBrowser() { + AuthEvent = nullptr; + State = Initialized; + bIsSiwe = false; } -void UThirdwebOAuthExternalBrowser::Authenticate(const FString& Link) -{ - FString Url = Link; - EModuleLoadResult ModuleResult; - FModuleManager::Get().LoadModuleWithFailureReason(FName(TEXT("HTTPServer")), ModuleResult); - if (ModuleResult != EModuleLoadResult::Success) - { - return HandleError(TEXT("Failed to load HTTPServer")); - } - - Router = FHttpServerModule::Get().GetHttpRouter(8789, true); - if (!Router.IsValid()) - { - return HandleError(TEXT("Failed to get HTTP Router")); - } - - AuthEvent = FPlatformProcess::GetSynchEventFromPool(false); +void UThirdwebOAuthExternalBrowser::Authenticate(const FString &Link) { + // Clean up any previous authentication session + CleanupAuthentication(); + + // Reset state + State = Initialized; + bIsSiwe = false; + AuthResult.Empty(); + Signature.Empty(); + Payload.Empty(); + + FString Url = Link; + EModuleLoadResult ModuleResult; + FModuleManager::Get().LoadModuleWithFailureReason(FName(TEXT("HTTPServer")), + ModuleResult); + if (ModuleResult != EModuleLoadResult::Success) { + return HandleError(TEXT("Failed to load HTTPServer")); + } + + Router = FHttpServerModule::Get().GetHttpRouter(8789, true); + if (!Router.IsValid()) { + return HandleError(TEXT("Failed to get HTTP Router")); + } + + AuthEvent = FPlatformProcess::GetSynchEventFromPool(false); #if UE_VERSION_OLDER_THAN(5, 4, 0) - FHttpRequestHandler Handler = [WeakThis = MakeWeakObjectPtr(this)](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) - { - if (WeakThis.IsValid()) - { - return WeakThis->CallbackRequestHandler(Request, OnComplete); - } - return false; - }; + FHttpRequestHandler Handler = [WeakThis = MakeWeakObjectPtr(this)]( + const FHttpServerRequest &Request, + const FHttpResultCallback &OnComplete) { + if (WeakThis.IsValid()) { + return WeakThis->CallbackRequestHandler(Request, OnComplete); + } + return false; + }; #else - FHttpRequestHandler Handler = FHttpRequestHandler::CreateUObject(this, &UThirdwebOAuthExternalBrowser::CallbackRequestHandler); + FHttpRequestHandler Handler = FHttpRequestHandler::CreateUObject( + this, &UThirdwebOAuthExternalBrowser::CallbackRequestHandler); #endif - - RouteHandle = Router->BindRoute(FHttpPath(TEXT("/callback")), EHttpServerRequestVerbs::VERB_GET, Handler); - - if (!RouteHandle.IsValid()) - { - FPlatformProcess::ReturnSynchEventToPool(AuthEvent); - return HandleError(TEXT("Failed to bind route")); - } - - // Start the HTTP server - FHttpServerModule::Get().StartAllListeners(); - TW_LOG(VeryVerbose, TEXT("OAuth HTTP Server started and listening on port 8789")); - - bIsSiwe = Url.ToUpper().TrimStartAndEnd().Equals(TEXT("SIWE")); - if (bIsSiwe) - { - Url = FString::Printf(TEXT("http://static.thirdweb.com/auth/siwe?redirectUrl=%s"), *FGenericPlatformHttp::UrlEncode(TEXT("http://localhost:8789/callback"))); - } - // Open the browser with the login URL - FPlatformProcess::LaunchURL(*Link, nullptr, nullptr); - TW_LOG(Verbose, TEXT("Browser opened with URL: %s"), *Link); - State = AuthPending; -} -void UThirdwebOAuthExternalBrowser::Tick(float DeltaTime) -{ - if (State == AuthComplete) - { - State = Complete; - - // Set the results based on the authentication - if (bIsSiwe) - { - if (!Signature.IsEmpty() && !Payload.IsEmpty()) - { - return HandleSuccess(); - } - } else - { - if (!AuthResult.IsEmpty()) - { - return HandleSuccess(); - } - } - - HandleError(TEXT("OAuth login flow did not complete in time")); - } + RouteHandle = Router->BindRoute(FHttpPath(TEXT("/callback")), + EHttpServerRequestVerbs::VERB_GET, Handler); + + if (!RouteHandle.IsValid()) { + FPlatformProcess::ReturnSynchEventToPool(AuthEvent); + return HandleError(TEXT("Failed to bind route")); + } + + // Start the HTTP server + FHttpServerModule::Get().StartAllListeners(); + TW_LOG(VeryVerbose, + TEXT("OAuth HTTP Server started and listening on port 8789")); + + bIsSiwe = Url.ToUpper().TrimStartAndEnd().Equals(TEXT("SIWE")); + if (bIsSiwe) { + Url = FString::Printf( + TEXT("http://static.thirdweb.com/auth/siwe?redirectUrl=%s"), + *FGenericPlatformHttp::UrlEncode( + TEXT("http://localhost:8789/callback"))); + } + // Open the browser with the login URL + FPlatformProcess::LaunchURL(*Url, nullptr, nullptr); + TW_LOG(Verbose, TEXT("Browser opened with URL: %s"), *Url); + State = AuthPending; } -void UThirdwebOAuthExternalBrowser::BeginDestroy() -{ - // Stop the HTTP listener - FHttpServerModule::Get().StopAllListeners(); - TW_LOG(VeryVerbose, TEXT("OAuth HTTP Server stopped listening")); - - if (Router.IsValid() && RouteHandle.IsValid()) - { - // Unbind the route - Router->UnbindRoute(RouteHandle); - TW_LOG(VeryVerbose, TEXT("Route unbound")); - } - if (AuthEvent) - { - FPlatformProcess::ReturnSynchEventToPool(AuthEvent); - } - ConditionalBeginDestroy(); - - UObject::BeginDestroy(); +void UThirdwebOAuthExternalBrowser::Tick(float DeltaTime) { + if (State == AuthComplete) { + State = Complete; + + // Set the results based on the authentication + if (bIsSiwe) { + if (!Signature.IsEmpty() && !Payload.IsEmpty()) { + return HandleSuccess(); + } + } else { + if (!AuthResult.IsEmpty()) { + return HandleSuccess(); + } + } + + HandleError(TEXT("OAuth login flow did not complete in time")); + } } -bool UThirdwebOAuthExternalBrowser::CallbackRequestHandler(const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) -{ - AuthResult = Request.QueryParams.FindRef(TEXT("authResult")); - Signature = Request.QueryParams.FindRef(TEXT("signature")); - Payload = FGenericPlatformHttp::UrlDecode(Request.QueryParams.FindRef(TEXT("payload"))); - TW_LOG(VeryVerbose, TEXT("UThirdwebOAuthExternalBrowser::CallbackRequestHandler::Signature=%s|Payload=%s|AuthResult=%s"), *Signature, *Payload, *AuthResult) - if (bIsSiwe ? Signature.IsEmpty() || Payload.IsEmpty() : AuthResult.IsEmpty()) - { - FString Error = FString::Printf(TEXT("%s query parameter is missing"), bIsSiwe ? TEXT("Signature/Payload") : TEXT("AuthResult")); - TUniquePtr Response = FHttpServerResponse::Create(Error, TEXT("text/plain")); - OnComplete(MoveTemp(Response)); - HandleError(Error); - } - else - { - State = AuthComplete; - AuthEvent->Trigger(); - TUniquePtr Response = FHttpServerResponse::Create( - FString::Printf(TEXT(""), *UThirdwebRuntimeSettings::GetExternalAuthRedirectUri()), - TEXT("text/html") - ); - OnComplete(MoveTemp(Response)); - } - return true; +void UThirdwebOAuthExternalBrowser::BeginDestroy() { + // Clean up authentication resources (idempotent) + CleanupAuthentication(); + + // Stop the HTTP listener (this stops ALL listeners globally) + FHttpServerModule::Get().StopAllListeners(); + TW_LOG(VeryVerbose, TEXT("OAuth HTTP Server stopped listening")); + + ConditionalBeginDestroy(); + UObject::BeginDestroy(); } -void UThirdwebOAuthExternalBrowser::HandleSuccess() -{ - if (bIsSiwe) - { - if (OnSiweComplete.IsBound()) - { - OnSiweComplete.Execute(Signature, Payload); - } - } else - { - if (OnAuthenticated.IsBound()) - { - OnAuthenticated.Execute(AuthResult); - } - } - +bool UThirdwebOAuthExternalBrowser::CallbackRequestHandler( + const FHttpServerRequest &Request, const FHttpResultCallback &OnComplete) { + AuthResult = Request.QueryParams.FindRef(TEXT("authResult")); + Signature = Request.QueryParams.FindRef(TEXT("signature")); + Payload = FGenericPlatformHttp::UrlDecode( + Request.QueryParams.FindRef(TEXT("payload"))); + TW_LOG(VeryVerbose, + TEXT("UThirdwebOAuthExternalBrowser::CallbackRequestHandler::" + "Signature=%s|Payload=%s|AuthResult=%s"), + *Signature, *Payload, *AuthResult) + if (bIsSiwe ? Signature.IsEmpty() || Payload.IsEmpty() + : AuthResult.IsEmpty()) { + FString Error = FString::Printf(TEXT("%s query parameter is missing"), + bIsSiwe ? TEXT("Signature/Payload") + : TEXT("AuthResult")); + TUniquePtr Response = + FHttpServerResponse::Create(Error, TEXT("text/plain")); + OnComplete(MoveTemp(Response)); + HandleError(Error); + } else { + State = AuthComplete; + AuthEvent->Trigger(); + TUniquePtr Response = FHttpServerResponse::Create( + FString::Printf( + TEXT(""), + *UThirdwebRuntimeSettings::GetExternalAuthRedirectUri()), + TEXT("text/html")); + OnComplete(MoveTemp(Response)); + } + return true; } -void UThirdwebOAuthExternalBrowser::HandleError(const FString& Error) -{ - - TW_LOG(VeryVerbose, TEXT("UThirdwebOAuthExternalBrowser::HandleError::%s"), *Error); - if (OnError.IsBound()) - { - OnError.Execute(Error); - } +void UThirdwebOAuthExternalBrowser::HandleSuccess() { + if (bIsSiwe) { + if (OnSiweComplete.IsBound()) { + OnSiweComplete.Execute(Payload, Signature); + } + } else { + if (OnAuthenticated.IsBound()) { + OnAuthenticated.Execute(AuthResult); + } + } + + // Clean up immediately after delegate fires + CleanupAuthentication(); } +void UThirdwebOAuthExternalBrowser::HandleError(const FString &Error) { + TW_LOG(VeryVerbose, TEXT("UThirdwebOAuthExternalBrowser::HandleError::%s"), + *Error); + if (OnError.IsBound()) { + OnError.Execute(Error); + } + // Clean up immediately after delegate fires + CleanupAuthentication(); +} +void UThirdwebOAuthExternalBrowser::CleanupAuthentication() { + // Unbind route if it exists + if (Router.IsValid() && RouteHandle.IsValid()) { + Router->UnbindRoute(RouteHandle); + RouteHandle = FHttpRouteHandle(); + TW_LOG(VeryVerbose, TEXT("Route unbound in cleanup")); + } + + // Return event to pool + if (AuthEvent) { + FPlatformProcess::ReturnSynchEventToPool(AuthEvent); + AuthEvent = nullptr; + TW_LOG(VeryVerbose, TEXT("AuthEvent returned to pool")); + } +} diff --git a/Source/Thirdweb/Private/ThirdwebUtils.cpp b/Source/Thirdweb/Private/ThirdwebUtils.cpp index ae183cf..0be3613 100644 --- a/Source/Thirdweb/Private/ThirdwebUtils.cpp +++ b/Source/Thirdweb/Private/ThirdwebUtils.cpp @@ -516,7 +516,7 @@ namespace ThirdwebUtils {TEXT("x-bundle-id"), Settings->GetBundleId()}, }); Headers.UpdateRequest(Request); - Request->SetTimeout(5.0f); + Request->SetTimeout(15.0f); // ReSharper disable once CppLocalVariableMayBeConst TSharedPtr JsonObject = MakeShareable(new FJsonObject); diff --git a/Source/Thirdweb/Private/Wallets/ThirdwebInAppWalletHandle.cpp b/Source/Thirdweb/Private/Wallets/ThirdwebInAppWalletHandle.cpp index 31fd0cd..9cc5062 100644 --- a/Source/Thirdweb/Private/Wallets/ThirdwebInAppWalletHandle.cpp +++ b/Source/Thirdweb/Private/Wallets/ThirdwebInAppWalletHandle.cpp @@ -158,7 +158,7 @@ void FInAppWalletHandle::CreateSiweWallet(const FCreateInAppWalletDelegate& Succ CHECK_DELEGATES(SuccessDelegate, ErrorDelegate) UE::Tasks::Launch(UE_SOURCE_LOCATION, [SuccessDelegate, ErrorDelegate] { - static FString Provider = TEXT("SIWE"); + static FString Provider = TEXT("Siwe"); FString Error; if (Thirdweb::create_ecosystem_wallet( TO_RUST_STRING(UThirdwebRuntimeSettings::GetEcosystemId()), @@ -598,8 +598,8 @@ void FInAppWalletHandle::LinkSiwe(const FInAppWalletHandle& Wallet, const FStrin nullptr, nullptr, nullptr, - TO_RUST_STRING(Signature), - TO_RUST_STRING(Payload)).AssignResult(Error, true)) + TO_RUST_STRING(Payload), + TO_RUST_STRING(Signature)).AssignResult(Error, true)) { SuccessDelegate.Execute(); return; diff --git a/Source/Thirdweb/Public/AsyncTasks/Wallets/InApp/AsyncTaskThirdwebLoginWithSiwe.h b/Source/Thirdweb/Public/AsyncTasks/Wallets/InApp/AsyncTaskThirdwebLoginWithSiwe.h new file mode 100644 index 0000000..671a549 --- /dev/null +++ b/Source/Thirdweb/Public/AsyncTasks/Wallets/InApp/AsyncTaskThirdwebLoginWithSiwe.h @@ -0,0 +1,48 @@ +// Copyright (c) 2025 Thirdweb. All Rights Reserved. + +#pragma once + +#include "AsyncTaskThirdwebInAppBase.h" +#include "Wallets/ThirdwebInAppWalletHandle.h" +#include "AsyncTaskThirdwebLoginWithSiwe.generated.h" + +class UThirdwebOAuthBrowserUserWidget; + +/** + * High-level SIWE login async task that handles browser widget creation and + * authentication flow + */ +UCLASS(Blueprintable, BlueprintType) +class THIRDWEB_API UAsyncTaskThirdwebLoginWithSiwe : public UAsyncTaskThirdwebInAppBase +{ + GENERATED_BODY() + +public: + virtual void Activate() override; + + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject"), Category = "Thirdweb|Wallets|In App") + static UAsyncTaskThirdwebLoginWithSiwe* + LoginWithSiwe(UObject* WorldContextObject, const FInAppWalletHandle& Wallet); + + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FSiweCompleteDelegate, const FString &, Payload, const FString &, Signature); + + UPROPERTY(BlueprintAssignable) + FSiweCompleteDelegate Success; + + UPROPERTY(BlueprintAssignable) + FErrorOnlyDelegate Failed; + +protected: + UPROPERTY(Transient) + UThirdwebOAuthBrowserUserWidget* Browser; + + UPROPERTY(Transient) + FInAppWalletHandle Wallet; + +private: + UFUNCTION() + void HandleSiweComplete(const FString& Payload, const FString& Signature); + + UFUNCTION() + void HandleFailed(const FString& Error); +}; diff --git a/Source/Thirdweb/Public/Browser/ThirdwebOAuthBrowserUserWidget.h b/Source/Thirdweb/Public/Browser/ThirdwebOAuthBrowserUserWidget.h index 721bee2..c8834fc 100644 --- a/Source/Thirdweb/Public/Browser/ThirdwebOAuthBrowserUserWidget.h +++ b/Source/Thirdweb/Public/Browser/ThirdwebOAuthBrowserUserWidget.h @@ -6,6 +6,7 @@ #include "Wallets/ThirdwebInAppWalletHandle.h" #include "ThirdwebOAuthBrowserUserWidget.generated.h" + UCLASS(DisplayName = "OAuth Browser") class THIRDWEB_API UThirdwebOAuthBrowserUserWidget : public UUserWidget { @@ -17,7 +18,7 @@ class THIRDWEB_API UThirdwebOAuthBrowserUserWidget : public UUserWidget UPROPERTY(BlueprintAssignable, Category = "Thirdweb|OAuth Browser") FOnAuthenticatedDelegate OnAuthenticated; - DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSiweCompleteDelegate, const FString &, Signature, const FString &, Payload); + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSiweCompleteDelegate, const FString &, Payload, const FString &, Signature); UPROPERTY(BlueprintAssignable, Category = "Thirdweb|OAuth Browser") FOnSiweCompleteDelegate OnSiweComplete; @@ -45,7 +46,8 @@ class THIRDWEB_API UThirdwebOAuthBrowserUserWidget : public UUserWidget UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Browser") bool bCollapseWhenBlank = true; - /** Automatically authenticate on Construct. Only works when created with a Wallet */ + /** Automatically authenticate on Construct. Only works when created with a + * Wallet */ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Browser") bool bAuthenticateOnConstruct = false; @@ -77,13 +79,13 @@ class THIRDWEB_API UThirdwebOAuthBrowserUserWidget : public UUserWidget virtual void HandleOnBeforePopup(const FString& Url, const FString& Frame); virtual void HandleAuthenticated(const FString& AuthResult); - virtual void HandleSiweComplete(const FString& Signature, const FString& Payload); + virtual void HandleSiweComplete(const FString& Payload, const FString& Signature); virtual void HandleError(const FString& Error); public: #if PLATFORM_ANDROID - void HandleDeepLink(const FString &Url); - void HandleCustomTabsDismissed(const FString &Url); + void HandleDeepLink(const FString &Url); + void HandleCustomTabsDismissed(const FString &Url); #endif UFUNCTION(BlueprintCallable, Category = "Thirdweb|OAuth Browser") diff --git a/Source/Thirdweb/Public/Browser/ThirdwebOAuthExternalBrowser.h b/Source/Thirdweb/Public/Browser/ThirdwebOAuthExternalBrowser.h index b48cb93..7f4d908 100644 --- a/Source/Thirdweb/Public/Browser/ThirdwebOAuthExternalBrowser.h +++ b/Source/Thirdweb/Public/Browser/ThirdwebOAuthExternalBrowser.h @@ -7,10 +7,11 @@ #include "UObject/Object.h" #include "ThirdwebOAuthExternalBrowser.generated.h" + class IHttpRouter; /** - * + * */ UCLASS(NotBlueprintable, NotBlueprintType, MinimalAPI) class UThirdwebOAuthExternalBrowser : public UObject, public FTickableGameObject @@ -19,34 +20,30 @@ class UThirdwebOAuthExternalBrowser : public UObject, public FTickableGameObject public: UThirdwebOAuthExternalBrowser(); - + void Authenticate(const FString& Link); - + /** FTickableGameObject implementation */ virtual void Tick(float DeltaTime) override; virtual TStatId GetStatId() const override { return TStatId(); }; virtual void BeginDestroy() override; - + private: bool CallbackRequestHandler(const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete); void HandleSuccess(); void HandleError(const FString& Error); + void CleanupAuthentication(); public: - DECLARE_DELEGATE_OneParam(FSimpleStringDelegate, const FString&); + DECLARE_DELEGATE_OneParam(FSimpleStringDelegate, const FString &); FSimpleStringDelegate OnAuthenticated; FSimpleStringDelegate OnError; - - DECLARE_DELEGATE_TwoParams(FDoubleStringDelegate, const FString&, const FString&); + + DECLARE_DELEGATE_TwoParams(FDoubleStringDelegate, const FString &, const FString &); FDoubleStringDelegate OnSiweComplete; + private: - enum EState - { - Initialized, - AuthPending, - AuthComplete, - Complete - }; + enum EState { Initialized, AuthPending, AuthComplete, Complete }; // OAuth FString AuthResult; @@ -54,7 +51,7 @@ class UThirdwebOAuthExternalBrowser : public UObject, public FTickableGameObject FString Signature; FString Payload; bool bIsSiwe; - + FEvent* AuthEvent; FHttpRouteHandle RouteHandle; TSharedPtr Router; diff --git a/Source/Thirdweb/Public/Wallets/ThirdwebInAppWalletHandle.h b/Source/Thirdweb/Public/Wallets/ThirdwebInAppWalletHandle.h index fca370c..9fc2fe4 100644 --- a/Source/Thirdweb/Public/Wallets/ThirdwebInAppWalletHandle.h +++ b/Source/Thirdweb/Public/Wallets/ThirdwebInAppWalletHandle.h @@ -331,7 +331,7 @@ struct THIRDWEB_API FInAppWalletHandle : public FWalletHandle {Phone, TEXT("Phone")}, {Jwt, TEXT("JWT")}, {AuthEndpoint, TEXT("AuthEndpoint")}, - {Siwe, TEXT("SIWE")}, + {Siwe, TEXT("Siwe")}, {Guest, TEXT("Guest")}, }; return Map.Contains(Source) ? Map[Source] : TEXT("Unknown"); From 83f29d135f7d3a3726ee31e20690bb8935372170 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 23 Oct 2025 07:12:22 +0700 Subject: [PATCH 2/2] fmt --- .../InApp/AsyncTaskThirdwebLoginWithSiwe.cpp | 114 +-- .../ThirdwebOAuthBrowserUserWidget.cpp | 268 +++--- .../Browser/ThirdwebOAuthExternalBrowser.cpp | 305 +++---- .../Wallets/ThirdwebInAppWalletHandle.cpp | 766 +++++++++--------- 4 files changed, 764 insertions(+), 689 deletions(-) diff --git a/Source/Thirdweb/Private/AsyncTasks/Wallets/InApp/AsyncTaskThirdwebLoginWithSiwe.cpp b/Source/Thirdweb/Private/AsyncTasks/Wallets/InApp/AsyncTaskThirdwebLoginWithSiwe.cpp index 7639a14..81b3334 100644 --- a/Source/Thirdweb/Private/AsyncTasks/Wallets/InApp/AsyncTaskThirdwebLoginWithSiwe.cpp +++ b/Source/Thirdweb/Private/AsyncTasks/Wallets/InApp/AsyncTaskThirdwebLoginWithSiwe.cpp @@ -9,60 +9,74 @@ #include "Kismet/GameplayStatics.h" #include "ThirdwebLog.h" -void UAsyncTaskThirdwebLoginWithSiwe::Activate() { - Browser->OnSiweComplete.AddDynamic(this, &ThisClass::HandleSiweComplete); - Browser->OnError.AddDynamic(this, &ThisClass::HandleFailed); - Browser->AddToViewport(10000); - Browser->Authenticate(Wallet); +void UAsyncTaskThirdwebLoginWithSiwe::Activate() +{ + Browser->OnSiweComplete.AddDynamic(this, &ThisClass::HandleSiweComplete); + Browser->OnError.AddDynamic(this, &ThisClass::HandleFailed); + Browser->AddToViewport(10000); + Browser->Authenticate(Wallet); } -UAsyncTaskThirdwebLoginWithSiwe *UAsyncTaskThirdwebLoginWithSiwe::LoginWithSiwe( - UObject *WorldContextObject, const FInAppWalletHandle &Wallet) { - if (!WorldContextObject) { - return nullptr; - } - NEW_TASK - Task->Wallet = Wallet; - Task->Browser = CreateWidget( - UGameplayStatics::GetGameInstance(WorldContextObject), - UThirdwebOAuthBrowserUserWidget::StaticClass()); - Task->RegisterWithGameInstance(WorldContextObject); - return Task; +UAsyncTaskThirdwebLoginWithSiwe* UAsyncTaskThirdwebLoginWithSiwe::LoginWithSiwe(UObject* WorldContextObject, const FInAppWalletHandle& Wallet) +{ + if (!WorldContextObject) + { + return nullptr; + } + NEW_TASK + Task->Wallet = Wallet; + Task->Browser = CreateWidget(UGameplayStatics::GetGameInstance(WorldContextObject), + UThirdwebOAuthBrowserUserWidget::StaticClass()); + Task->RegisterWithGameInstance(WorldContextObject); + return Task; } -void UAsyncTaskThirdwebLoginWithSiwe::HandleSiweComplete( - const FString &Payload, const FString &Signature) { - if (IsInGameThread()) { - Success.Broadcast(Payload, Signature); - Browser->RemoveFromParent(); - SetReadyToDestroy(); - } else { - // Retry on the GameThread. - TWeakObjectPtr WeakThis = this; - FFunctionGraphTask::CreateAndDispatchWhenReady( - [WeakThis, Payload, Signature]() { - if (WeakThis.IsValid()) { - WeakThis->HandleSiweComplete(Payload, Signature); - } - }, - TStatId(), nullptr, ENamedThreads::GameThread); - } +void UAsyncTaskThirdwebLoginWithSiwe::HandleSiweComplete(const FString& Payload, const FString& Signature) +{ + if (IsInGameThread()) + { + Success.Broadcast(Payload, Signature); + Browser->RemoveFromParent(); + SetReadyToDestroy(); + } + else + { + // Retry on the GameThread. + TWeakObjectPtr WeakThis = this; + FFunctionGraphTask::CreateAndDispatchWhenReady([WeakThis, Payload, Signature]() + { + if (WeakThis.IsValid()) + { + WeakThis->HandleSiweComplete(Payload, Signature); + } + }, + TStatId(), + nullptr, + ENamedThreads::GameThread); + } } -void UAsyncTaskThirdwebLoginWithSiwe::HandleFailed(const FString &Error) { - if (IsInGameThread()) { - Browser->RemoveFromParent(); - Failed.Broadcast(Error); - SetReadyToDestroy(); - } else { - // Retry on the GameThread. - TWeakObjectPtr WeakThis = this; - FFunctionGraphTask::CreateAndDispatchWhenReady( - [WeakThis, Error]() { - if (WeakThis.IsValid()) { - WeakThis->HandleFailed(Error); - } - }, - TStatId(), nullptr, ENamedThreads::GameThread); - } +void UAsyncTaskThirdwebLoginWithSiwe::HandleFailed(const FString& Error) +{ + if (IsInGameThread()) + { + Browser->RemoveFromParent(); + Failed.Broadcast(Error); + SetReadyToDestroy(); + } + else + { + // Retry on the GameThread. + TWeakObjectPtr WeakThis = this; + FFunctionGraphTask::CreateAndDispatchWhenReady([WeakThis, Error]() + { + if (WeakThis.IsValid()) + { + WeakThis->HandleFailed(Error); + } + }, + TStatId(), + nullptr, + ENamedThreads::GameThread); + } } diff --git a/Source/Thirdweb/Private/Browser/ThirdwebOAuthBrowserUserWidget.cpp b/Source/Thirdweb/Private/Browser/ThirdwebOAuthBrowserUserWidget.cpp index e2e680f..f77a9ec 100644 --- a/Source/Thirdweb/Private/Browser/ThirdwebOAuthBrowserUserWidget.cpp +++ b/Source/Thirdweb/Private/Browser/ThirdwebOAuthBrowserUserWidget.cpp @@ -16,91 +16,91 @@ #include "Browser/Android/ThirdwebAndroidJNI.h" #endif -const FString UThirdwebOAuthBrowserUserWidget::BackendUrlPrefix = - TEXT("https://embedded-wallet.thirdweb.com/"); -const FString UThirdwebOAuthBrowserUserWidget::DummyUrl = - TEXT("http://localhost:8789/callback"); - -TSharedRef UThirdwebOAuthBrowserUserWidget::RebuildWidget() { - // RebuildWidget is not called until the widget is first added to the - // viewport. - - UPanelWidget *RootWidget = Cast(GetRootWidget()); - - // Construct root widget if needed - if (!RootWidget) { - RootWidget = WidgetTree->ConstructWidget(UOverlay::StaticClass(), - TEXT("RootWidget")); - WidgetTree->RootWidget = RootWidget; - } - - // Construct children - if (RootWidget) { - // Construct External browser - ExternalBrowser = NewObject(this); - ExternalBrowser->OnAuthenticated.BindUObject( - this, &ThisClass::HandleAuthenticated); - ExternalBrowser->OnError.BindUObject(this, &ThisClass::HandleError); - ExternalBrowser->OnSiweComplete.BindUObject(this, - &ThisClass::HandleSiweComplete); - } - - return Super::RebuildWidget(); +const FString UThirdwebOAuthBrowserUserWidget::BackendUrlPrefix = TEXT("https://embedded-wallet.thirdweb.com/"); +const FString UThirdwebOAuthBrowserUserWidget::DummyUrl = TEXT("http://localhost:8789/callback"); + +TSharedRef UThirdwebOAuthBrowserUserWidget::RebuildWidget() +{ + // RebuildWidget is not called until the widget is first added to the + // viewport. + + UPanelWidget* RootWidget = Cast(GetRootWidget()); + + // Construct root widget if needed + if (!RootWidget) + { + RootWidget = WidgetTree->ConstructWidget(UOverlay::StaticClass(), TEXT("RootWidget")); + WidgetTree->RootWidget = RootWidget; + } + + // Construct children + if (RootWidget) + { + // Construct External browser + ExternalBrowser = NewObject(this); + ExternalBrowser->OnAuthenticated.BindUObject(this, &ThisClass::HandleAuthenticated); + ExternalBrowser->OnError.BindUObject(this, &ThisClass::HandleError); + ExternalBrowser->OnSiweComplete.BindUObject(this, &ThisClass::HandleSiweComplete); + } + + return Super::RebuildWidget(); } #if WITH_EDITOR -const FText UThirdwebOAuthBrowserUserWidget::GetPaletteCategory() { - return NSLOCTEXT("Thirdweb", "Thirdweb", "Thirdweb"); +const FText UThirdwebOAuthBrowserUserWidget::GetPaletteCategory() +{ + return NSLOCTEXT("Thirdweb", "Thirdweb", "Thirdweb"); } #endif -void UThirdwebOAuthBrowserUserWidget::OnWidgetRebuilt() { - Super::OnWidgetRebuilt(); - SetVisible(false); +void UThirdwebOAuthBrowserUserWidget::OnWidgetRebuilt() +{ + Super::OnWidgetRebuilt(); + SetVisible(false); } -void UThirdwebOAuthBrowserUserWidget::BeginDestroy() { - if (ExternalBrowser) { - ExternalBrowser->ConditionalBeginDestroy(); - } - Super::BeginDestroy(); +void UThirdwebOAuthBrowserUserWidget::BeginDestroy() +{ + if (ExternalBrowser) + { + ExternalBrowser->ConditionalBeginDestroy(); + } + Super::BeginDestroy(); } -FString UThirdwebOAuthBrowserUserWidget::GetDummyUrl() { +FString UThirdwebOAuthBrowserUserWidget::GetDummyUrl() +{ #if PLATFORM_ANDROID return UThirdwebRuntimeSettings::GetAppUri(); #else - return DummyUrl; + return DummyUrl; #endif } -void UThirdwebOAuthBrowserUserWidget::Authenticate( - const FInAppWalletHandle &InAppWallet) { - // Validate Wallet - if (!InAppWallet.IsValid()) { - TW_LOG(Error, TEXT("OAuthBrowserUserWidget::Authenticate::Wallet invalid")); - return HandleError(TEXT("Invalid Wallet")); - } - Wallet = InAppWallet; - TW_LOG(VeryVerbose, - TEXT("OAuthBrowserUserWidget::Authenticate::Wallet Type::%s"), - Wallet.GetSourceString()); - if (Wallet == FInAppWalletHandle::Siwe) { - TW_LOG(VeryVerbose, TEXT("OAuthBrowserUserWidget::Authenticate::" - "Authenticating against %s"), Wallet.GetSourceString()); - ExternalBrowser->Authenticate(Wallet.GetSourceString()); - return; - } - - // Get Login URL - FString Link; - if (FString Error; !Wallet.FetchOAuthLoginURL(GetDummyUrl(), Link, Error)) { - return HandleError(Error); - } - TW_LOG( - VeryVerbose, - TEXT("OAuthBrowserUserWidget::Authenticate::Authenticating against %s"), - *Link); +void UThirdwebOAuthBrowserUserWidget::Authenticate(const FInAppWalletHandle& InAppWallet) +{ + // Validate Wallet + if (!InAppWallet.IsValid()) + { + TW_LOG(Error, TEXT("OAuthBrowserUserWidget::Authenticate::Wallet invalid")); + return HandleError(TEXT("Invalid Wallet")); + } + Wallet = InAppWallet; + TW_LOG(VeryVerbose, TEXT("OAuthBrowserUserWidget::Authenticate::Wallet Type::%s"), Wallet.GetSourceString()); + if (Wallet == FInAppWalletHandle::Siwe) + { + TW_LOG(VeryVerbose, TEXT("OAuthBrowserUserWidget::Authenticate::" "Authenticating against %s"), Wallet.GetSourceString()); + ExternalBrowser->Authenticate(Wallet.GetSourceString()); + return; + } + + // Get Login URL + FString Link; + if (FString Error; !Wallet.FetchOAuthLoginURL(GetDummyUrl(), Link, Error)) + { + return HandleError(Error); + } + TW_LOG(VeryVerbose, TEXT("OAuthBrowserUserWidget::Authenticate::Authenticating against %s"), *Link); #if PLATFORM_ANDROID if (JNIEnv *Env = FAndroidApplication::GetJavaEnv()) { @@ -120,63 +120,73 @@ void UThirdwebOAuthBrowserUserWidget::Authenticate( return; #endif - return ExternalBrowser->Authenticate(Link); + return ExternalBrowser->Authenticate(Link); } -void UThirdwebOAuthBrowserUserWidget::HandleUrlChanged(const FString &Url) { - TW_LOG(Verbose, TEXT("OAuthBrowserUserWidget::HandleUrlChanged::%s"), *Url); - if (Url.IsEmpty() || - (Url.StartsWith(BackendUrlPrefix) && - !Url.StartsWith(BackendUrlPrefix + TEXT("sdk/oauth")))) { - return SetVisible(false); - } - if (Url.StartsWith(GetDummyUrl())) { - SetVisible(false); - FString Left, Right; - if (Url.Split(TEXT("authResult="), &Left, &Right, - ESearchCase::IgnoreCase)) { - return HandleAuthenticated(Right); - } - return HandleError(TEXT("Failed to match AuthResult in url")); - } - bShouldBeVisible = true; +void UThirdwebOAuthBrowserUserWidget::HandleUrlChanged(const FString& Url) +{ + TW_LOG(Verbose, TEXT("OAuthBrowserUserWidget::HandleUrlChanged::%s"), *Url); + if (Url.IsEmpty() || (Url.StartsWith(BackendUrlPrefix) && !Url.StartsWith(BackendUrlPrefix + TEXT("sdk/oauth")))) + { + return SetVisible(false); + } + if (Url.StartsWith(GetDummyUrl())) + { + SetVisible(false); + FString Left, Right; + if (Url.Split(TEXT("authResult="), &Left, &Right, ESearchCase::IgnoreCase)) + { + return HandleAuthenticated(Right); + } + return HandleError(TEXT("Failed to match AuthResult in url")); + } + bShouldBeVisible = true; } -void UThirdwebOAuthBrowserUserWidget::HandlePageLoaded(const FString &Url) { - if (bShouldBeVisible) { - SetVisible(true); - } +void UThirdwebOAuthBrowserUserWidget::HandlePageLoaded(const FString& Url) +{ + if (bShouldBeVisible) + { + SetVisible(true); + } } -void UThirdwebOAuthBrowserUserWidget::HandleOnBeforePopup( - const FString &Url, const FString &Frame) { - return OnPopup.Broadcast(Url, Frame); +void UThirdwebOAuthBrowserUserWidget::HandleOnBeforePopup(const FString& Url, const FString& Frame) +{ + return OnPopup.Broadcast(Url, Frame); } -void UThirdwebOAuthBrowserUserWidget::HandleAuthenticated( - const FString &AuthResult) { - OnAuthenticated.Broadcast(AuthResult); +void UThirdwebOAuthBrowserUserWidget::HandleAuthenticated(const FString& AuthResult) +{ + OnAuthenticated.Broadcast(AuthResult); } -void UThirdwebOAuthBrowserUserWidget::HandleSiweComplete( - const FString &Payload, const FString &Signature) { - if (IsInGameThread()) { - OnSiweComplete.Broadcast(Payload, Signature); - } else { - // Dispatch to game thread - TWeakObjectPtr WeakThis = this; - FFunctionGraphTask::CreateAndDispatchWhenReady( - [WeakThis, Payload, Signature]() { - if (WeakThis.IsValid()) { - WeakThis->OnSiweComplete.Broadcast(Payload, Signature); - } - }, - TStatId(), nullptr, ENamedThreads::GameThread); - } +void UThirdwebOAuthBrowserUserWidget::HandleSiweComplete(const FString& Payload, const FString& Signature) +{ + if (IsInGameThread()) + { + OnSiweComplete.Broadcast(Payload, Signature); + } + else + { + // Dispatch to game thread + TWeakObjectPtr WeakThis = this; + FFunctionGraphTask::CreateAndDispatchWhenReady([WeakThis, Payload, Signature]() + { + if (WeakThis.IsValid()) + { + WeakThis->OnSiweComplete.Broadcast(Payload, Signature); + } + }, + TStatId(), + nullptr, + ENamedThreads::GameThread); + } } -void UThirdwebOAuthBrowserUserWidget::HandleError(const FString &Error) { - OnError.Broadcast(Error); +void UThirdwebOAuthBrowserUserWidget::HandleError(const FString& Error) +{ + OnError.Broadcast(Error); } #if PLATFORM_ANDROID @@ -195,24 +205,30 @@ void UThirdwebOAuthBrowserUserWidget::HandleCustomTabsDismissed( } #endif -void UThirdwebOAuthBrowserUserWidget::SetVisible(const bool bVisible) { - // Mobile webview needs to be visible to work - if (bVisible) { - if (bCollapseWhenBlank) { +void UThirdwebOAuthBrowserUserWidget::SetVisible(const bool bVisible) +{ + // Mobile webview needs to be visible to work + if (bVisible) + { + if (bCollapseWhenBlank) + { #if PLATFORM_IOS | PLATFORM_ANDROID SetRenderOpacity(1.0f); #else - SetVisibility(ESlateVisibility::Visible); + SetVisibility(ESlateVisibility::Visible); #endif - } - } else { - bShouldBeVisible = false; - if (bCollapseWhenBlank) { + } + } + else + { + bShouldBeVisible = false; + if (bCollapseWhenBlank) + { #if PLATFORM_IOS | PLATFORM_ANDROID SetRenderOpacity(0.01f); #else - SetVisibility(ESlateVisibility::Collapsed); + SetVisibility(ESlateVisibility::Collapsed); #endif - } - } + } + } } diff --git a/Source/Thirdweb/Private/Browser/ThirdwebOAuthExternalBrowser.cpp b/Source/Thirdweb/Private/Browser/ThirdwebOAuthExternalBrowser.cpp index 4705c69..9e7feb6 100644 --- a/Source/Thirdweb/Private/Browser/ThirdwebOAuthExternalBrowser.cpp +++ b/Source/Thirdweb/Private/Browser/ThirdwebOAuthExternalBrowser.cpp @@ -12,37 +12,40 @@ #include "ThirdwebLog.h" #include "ThirdwebRuntimeSettings.h" -UThirdwebOAuthExternalBrowser::UThirdwebOAuthExternalBrowser() { - AuthEvent = nullptr; - State = Initialized; - bIsSiwe = false; +UThirdwebOAuthExternalBrowser::UThirdwebOAuthExternalBrowser() +{ + AuthEvent = nullptr; + State = Initialized; + bIsSiwe = false; } -void UThirdwebOAuthExternalBrowser::Authenticate(const FString &Link) { - // Clean up any previous authentication session - CleanupAuthentication(); - - // Reset state - State = Initialized; - bIsSiwe = false; - AuthResult.Empty(); - Signature.Empty(); - Payload.Empty(); - - FString Url = Link; - EModuleLoadResult ModuleResult; - FModuleManager::Get().LoadModuleWithFailureReason(FName(TEXT("HTTPServer")), - ModuleResult); - if (ModuleResult != EModuleLoadResult::Success) { - return HandleError(TEXT("Failed to load HTTPServer")); - } - - Router = FHttpServerModule::Get().GetHttpRouter(8789, true); - if (!Router.IsValid()) { - return HandleError(TEXT("Failed to get HTTP Router")); - } - - AuthEvent = FPlatformProcess::GetSynchEventFromPool(false); +void UThirdwebOAuthExternalBrowser::Authenticate(const FString& Link) +{ + // Clean up any previous authentication session + CleanupAuthentication(); + + // Reset state + State = Initialized; + bIsSiwe = false; + AuthResult.Empty(); + Signature.Empty(); + Payload.Empty(); + + FString Url = Link; + EModuleLoadResult ModuleResult; + FModuleManager::Get().LoadModuleWithFailureReason(FName(TEXT("HTTPServer")), ModuleResult); + if (ModuleResult != EModuleLoadResult::Success) + { + return HandleError(TEXT("Failed to load HTTPServer")); + } + + Router = FHttpServerModule::Get().GetHttpRouter(8789, true); + if (!Router.IsValid()) + { + return HandleError(TEXT("Failed to get HTTP Router")); + } + + AuthEvent = FPlatformProcess::GetSynchEventFromPool(false); #if UE_VERSION_OLDER_THAN(5, 4, 0) FHttpRequestHandler Handler = [WeakThis = MakeWeakObjectPtr(this)]( @@ -54,137 +57,149 @@ void UThirdwebOAuthExternalBrowser::Authenticate(const FString &Link) { return false; }; #else - FHttpRequestHandler Handler = FHttpRequestHandler::CreateUObject( - this, &UThirdwebOAuthExternalBrowser::CallbackRequestHandler); + FHttpRequestHandler Handler = FHttpRequestHandler::CreateUObject(this, &UThirdwebOAuthExternalBrowser::CallbackRequestHandler); #endif - RouteHandle = Router->BindRoute(FHttpPath(TEXT("/callback")), - EHttpServerRequestVerbs::VERB_GET, Handler); - - if (!RouteHandle.IsValid()) { - FPlatformProcess::ReturnSynchEventToPool(AuthEvent); - return HandleError(TEXT("Failed to bind route")); - } - - // Start the HTTP server - FHttpServerModule::Get().StartAllListeners(); - TW_LOG(VeryVerbose, - TEXT("OAuth HTTP Server started and listening on port 8789")); - - bIsSiwe = Url.ToUpper().TrimStartAndEnd().Equals(TEXT("SIWE")); - if (bIsSiwe) { - Url = FString::Printf( - TEXT("http://static.thirdweb.com/auth/siwe?redirectUrl=%s"), - *FGenericPlatformHttp::UrlEncode( - TEXT("http://localhost:8789/callback"))); - } - // Open the browser with the login URL - FPlatformProcess::LaunchURL(*Url, nullptr, nullptr); - TW_LOG(Verbose, TEXT("Browser opened with URL: %s"), *Url); - State = AuthPending; + RouteHandle = Router->BindRoute(FHttpPath(TEXT("/callback")), EHttpServerRequestVerbs::VERB_GET, Handler); + + if (!RouteHandle.IsValid()) + { + FPlatformProcess::ReturnSynchEventToPool(AuthEvent); + return HandleError(TEXT("Failed to bind route")); + } + + // Start the HTTP server + FHttpServerModule::Get().StartAllListeners(); + TW_LOG(VeryVerbose, TEXT("OAuth HTTP Server started and listening on port 8789")); + + bIsSiwe = Url.ToUpper().TrimStartAndEnd().Equals(TEXT("SIWE")); + if (bIsSiwe) + { + Url = FString::Printf(TEXT("http://static.thirdweb.com/auth/siwe?redirectUrl=%s"), + *FGenericPlatformHttp::UrlEncode(TEXT("http://localhost:8789/callback"))); + } + // Open the browser with the login URL + FPlatformProcess::LaunchURL(*Url, nullptr, nullptr); + TW_LOG(Verbose, TEXT("Browser opened with URL: %s"), *Url); + State = AuthPending; } -void UThirdwebOAuthExternalBrowser::Tick(float DeltaTime) { - if (State == AuthComplete) { - State = Complete; - - // Set the results based on the authentication - if (bIsSiwe) { - if (!Signature.IsEmpty() && !Payload.IsEmpty()) { - return HandleSuccess(); - } - } else { - if (!AuthResult.IsEmpty()) { - return HandleSuccess(); - } - } - - HandleError(TEXT("OAuth login flow did not complete in time")); - } +void UThirdwebOAuthExternalBrowser::Tick(float DeltaTime) +{ + if (State == AuthComplete) + { + State = Complete; + + // Set the results based on the authentication + if (bIsSiwe) + { + if (!Signature.IsEmpty() && !Payload.IsEmpty()) + { + return HandleSuccess(); + } + } + else + { + if (!AuthResult.IsEmpty()) + { + return HandleSuccess(); + } + } + + HandleError(TEXT("OAuth login flow did not complete in time")); + } } -void UThirdwebOAuthExternalBrowser::BeginDestroy() { - // Clean up authentication resources (idempotent) - CleanupAuthentication(); +void UThirdwebOAuthExternalBrowser::BeginDestroy() +{ + // Clean up authentication resources (idempotent) + CleanupAuthentication(); - // Stop the HTTP listener (this stops ALL listeners globally) - FHttpServerModule::Get().StopAllListeners(); - TW_LOG(VeryVerbose, TEXT("OAuth HTTP Server stopped listening")); + // Stop the HTTP listener (this stops ALL listeners globally) + FHttpServerModule::Get().StopAllListeners(); + TW_LOG(VeryVerbose, TEXT("OAuth HTTP Server stopped listening")); - ConditionalBeginDestroy(); - UObject::BeginDestroy(); + ConditionalBeginDestroy(); + UObject::BeginDestroy(); } -bool UThirdwebOAuthExternalBrowser::CallbackRequestHandler( - const FHttpServerRequest &Request, const FHttpResultCallback &OnComplete) { - AuthResult = Request.QueryParams.FindRef(TEXT("authResult")); - Signature = Request.QueryParams.FindRef(TEXT("signature")); - Payload = FGenericPlatformHttp::UrlDecode( - Request.QueryParams.FindRef(TEXT("payload"))); - TW_LOG(VeryVerbose, - TEXT("UThirdwebOAuthExternalBrowser::CallbackRequestHandler::" - "Signature=%s|Payload=%s|AuthResult=%s"), - *Signature, *Payload, *AuthResult) - if (bIsSiwe ? Signature.IsEmpty() || Payload.IsEmpty() - : AuthResult.IsEmpty()) { - FString Error = FString::Printf(TEXT("%s query parameter is missing"), - bIsSiwe ? TEXT("Signature/Payload") - : TEXT("AuthResult")); - TUniquePtr Response = - FHttpServerResponse::Create(Error, TEXT("text/plain")); - OnComplete(MoveTemp(Response)); - HandleError(Error); - } else { - State = AuthComplete; - AuthEvent->Trigger(); - TUniquePtr Response = FHttpServerResponse::Create( - FString::Printf( - TEXT(""), - *UThirdwebRuntimeSettings::GetExternalAuthRedirectUri()), - TEXT("text/html")); - OnComplete(MoveTemp(Response)); - } - return true; +bool UThirdwebOAuthExternalBrowser::CallbackRequestHandler(const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) +{ + AuthResult = Request.QueryParams.FindRef(TEXT("authResult")); + Signature = Request.QueryParams.FindRef(TEXT("signature")); + Payload = FGenericPlatformHttp::UrlDecode(Request.QueryParams.FindRef(TEXT("payload"))); + TW_LOG(VeryVerbose, + TEXT("UThirdwebOAuthExternalBrowser::CallbackRequestHandler::" "Signature=%s|Payload=%s|AuthResult=%s"), + *Signature, + *Payload, + *AuthResult) + if (bIsSiwe ? Signature.IsEmpty() || Payload.IsEmpty() : AuthResult.IsEmpty()) + { + FString Error = FString::Printf(TEXT("%s query parameter is missing"), bIsSiwe ? TEXT("Signature/Payload") : TEXT("AuthResult")); + TUniquePtr Response = FHttpServerResponse::Create(Error, TEXT("text/plain")); + OnComplete(MoveTemp(Response)); + HandleError(Error); + } + else + { + State = AuthComplete; + AuthEvent->Trigger(); + TUniquePtr Response = FHttpServerResponse::Create( + FString::Printf(TEXT(""), *UThirdwebRuntimeSettings::GetExternalAuthRedirectUri()), + TEXT("text/html")); + OnComplete(MoveTemp(Response)); + } + return true; } -void UThirdwebOAuthExternalBrowser::HandleSuccess() { - if (bIsSiwe) { - if (OnSiweComplete.IsBound()) { - OnSiweComplete.Execute(Payload, Signature); - } - } else { - if (OnAuthenticated.IsBound()) { - OnAuthenticated.Execute(AuthResult); - } - } - - // Clean up immediately after delegate fires - CleanupAuthentication(); +void UThirdwebOAuthExternalBrowser::HandleSuccess() +{ + if (bIsSiwe) + { + if (OnSiweComplete.IsBound()) + { + OnSiweComplete.Execute(Payload, Signature); + } + } + else + { + if (OnAuthenticated.IsBound()) + { + OnAuthenticated.Execute(AuthResult); + } + } + + // Clean up immediately after delegate fires + CleanupAuthentication(); } -void UThirdwebOAuthExternalBrowser::HandleError(const FString &Error) { - TW_LOG(VeryVerbose, TEXT("UThirdwebOAuthExternalBrowser::HandleError::%s"), - *Error); - if (OnError.IsBound()) { - OnError.Execute(Error); - } +void UThirdwebOAuthExternalBrowser::HandleError(const FString& Error) +{ + TW_LOG(VeryVerbose, TEXT("UThirdwebOAuthExternalBrowser::HandleError::%s"), *Error); + if (OnError.IsBound()) + { + OnError.Execute(Error); + } - // Clean up immediately after delegate fires - CleanupAuthentication(); + // Clean up immediately after delegate fires + CleanupAuthentication(); } -void UThirdwebOAuthExternalBrowser::CleanupAuthentication() { - // Unbind route if it exists - if (Router.IsValid() && RouteHandle.IsValid()) { - Router->UnbindRoute(RouteHandle); - RouteHandle = FHttpRouteHandle(); - TW_LOG(VeryVerbose, TEXT("Route unbound in cleanup")); - } - - // Return event to pool - if (AuthEvent) { - FPlatformProcess::ReturnSynchEventToPool(AuthEvent); - AuthEvent = nullptr; - TW_LOG(VeryVerbose, TEXT("AuthEvent returned to pool")); - } +void UThirdwebOAuthExternalBrowser::CleanupAuthentication() +{ + // Unbind route if it exists + if (Router.IsValid() && RouteHandle.IsValid()) + { + Router->UnbindRoute(RouteHandle); + RouteHandle = FHttpRouteHandle(); + TW_LOG(VeryVerbose, TEXT("Route unbound in cleanup")); + } + + // Return event to pool + if (AuthEvent) + { + FPlatformProcess::ReturnSynchEventToPool(AuthEvent); + AuthEvent = nullptr; + TW_LOG(VeryVerbose, TEXT("AuthEvent returned to pool")); + } } diff --git a/Source/Thirdweb/Private/Wallets/ThirdwebInAppWalletHandle.cpp b/Source/Thirdweb/Private/Wallets/ThirdwebInAppWalletHandle.cpp index 9cc5062..0958484 100644 --- a/Source/Thirdweb/Private/Wallets/ThirdwebInAppWalletHandle.cpp +++ b/Source/Thirdweb/Private/Wallets/ThirdwebInAppWalletHandle.cpp @@ -77,110 +77,114 @@ void FInAppWalletHandle::CreateEmailWallet(const FString& Email, const FCreateIn { CHECK_DELEGATES(SuccessDelegate, ErrorDelegate) - UE::Tasks::Launch(UE_SOURCE_LOCATION, [Email, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::create_ecosystem_wallet( - TO_RUST_STRING(UThirdwebRuntimeSettings::GetEcosystemId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetPartnerId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetClientId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetBundleId()), - nullptr, - TO_RUST_STRING(Email), - nullptr, - TO_RUST_STRING(UThirdwebRuntimeSettings::GetStorageDirectory()), - nullptr, - nullptr - ).AssignResult(Error)) - { - SuccessDelegate.Execute(FInAppWalletHandle(EInAppSource::Email, Error)); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [Email, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::create_ecosystem_wallet( + TO_RUST_STRING(UThirdwebRuntimeSettings::GetEcosystemId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetPartnerId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetClientId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetBundleId()), + nullptr, + TO_RUST_STRING(Email), + nullptr, + TO_RUST_STRING(UThirdwebRuntimeSettings::GetStorageDirectory()), + nullptr, + nullptr).AssignResult(Error)) + { + SuccessDelegate.Execute(FInAppWalletHandle(EInAppSource::Email, Error)); + return; + } + ErrorDelegate.Execute(Error); + }); } -void FInAppWalletHandle::CreateOAuthWallet(const EThirdwebOAuthProvider Provider, const FCreateInAppWalletDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) +void FInAppWalletHandle::CreateOAuthWallet(const EThirdwebOAuthProvider Provider, + const FCreateInAppWalletDelegate& SuccessDelegate, + const FStringDelegate& ErrorDelegate) { CHECK_DELEGATES(SuccessDelegate, ErrorDelegate) - UE::Tasks::Launch(UE_SOURCE_LOCATION, [Provider, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::create_ecosystem_wallet( - TO_RUST_STRING(UThirdwebRuntimeSettings::GetEcosystemId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetPartnerId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetClientId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetBundleId()), - nullptr, - nullptr, - nullptr, - TO_RUST_STRING(UThirdwebRuntimeSettings::GetStorageDirectory()), - TO_RUST_STRING(ThirdwebUtils::ToString(Provider)), - nullptr - ).AssignResult(Error)) - { - SuccessDelegate.Execute(FInAppWalletHandle(Provider, Error)); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [Provider, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::create_ecosystem_wallet( + TO_RUST_STRING(UThirdwebRuntimeSettings::GetEcosystemId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetPartnerId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetClientId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetBundleId()), + nullptr, + nullptr, + nullptr, + TO_RUST_STRING(UThirdwebRuntimeSettings::GetStorageDirectory()), + TO_RUST_STRING(ThirdwebUtils::ToString(Provider)), + nullptr).AssignResult(Error)) + { + SuccessDelegate.Execute(FInAppWalletHandle(Provider, Error)); + return; + } + ErrorDelegate.Execute(Error); + }); } void FInAppWalletHandle::CreatePhoneWallet(const FString& Phone, const FCreateInAppWalletDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) { CHECK_DELEGATES(SuccessDelegate, ErrorDelegate) - UE::Tasks::Launch(UE_SOURCE_LOCATION, [Phone, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::create_ecosystem_wallet( - TO_RUST_STRING(UThirdwebRuntimeSettings::GetEcosystemId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetPartnerId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetClientId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetBundleId()), - nullptr, - nullptr, - TO_RUST_STRING(Phone), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetStorageDirectory()), - nullptr, - nullptr - ).AssignResult(Error)) - { - SuccessDelegate.Execute(FInAppWalletHandle(EInAppSource::Phone, Error)); - return; - } - - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [Phone, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::create_ecosystem_wallet( + TO_RUST_STRING(UThirdwebRuntimeSettings::GetEcosystemId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetPartnerId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetClientId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetBundleId()), + nullptr, + nullptr, + TO_RUST_STRING(Phone), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetStorageDirectory()), + nullptr, + nullptr).AssignResult(Error)) + { + SuccessDelegate.Execute(FInAppWalletHandle(EInAppSource::Phone, Error)); + return; + } + + ErrorDelegate.Execute(Error); + }); } void FInAppWalletHandle::CreateSiweWallet(const FCreateInAppWalletDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) { CHECK_DELEGATES(SuccessDelegate, ErrorDelegate) - UE::Tasks::Launch(UE_SOURCE_LOCATION, [SuccessDelegate, ErrorDelegate] - { - static FString Provider = TEXT("Siwe"); - FString Error; - if (Thirdweb::create_ecosystem_wallet( - TO_RUST_STRING(UThirdwebRuntimeSettings::GetEcosystemId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetPartnerId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetClientId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetBundleId()), - nullptr, - nullptr, - nullptr, - TO_RUST_STRING(UThirdwebRuntimeSettings::GetStorageDirectory()), - TO_RUST_STRING(Provider), - nullptr - ).AssignResult(Error)) - { - SuccessDelegate.Execute(FInAppWalletHandle(Siwe, Error)); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [SuccessDelegate, ErrorDelegate] + { + static FString Provider = TEXT("Siwe"); + FString Error; + if (Thirdweb::create_ecosystem_wallet( + TO_RUST_STRING(UThirdwebRuntimeSettings::GetEcosystemId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetPartnerId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetClientId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetBundleId()), + nullptr, + nullptr, + nullptr, + TO_RUST_STRING(UThirdwebRuntimeSettings::GetStorageDirectory()), + TO_RUST_STRING(Provider), + nullptr).AssignResult(Error)) + { + SuccessDelegate.Execute(FInAppWalletHandle(Siwe, Error)); + return; + } + ErrorDelegate.Execute(Error); + }); } -void FInAppWalletHandle::CreateCustomAuthWallet(const EInAppSource Source, const FCreateInAppWalletDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) +void FInAppWalletHandle::CreateCustomAuthWallet(const EInAppSource Source, + const FCreateInAppWalletDelegate& SuccessDelegate, + const FStringDelegate& ErrorDelegate) { CHECK_DELEGATES(SuccessDelegate, ErrorDelegate) if (Source != Jwt && Source != AuthEndpoint && Source != Guest) @@ -191,28 +195,27 @@ void FInAppWalletHandle::CreateCustomAuthWallet(const EInAppSource Source, const } return; } - UE::Tasks::Launch(UE_SOURCE_LOCATION, [Source, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::create_ecosystem_wallet( - TO_RUST_STRING(UThirdwebRuntimeSettings::GetEcosystemId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetPartnerId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetClientId()), - TO_RUST_STRING(UThirdwebRuntimeSettings::GetBundleId()), - nullptr, - nullptr, - nullptr, - TO_RUST_STRING(UThirdwebRuntimeSettings::GetStorageDirectory()), - TO_RUST_STRING(FString(GetSourceString(Source))), - // legacy, will be used if migrating only - TO_RUST_STRING(UThirdwebRuntimeSettings::GetEncryptionKey()) - ).AssignResult(Error)) - { - SuccessDelegate.Execute(FInAppWalletHandle(Source, Error)); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [Source, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::create_ecosystem_wallet(TO_RUST_STRING(UThirdwebRuntimeSettings::GetEcosystemId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetPartnerId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetClientId()), + TO_RUST_STRING(UThirdwebRuntimeSettings::GetBundleId()), + nullptr, + nullptr, + nullptr, + TO_RUST_STRING(UThirdwebRuntimeSettings::GetStorageDirectory()), + TO_RUST_STRING(FString(GetSourceString(Source))), + // legacy, will be used if migrating only + TO_RUST_STRING(UThirdwebRuntimeSettings::GetEncryptionKey())).AssignResult(Error)) + { + SuccessDelegate.Execute(FInAppWalletHandle(Source, Error)); + return; + } + ErrorDelegate.Execute(Error); + }); } bool FInAppWalletHandle::IsConnected() const @@ -230,36 +233,37 @@ void FInAppWalletHandle::SendOTP(const FStreamableDelegate& SuccessDelegate, con CHECK_DELEGATES(SuccessDelegate, ErrorDelegate) CHECK_VALIDITY(ErrorDelegate) FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, SuccessDelegate, ErrorDelegate] - { - FString Error; - switch (ThisCopy.GetSource()) - { - case Phone: - { - if (Thirdweb::ecosystem_wallet_send_otp_phone(ThisCopy.GetID()).AssignResult(Error, true)) - { - SuccessDelegate.Execute(); - return; - } - break; - } - case Email: - { - if (Thirdweb::ecosystem_wallet_send_otp_email(ThisCopy.GetID()).AssignResult(Error, true)) - { - SuccessDelegate.Execute(); - return; - } - break; - } - default: - { - Error = TEXT("Wallet handle is not email/phone source"); - } - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, SuccessDelegate, ErrorDelegate] + { + FString Error; + switch (ThisCopy.GetSource()) + { + case Phone: + { + if (Thirdweb::ecosystem_wallet_send_otp_phone(ThisCopy.GetID()).AssignResult(Error, true)) + { + SuccessDelegate.Execute(); + return; + } + break; + } + case Email: + { + if (Thirdweb::ecosystem_wallet_send_otp_email(ThisCopy.GetID()).AssignResult(Error, true)) + { + SuccessDelegate.Execute(); + return; + } + break; + } + default: + { + Error = TEXT("Wallet handle is not email/phone source"); + } + } + ErrorDelegate.Execute(Error); + }); } void FInAppWalletHandle::SignInWithOTP(const FString& OTP, const FStreamableDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) @@ -272,38 +276,42 @@ void FInAppWalletHandle::SignInWithOTP(const FString& OTP, const FStreamableDele return; } FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, OTP, SuccessDelegate, ErrorDelegate] - { - FString Error; - switch (ThisCopy.GetSource()) - { - case Phone: - { - if (Thirdweb::ecosystem_wallet_sign_in_with_otp_phone(ThisCopy.GetID(), TO_RUST_STRING(OTP)).AssignResult(Error, true)) - { - ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); - SuccessDelegate.Execute(); - return; - } - break; - } - case Email: - { - if (Thirdweb::ecosystem_wallet_sign_in_with_otp_email(ThisCopy.GetID(), TO_RUST_STRING(OTP)).AssignResult(Error, true)) - { - ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); - SuccessDelegate.Execute(); - return; - } - break; - } - default: return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, OTP, SuccessDelegate, ErrorDelegate] + { + FString Error; + switch (ThisCopy.GetSource()) + { + case Phone: + { + if (Thirdweb::ecosystem_wallet_sign_in_with_otp_phone(ThisCopy.GetID(), TO_RUST_STRING(OTP)).AssignResult(Error, true)) + { + ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); + SuccessDelegate.Execute(); + return; + } + break; + } + case Email: + { + if (Thirdweb::ecosystem_wallet_sign_in_with_otp_email(ThisCopy.GetID(), TO_RUST_STRING(OTP)).AssignResult(Error, true)) + { + ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); + SuccessDelegate.Execute(); + return; + } + break; + } + default: return; + } + ErrorDelegate.Execute(Error); + }); } -void FInAppWalletHandle::LinkOTP(const FInAppWalletHandle& Wallet, const FString& OTP, const FStreamableDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) +void FInAppWalletHandle::LinkOTP(const FInAppWalletHandle& Wallet, + const FString& OTP, + const FStreamableDelegate& SuccessDelegate, + const FStringDelegate& ErrorDelegate) { CHECK_DELEGATES(SuccessDelegate, ErrorDelegate) CHECK_VALIDITY(ErrorDelegate) @@ -313,26 +321,25 @@ void FInAppWalletHandle::LinkOTP(const FInAppWalletHandle& Wallet, const FString return; } FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, Wallet, OTP, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::ecosystem_wallet_link_account( - ThisCopy.GetID(), - Wallet.GetID(), - TO_RUST_STRING(OTP), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr - ).AssignResult(Error, true)) - { - SuccessDelegate.Execute(); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, Wallet, OTP, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::ecosystem_wallet_link_account(ThisCopy.GetID(), + Wallet.GetID(), + TO_RUST_STRING(OTP), + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr).AssignResult(Error, true)) + { + SuccessDelegate.Execute(); + return; + } + ErrorDelegate.Execute(Error); + }); } bool FInAppWalletHandle::FetchOAuthLoginURL(const FString& RedirectUrl, FString& LoginLink, FString& Error) @@ -370,21 +377,25 @@ void FInAppWalletHandle::SignInWithOAuth(const FString& AuthResult, const FStrea } FString Result = ThirdwebUtils::ParseAuthResult(AuthResult); FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, Result, SuccessDelegate, ErrorDelegate] - { - FString Error; - TW_LOG(VeryVerbose, TEXT("FInAppWalletHandle::SignInWithOAuth::Task::%s"), *Result) - if (Thirdweb::ecosystem_wallet_sign_in_with_oauth(ThisCopy.GetID(), TO_RUST_STRING(Result)).AssignResult(Error, true)) - { - ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); - SuccessDelegate.Execute(); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, Result, SuccessDelegate, ErrorDelegate] + { + FString Error; + TW_LOG(VeryVerbose, TEXT("FInAppWalletHandle::SignInWithOAuth::Task::%s"), *Result) + if (Thirdweb::ecosystem_wallet_sign_in_with_oauth(ThisCopy.GetID(), TO_RUST_STRING(Result)).AssignResult(Error, true)) + { + ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); + SuccessDelegate.Execute(); + return; + } + ErrorDelegate.Execute(Error); + }); } -void FInAppWalletHandle::LinkOAuth(const FInAppWalletHandle& Wallet, const FString& AuthResult, const FStreamableDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) +void FInAppWalletHandle::LinkOAuth(const FInAppWalletHandle& Wallet, + const FString& AuthResult, + const FStreamableDelegate& SuccessDelegate, + const FStringDelegate& ErrorDelegate) { CHECK_DELEGATES(SuccessDelegate, ErrorDelegate) CHECK_VALIDITY(ErrorDelegate) @@ -392,26 +403,25 @@ void FInAppWalletHandle::LinkOAuth(const FInAppWalletHandle& Wallet, const FStri FString Result = ThirdwebUtils::ParseAuthResult(AuthResult); FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, Wallet, Result, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::ecosystem_wallet_link_account( - ThisCopy.GetID(), - Wallet.GetID(), - nullptr, - TO_RUST_STRING(Result), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr - ).AssignResult(Error, true)) - { - SuccessDelegate.Execute(); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, Wallet, Result, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::ecosystem_wallet_link_account(ThisCopy.GetID(), + Wallet.GetID(), + nullptr, + TO_RUST_STRING(Result), + nullptr, + nullptr, + nullptr, + nullptr, + nullptr).AssignResult(Error, true)) + { + SuccessDelegate.Execute(); + return; + } + ErrorDelegate.Execute(Error); + }); } void FInAppWalletHandle::SignInWithJwt(const FString& Jwt, const FStreamableDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) @@ -421,46 +431,49 @@ void FInAppWalletHandle::SignInWithJwt(const FString& Jwt, const FStreamableDele CHECK_SOURCE(EInAppSource::Jwt, ErrorDelegate) FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, Jwt, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::ecosystem_wallet_sign_in_with_jwt(ThisCopy.GetID(), TO_RUST_STRING(Jwt)).AssignResult(Error, true)) - { - ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); - SuccessDelegate.Execute(); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, Jwt, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::ecosystem_wallet_sign_in_with_jwt(ThisCopy.GetID(), TO_RUST_STRING(Jwt)).AssignResult(Error, true)) + { + ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); + SuccessDelegate.Execute(); + return; + } + ErrorDelegate.Execute(Error); + }); } -void FInAppWalletHandle::LinkJwt(const FInAppWalletHandle& Wallet, const FString& Jwt, const FStreamableDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) +void FInAppWalletHandle::LinkJwt(const FInAppWalletHandle& Wallet, + const FString& Jwt, + const FStreamableDelegate& SuccessDelegate, + const FStringDelegate& ErrorDelegate) { CHECK_DELEGATES(SuccessDelegate, ErrorDelegate) CHECK_VALIDITY(ErrorDelegate) CHECK_WALLET_SOURCE(Wallet, EInAppSource::Jwt, ErrorDelegate) FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, Wallet, Jwt, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::ecosystem_wallet_link_account( - ThisCopy.GetID(), - Wallet.GetID(), - nullptr, - nullptr, - TO_RUST_STRING(Jwt), - nullptr, - nullptr, - nullptr, - nullptr - ).AssignResult(Error, true)) - { - SuccessDelegate.Execute(); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, Wallet, Jwt, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::ecosystem_wallet_link_account(ThisCopy.GetID(), + Wallet.GetID(), + nullptr, + nullptr, + TO_RUST_STRING(Jwt), + nullptr, + nullptr, + nullptr, + nullptr).AssignResult(Error, true)) + { + SuccessDelegate.Execute(); + return; + } + ErrorDelegate.Execute(Error); + }); } void FInAppWalletHandle::SignInWithAuthEndpoint(const FString& Payload, const FStreamableDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) @@ -470,46 +483,49 @@ void FInAppWalletHandle::SignInWithAuthEndpoint(const FString& Payload, const FS CHECK_SOURCE(AuthEndpoint, ErrorDelegate) FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, Payload, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::ecosystem_wallet_sign_in_with_auth_endpoint(ThisCopy.GetID(), TO_RUST_STRING(Payload)).AssignResult(Error, true)) - { - ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); - SuccessDelegate.Execute(); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, Payload, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::ecosystem_wallet_sign_in_with_auth_endpoint(ThisCopy.GetID(), TO_RUST_STRING(Payload)).AssignResult(Error, true)) + { + ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); + SuccessDelegate.Execute(); + return; + } + ErrorDelegate.Execute(Error); + }); } -void FInAppWalletHandle::LinkAuthEndpoint(const FInAppWalletHandle& Wallet, const FString& Payload, const FStreamableDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) +void FInAppWalletHandle::LinkAuthEndpoint(const FInAppWalletHandle& Wallet, + const FString& Payload, + const FStreamableDelegate& SuccessDelegate, + const FStringDelegate& ErrorDelegate) { CHECK_DELEGATES(SuccessDelegate, ErrorDelegate) CHECK_VALIDITY(ErrorDelegate) CHECK_WALLET_SOURCE(Wallet, AuthEndpoint, ErrorDelegate) FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, Wallet, Payload, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::ecosystem_wallet_link_account( - ThisCopy.GetID(), - Wallet.GetID(), - nullptr, - nullptr, - nullptr, - TO_RUST_STRING(Payload), - nullptr, - nullptr, - nullptr - ).AssignResult(Error, true)) - { - SuccessDelegate.Execute(); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, Wallet, Payload, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::ecosystem_wallet_link_account(ThisCopy.GetID(), + Wallet.GetID(), + nullptr, + nullptr, + nullptr, + TO_RUST_STRING(Payload), + nullptr, + nullptr, + nullptr).AssignResult(Error, true)) + { + SuccessDelegate.Execute(); + return; + } + ErrorDelegate.Execute(Error); + }); } void FInAppWalletHandle::SignInWithGuest(const FStreamableDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) @@ -519,17 +535,20 @@ void FInAppWalletHandle::SignInWithGuest(const FStreamableDelegate& SuccessDeleg CHECK_SOURCE(Guest, ErrorDelegate) FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::ecosystem_wallet_sign_in_with_guest(ThisCopy.GetID(), TO_RUST_STRING(FPlatformMisc::GetLoginId())).AssignResult(Error, true)) - { - ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); - SuccessDelegate.Execute(); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::ecosystem_wallet_sign_in_with_guest(ThisCopy.GetID(), TO_RUST_STRING(FPlatformMisc::GetLoginId())).AssignResult( + Error, + true)) + { + ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); + SuccessDelegate.Execute(); + return; + } + ErrorDelegate.Execute(Error); + }); } void FInAppWalletHandle::LinkGuest(const FInAppWalletHandle& Wallet, const FStreamableDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) @@ -539,73 +558,83 @@ void FInAppWalletHandle::LinkGuest(const FInAppWalletHandle& Wallet, const FStre CHECK_WALLET_SOURCE(Wallet, Guest, ErrorDelegate) FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, Wallet, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::ecosystem_wallet_link_account( - ThisCopy.GetID(), - Wallet.GetID(), - nullptr, - nullptr, - nullptr, - nullptr, - TO_RUST_STRING(FPlatformMisc::GetLoginId()), - nullptr, - nullptr).AssignResult(Error, true)) - { - SuccessDelegate.Execute(); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, Wallet, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::ecosystem_wallet_link_account(ThisCopy.GetID(), + Wallet.GetID(), + nullptr, + nullptr, + nullptr, + nullptr, + TO_RUST_STRING(FPlatformMisc::GetLoginId()), + nullptr, + nullptr).AssignResult(Error, true)) + { + SuccessDelegate.Execute(); + return; + } + ErrorDelegate.Execute(Error); + }); } -void FInAppWalletHandle::SignInWithEthereum(const FString& Payload, const FString& Signature, const FStreamableDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) +void FInAppWalletHandle::SignInWithEthereum(const FString& Payload, + const FString& Signature, + const FStreamableDelegate& SuccessDelegate, + const FStringDelegate& ErrorDelegate) { CHECK_DELEGATES(SuccessDelegate, ErrorDelegate) CHECK_VALIDITY(ErrorDelegate) CHECK_SOURCE(Siwe, ErrorDelegate) FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, Payload, Signature, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::ecosystem_wallet_sign_in_with_siwe(ThisCopy.GetID(), TO_RUST_STRING(Payload), TO_RUST_STRING(Signature)).AssignResult(Error, true)) - { - ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); - SuccessDelegate.Execute(); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, Payload, Signature, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::ecosystem_wallet_sign_in_with_siwe(ThisCopy.GetID(), TO_RUST_STRING(Payload), TO_RUST_STRING(Signature)).AssignResult( + Error, + true)) + { + ThirdwebUtils::Internal::SendConnectEvent(ThisCopy); + SuccessDelegate.Execute(); + return; + } + ErrorDelegate.Execute(Error); + }); } -void FInAppWalletHandle::LinkSiwe(const FInAppWalletHandle& Wallet, const FString& Payload, const FString& Signature, const FStreamableDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) +void FInAppWalletHandle::LinkSiwe(const FInAppWalletHandle& Wallet, + const FString& Payload, + const FString& Signature, + const FStreamableDelegate& SuccessDelegate, + const FStringDelegate& ErrorDelegate) { CHECK_DELEGATES(SuccessDelegate, ErrorDelegate) CHECK_VALIDITY(ErrorDelegate) CHECK_WALLET_SOURCE(Wallet, Siwe, ErrorDelegate) FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, Wallet, Payload, Signature, SuccessDelegate, ErrorDelegate] - { - FString Error; - if (Thirdweb::ecosystem_wallet_link_account( - ThisCopy.GetID(), - Wallet.GetID(), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - TO_RUST_STRING(Payload), - TO_RUST_STRING(Signature)).AssignResult(Error, true)) - { - SuccessDelegate.Execute(); - return; - } - ErrorDelegate.Execute(Error); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, Wallet, Payload, Signature, SuccessDelegate, ErrorDelegate] + { + FString Error; + if (Thirdweb::ecosystem_wallet_link_account(ThisCopy.GetID(), + Wallet.GetID(), + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + TO_RUST_STRING(Payload), + TO_RUST_STRING(Signature)).AssignResult(Error, true)) + { + SuccessDelegate.Execute(); + return; + } + ErrorDelegate.Execute(Error); + }); } void FInAppWalletHandle::GetLinkedAccounts(const FGetLinkedAccountsDelegate& SuccessDelegate, const FStringDelegate& ErrorDelegate) @@ -614,25 +643,26 @@ void FInAppWalletHandle::GetLinkedAccounts(const FGetLinkedAccountsDelegate& Suc CHECK_VALIDITY(ErrorDelegate) FInAppWalletHandle ThisCopy = *this; - UE::Tasks::Launch(UE_SOURCE_LOCATION, [ThisCopy, SuccessDelegate, ErrorDelegate] - { - FString Output; - if (Thirdweb::ecosystem_wallet_get_linked_accounts(ThisCopy.GetID()).AssignResult(Output)) - { - TArray LinkedAccounts; - TArray> JsonValueArray = ThirdwebUtils::Json::ToJsonArray(Output); - for (int i = 0; i < JsonValueArray.Num(); i++) - { - if (JsonValueArray[i]->Type == EJson::Object) - { - LinkedAccounts.Emplace(FThirdwebLinkedAccount::FromJson(JsonValueArray[i]->AsObject())); - } - } - SuccessDelegate.Execute(LinkedAccounts); - return; - } - ErrorDelegate.Execute(Output); - }); + UE::Tasks::Launch(UE_SOURCE_LOCATION, + [ThisCopy, SuccessDelegate, ErrorDelegate] + { + FString Output; + if (Thirdweb::ecosystem_wallet_get_linked_accounts(ThisCopy.GetID()).AssignResult(Output)) + { + TArray LinkedAccounts; + TArray> JsonValueArray = ThirdwebUtils::Json::ToJsonArray(Output); + for (int i = 0; i < JsonValueArray.Num(); i++) + { + if (JsonValueArray[i]->Type == EJson::Object) + { + LinkedAccounts.Emplace(FThirdwebLinkedAccount::FromJson(JsonValueArray[i]->AsObject())); + } + } + SuccessDelegate.Execute(LinkedAccounts); + return; + } + ErrorDelegate.Execute(Output); + }); } FString FInAppWalletHandle::GetDisplayName() const