diff --git a/Content/BlueprintSampleContent/ImtblAuthenticatedWidget4_26.uasset b/Content/BlueprintSampleContent/ImtblAuthenticatedWidget4_26.uasset index 9ee2db9..621518c 100644 Binary files a/Content/BlueprintSampleContent/ImtblAuthenticatedWidget4_26.uasset and b/Content/BlueprintSampleContent/ImtblAuthenticatedWidget4_26.uasset differ diff --git a/Content/BlueprintSampleContent/ImtblEvmBalanceWidget4_26.uasset b/Content/BlueprintSampleContent/ImtblEvmBalanceWidget4_26.uasset index 20f3575..ec4415b 100644 Binary files a/Content/BlueprintSampleContent/ImtblEvmBalanceWidget4_26.uasset and b/Content/BlueprintSampleContent/ImtblEvmBalanceWidget4_26.uasset differ diff --git a/Content/BlueprintSampleContent/ImtblEvmTransactionReceiptWidget4_26.uasset b/Content/BlueprintSampleContent/ImtblEvmTransactionReceiptWidget4_26.uasset new file mode 100644 index 0000000..7a96012 Binary files /dev/null and b/Content/BlueprintSampleContent/ImtblEvmTransactionReceiptWidget4_26.uasset differ diff --git a/Content/PackagedResources/index.uasset b/Content/PackagedResources/index.uasset index ea7236b..96628f7 100644 Binary files a/Content/PackagedResources/index.uasset and b/Content/PackagedResources/index.uasset differ diff --git a/Source/Immutable/Private/Immutable/Actions/ImtblPassportZkEvmGetTransactionReceiptAA.cpp b/Source/Immutable/Private/Immutable/Actions/ImtblPassportZkEvmGetTransactionReceiptAA.cpp new file mode 100644 index 0000000..d34c8b2 --- /dev/null +++ b/Source/Immutable/Private/Immutable/Actions/ImtblPassportZkEvmGetTransactionReceiptAA.cpp @@ -0,0 +1,64 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Immutable/Actions/ImtblPassportZkEvmGetTransactionReceiptAA.h" + +#include "Immutable/ImmutablePassport.h" +#include "Immutable/ImmutableSubsystem.h" +#include "Immutable/Misc/ImtblLogging.h" + +UImtblPassportZkEvmGetTransactionReceiptAA* UImtblPassportZkEvmGetTransactionReceiptAA::ZkEvmGetTransactionReceipt(UObject* WorldContextObject, const FString& Hash) +{ + UImtblPassportZkEvmGetTransactionReceiptAA* PassportZkEvmSendTransactionBlueprintNode = NewObject(); + + PassportZkEvmSendTransactionBlueprintNode->WorldContextObject = WorldContextObject; + PassportZkEvmSendTransactionBlueprintNode->Hash = Hash; + + return PassportZkEvmSendTransactionBlueprintNode; +} + +void UImtblPassportZkEvmGetTransactionReceiptAA::Activate() +{ + if (!WorldContextObject || !WorldContextObject->GetWorld()) + { + const FString ErrorMessage = "ZkEvmSendTransaction failed due to missing world or world " "context object."; + IMTBL_WARN("%s", *ErrorMessage) + Failed.Broadcast(ErrorMessage, FZkEvmTransactionReceipt()); + return; + } + + GetSubsystem()->WhenReady(this, &UImtblPassportZkEvmGetTransactionReceiptAA::DoZkEvmGetTransactionReceipt); +} + +void UImtblPassportZkEvmGetTransactionReceiptAA::DoZkEvmGetTransactionReceipt(TWeakObjectPtr JSConnector) +{ + auto Passport = GetSubsystem()->GetPassport(); + + if (Passport.IsValid()) + { + Passport->ZkEvmGetTransactionReceipt({ Hash }, UImmutablePassport::FImtblPassportResponseDelegate::CreateUObject(this, &UImtblPassportZkEvmGetTransactionReceiptAA::OnZkEvmGetTransactionReceiptResponse)); + } +} + +void UImtblPassportZkEvmGetTransactionReceiptAA::OnZkEvmGetTransactionReceiptResponse(FImmutablePassportResult Result) +{ + if (Result.Success) + { + auto Receipt = JsonObjectToUStruct(Result.Response.JsonObject); + + if (Receipt.IsSet()) + { + IMTBL_LOG("ZkEvmGetTransactionReceipt success") + Success.Broadcast(TEXT(""), Receipt.GetValue()); + } + else + { + IMTBL_LOG("ZkEvm Transaction Receipt is not provided") + Success.Broadcast(TEXT(""), FZkEvmTransactionReceipt()); + } + } + else + { + IMTBL_LOG("ZkEvmGetTransactionReceipt failed") + Failed.Broadcast(Result.Message, FZkEvmTransactionReceipt()); + } +} diff --git a/Source/Immutable/Private/Immutable/ImmutableBlueprintLibrary.cpp b/Source/Immutable/Private/Immutable/ImmutableBlueprintLibrary.cpp new file mode 100644 index 0000000..7fa7ded --- /dev/null +++ b/Source/Immutable/Private/Immutable/ImmutableBlueprintLibrary.cpp @@ -0,0 +1,37 @@ +#include "Immutable/ImmutableBlueprintLibrary.h" + + +void UImmutableBlueprintLibrary::BreakFZkEvmTransactionReceiptLog(FZkEvmTransactionReceiptLog Log, FString& Address, FString& Data, + FString& BlockNumber, FString& TransactionHash, FString& TransactionIndex, FString& BlockHash, FString& LogIndex, bool& Removed, + TArray& Topics) +{ + Address = Log.address; + Data = Log.data; + BlockNumber = Log.blockNumber; + TransactionHash = Log.transactionHash; + TransactionIndex = Log.transactionIndex; + BlockHash = Log.blockHash; + LogIndex = Log.logIndex; + Removed = Log.removed; + Topics = Log.topics; +} + +void UImmutableBlueprintLibrary::BreakZkEvmTransactionReceipt(FZkEvmTransactionReceipt Receipt, FString& BlockHash, FString& BlockNumber, + FString& ContractAddress, FString& CumulativeGasUsed, FString& EffectiveGasPrice, FString& From, FString& GasUsed, FString& LogsBloom, + FString& Status, FString& To, FString& TransactionHash, FString& TransactionIndex, FString& Type, TArray& Logs) +{ + BlockHash = Receipt.blockHash; + BlockNumber = Receipt.blockNumber; + ContractAddress = Receipt.contractAddress; + CumulativeGasUsed = Receipt.cumulativeGasUsed; + EffectiveGasPrice = Receipt.effectiveGasPrice; + From = Receipt.from; + GasUsed = Receipt.gasUsed; + LogsBloom = Receipt.logsBloom; + Status = Receipt.status; + To = Receipt.to; + TransactionHash = Receipt.transactionHash; + TransactionIndex = Receipt.transactionIndex; + Type = Receipt.type; + Logs = Receipt.logs; +} diff --git a/Source/Immutable/Private/Immutable/ImmutablePassport.cpp b/Source/Immutable/Private/Immutable/ImmutablePassport.cpp index 260dbba..e9ffd37 100644 --- a/Source/Immutable/Private/Immutable/ImmutablePassport.cpp +++ b/Source/Immutable/Private/Immutable/ImmutablePassport.cpp @@ -116,6 +116,11 @@ void UImmutablePassport::ZkEvmSendTransaction(const FImtblTransactionRequest& Re CallJS(ImmutablePassportAction::ZkEvmSendTransaction, UStructToJsonString(Request), ResponseDelegate, FImtblJSResponseDelegate::CreateUObject(this, &UImmutablePassport::OnZkEvmSendTransactionResponse)); } +void UImmutablePassport::ZkEvmGetTransactionReceipt(const FZkEvmTransactionReceiptRequest& Request, const FImtblPassportResponseDelegate& ResponseDelegate) +{ + CallJS(ImmutablePassportAction::ZkEvmGetTransactionReceipt, UStructToJsonString(Request), ResponseDelegate, FImtblJSResponseDelegate::CreateUObject(this, &UImmutablePassport::OnZkEvmGetTransactionReceiptResponse)); +} + void UImmutablePassport::ConfirmCode(const FString& DeviceCode, const float Interval, const FImtblPassportResponseDelegate& ResponseDelegate) { FImmutablePassportCodeConfirmRequestData Data{DeviceCode, Interval}; @@ -647,6 +652,23 @@ void UImmutablePassport::OnZkEvmSendTransactionResponse(FImtblJSResponse Respons } } +void UImmutablePassport::OnZkEvmGetTransactionReceiptResponse(FImtblJSResponse Response) +{ + if (auto ResponseDelegate = GetResponseDelegate(Response)) + { + FString Msg; + bool bSuccess = true; + + if (!Response.success) + { + IMTBL_WARN("zkEVM transaction receipt retrieval failed."); + Response.Error.IsSet() ? Msg = Response.Error->ToString() : Msg = Response.JsonObject->GetStringField(TEXT("error")); + bSuccess = false; + } + ResponseDelegate->ExecuteIfBound(FImmutablePassportResult{bSuccess, Msg, Response}); + } +} + void UImmutablePassport::OnConfirmCodeResponse(FImtblJSResponse Response) { if (auto ResponseDelegate = GetResponseDelegate(Response)) diff --git a/Source/Immutable/Public/Immutable/Actions/ImtblPassportZkEvmGetTransactionReceiptAA.h b/Source/Immutable/Public/Immutable/Actions/ImtblPassportZkEvmGetTransactionReceiptAA.h new file mode 100644 index 0000000..fa9a8ee --- /dev/null +++ b/Source/Immutable/Public/Immutable/Actions/ImtblPassportZkEvmGetTransactionReceiptAA.h @@ -0,0 +1,38 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Immutable/ImmutablePassport.h" +#include "ImtblBlueprintAsyncAction.h" + +#include "ImtblPassportZkEvmGetTransactionReceiptAA.generated.h" + + +/** + * + */ +UCLASS() +class IMMUTABLE_API UImtblPassportZkEvmGetTransactionReceiptAA : public UImtblBlueprintAsyncAction +{ + GENERATED_BODY() + + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FZkEvmGetTransactionReceiptOutputPin, FString, ErrorMessage, const struct FZkEvmTransactionReceipt&, Receipt); + +public: + UFUNCTION(BlueprintCallable, meta = (WorldContext = "WorldContextObject", BlueprintInternalUseOnly = "true"), Category = "Immutable") + static UImtblPassportZkEvmGetTransactionReceiptAA* ZkEvmGetTransactionReceipt(UObject* WorldContextObject, const FString& Hash); + + virtual void Activate() override; + +private: + FString Hash; + + UPROPERTY(BlueprintAssignable) + FZkEvmGetTransactionReceiptOutputPin Success; + UPROPERTY(BlueprintAssignable) + FZkEvmGetTransactionReceiptOutputPin Failed; + + void DoZkEvmGetTransactionReceipt(TWeakObjectPtr JSGetConnector); + void OnZkEvmGetTransactionReceiptResponse(FImmutablePassportResult Result); +}; diff --git a/Source/Immutable/Public/Immutable/ImmutableBlueprintLibrary.h b/Source/Immutable/Public/Immutable/ImmutableBlueprintLibrary.h new file mode 100644 index 0000000..05254d7 --- /dev/null +++ b/Source/Immutable/Public/Immutable/ImmutableBlueprintLibrary.h @@ -0,0 +1,22 @@ +#pragma once + +#include "Kismet/BlueprintFunctionLibrary.h" +#include "Immutable/ImmutableDataTypes.h" + +#include "ImmutableBlueprintLibrary.generated.h" + + +UCLASS() +class IMMUTABLE_API UImmutableBlueprintLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + + UFUNCTION(BlueprintPure, Category = "Immutable", meta = (NativeBreakFunc)) + static void BreakFZkEvmTransactionReceiptLog(FZkEvmTransactionReceiptLog Log, FString& Address, FString& Data, FString& BlockNumber, FString& TransactionHash, FString& TransactionIndex, FString& BlockHash, FString& LogIndex, bool& Removed, TArray& Topics); + + UFUNCTION(BlueprintPure, Category = "Immutable", meta = (NativeBreakFunc)) + static void BreakZkEvmTransactionReceipt(FZkEvmTransactionReceipt Receipt, FString& BlockHash, FString& BlockNumber, FString& ContractAddress, FString& CumulativeGasUsed, FString& EffectiveGasPrice, FString& From, FString& GasUsed, FString& LogsBloom, FString& Status, FString& To, FString& TransactionHash, FString& TransactionIndex, FString& Type, TArray& Logs); + +}; \ No newline at end of file diff --git a/Source/Immutable/Public/Immutable/ImmutableDataTypes.h b/Source/Immutable/Public/Immutable/ImmutableDataTypes.h index 6fbcff4..65f78a9 100644 --- a/Source/Immutable/Public/Immutable/ImmutableDataTypes.h +++ b/Source/Immutable/Public/Immutable/ImmutableDataTypes.h @@ -184,3 +184,86 @@ struct FNftTransferDetails UPROPERTY(BlueprintReadWrite) FString tokenAddress; }; + + +USTRUCT(BlueprintType, meta = (HasNativeBreak = "/Script/Immutable.ImmutableBlueprintLibrary.BreakFZkEvmTransactionReceiptLog")) +struct IMMUTABLE_API FZkEvmTransactionReceiptLog +{ + GENERATED_BODY() + + UPROPERTY() + FString address; + + UPROPERTY() + TArray topics; + + UPROPERTY() + FString data; + + UPROPERTY() + FString blockNumber; + + UPROPERTY() + FString transactionHash; + + UPROPERTY() + FString transactionIndex; + + UPROPERTY() + FString blockHash; + + UPROPERTY() + FString logIndex; + + UPROPERTY() + bool removed; +}; + +USTRUCT(BlueprintType, meta = (HasNativeBreak = "/Script/Immutable.ImmutableBlueprintLibrary.BreakZkEvmTransactionReceipt")) +struct IMMUTABLE_API FZkEvmTransactionReceipt +{ + GENERATED_BODY() + + UPROPERTY() + FString blockHash; + + UPROPERTY() + FString blockNumber; + + UPROPERTY() + FString contractAddress; + + UPROPERTY() + FString cumulativeGasUsed; + + UPROPERTY() + FString effectiveGasPrice; + + UPROPERTY() + FString from; + + UPROPERTY() + FString gasUsed; + + UPROPERTY(BlueprintReadOnly) + TArray logs; + + UPROPERTY() + FString logsBloom; + + // Either 1 (success) or 0 (failure) encoded as a hexadecimal. + UPROPERTY() + FString status; + + UPROPERTY() + FString to; + + UPROPERTY() + FString transactionHash; + + UPROPERTY() + FString transactionIndex; + + UPROPERTY() + FString type; +}; \ No newline at end of file diff --git a/Source/Immutable/Public/Immutable/ImmutableNames.h b/Source/Immutable/Public/Immutable/ImmutableNames.h index bc52a4f..0edb262 100644 --- a/Source/Immutable/Public/Immutable/ImmutableNames.h +++ b/Source/Immutable/Public/Immutable/ImmutableNames.h @@ -14,6 +14,7 @@ namespace ImmutablePassportAction const FString ZkEvmRequestAccounts = TEXT("zkEvmRequestAccounts"); const FString ZkEvmGetBalance = TEXT("zkEvmGetBalance"); const FString ZkEvmSendTransaction = TEXT("zkEvmSendTransaction"); + const FString ZkEvmGetTransactionReceipt = TEXT("zkEvmGetTransactionReceipt"); #if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC const FString GetPKCEAuthUrl = TEXT("getPKCEAuthUrl"); diff --git a/Source/Immutable/Public/Immutable/ImmutablePassport.h b/Source/Immutable/Public/Immutable/ImmutablePassport.h index a539fbd..6c4c208 100644 --- a/Source/Immutable/Public/Immutable/ImmutablePassport.h +++ b/Source/Immutable/Public/Immutable/ImmutablePassport.h @@ -103,6 +103,16 @@ class IMMUTABLE_API UImmutablePassport : public UObject * FImtblPassportResponseDelegate to call on response from JS. */ void ZkEvmSendTransaction(const FImtblTransactionRequest& Request, const FImtblPassportResponseDelegate& ResponseDelegate); + + /** + * Retrieves the transaction information of a given transaction hash. This function uses the Ethereum JSON-RPC + * eth_getTransactionReceipt method. Response will contain the receipt of the transaction or null if it is still processing. + * @param Request The request data(Hash) to perform the transaction. + * @param ResponseDelegate The response delegate of type + * FImtblPassportResponseDelegate to call on response from JS. + */ + void ZkEvmGetTransactionReceipt(const FZkEvmTransactionReceiptRequest& Request, const FImtblPassportResponseDelegate& ResponseDelegate); + void GetIdToken(const FImtblPassportResponseDelegate& ResponseDelegate); void GetAccessToken(const FImtblPassportResponseDelegate& ResponseDelegate); void GetAddress(const FImtblPassportResponseDelegate& ResponseDelegate); @@ -194,6 +204,7 @@ class IMMUTABLE_API UImmutablePassport : public UObject void OnZkEvmRequestAccountsResponse(FImtblJSResponse Response); void OnZkEvmGetBalanceResponse(FImtblJSResponse Response); void OnZkEvmSendTransactionResponse(FImtblJSResponse Response); + void OnZkEvmGetTransactionReceiptResponse(FImtblJSResponse Response); void OnConfirmCodeResponse(FImtblJSResponse Response); #if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC void OnGetPKCEAuthUrlResponse(FImtblJSResponse Response); diff --git a/Source/Immutable/Public/Immutable/ImmutableRequests.h b/Source/Immutable/Public/Immutable/ImmutableRequests.h index 42d0a95..4132866 100644 --- a/Source/Immutable/Public/Immutable/ImmutableRequests.h +++ b/Source/Immutable/Public/Immutable/ImmutableRequests.h @@ -19,7 +19,7 @@ struct IMMUTABLE_API FImtblTransactionRequest FString value; }; -USTRUCT() +USTRUCT(BlueprintType) struct IMMUTABLE_API FImxTransferRequest { GENERATED_BODY() @@ -42,7 +42,7 @@ struct IMMUTABLE_API FImxTransferRequest FString ToJsonString() const; }; -USTRUCT() +USTRUCT(BlueprintType) struct IMMUTABLE_API FImxBatchNftTransferRequest { GENERATED_BODY() @@ -52,3 +52,12 @@ struct IMMUTABLE_API FImxBatchNftTransferRequest FString ToJsonString() const; }; + +USTRUCT(BlueprintType) +struct IMMUTABLE_API FZkEvmTransactionReceiptRequest +{ + GENERATED_BODY() + + UPROPERTY() + FString txHash; +};