diff --git a/sample/Assets/Scenes/ZkEvmSendTransaction.unity b/sample/Assets/Scenes/ZkEvmSendTransaction.unity index 5ed8e606..7b835cf7 100644 --- a/sample/Assets/Scenes/ZkEvmSendTransaction.unity +++ b/sample/Assets/Scenes/ZkEvmSendTransaction.unity @@ -318,6 +318,86 @@ MonoBehaviour: m_ChildScaleWidth: 0 m_ChildScaleHeight: 0 m_ReverseArrangement: 0 +--- !u!1 &59520625 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 59520626} + - component: {fileID: 59520628} + - component: {fileID: 59520627} + m_Layer: 5 + m_Name: Label + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &59520626 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 59520625} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1873101808} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 214.26965, y: -0.5} + m_SizeDelta: {x: 308.5393, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &59520627 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 59520625} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Get Transaction Receipt +--- !u!222 &59520628 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 59520625} + m_CullTransparentMesh: 1 --- !u!1 &66309837 GameObject: m_ObjectHideFlags: 0 @@ -478,7 +558,7 @@ MonoBehaviour: m_HandleRect: {fileID: 66309838} m_Direction: 0 m_Value: 0 - m_Size: 0.9999999 + m_Size: 0.99999994 m_NumberOfSteps: 0 m_OnValueChanged: m_PersistentCalls: @@ -1316,6 +1396,83 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 885137215} m_CullTransparentMesh: 1 +--- !u!1 &940303762 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 940303763} + - component: {fileID: 940303765} + - component: {fileID: 940303764} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &940303763 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 940303762} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1699155305} + m_Father: {fileID: 1873101808} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 20, y: 0} + m_SizeDelta: {x: 40, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &940303764 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 940303762} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &940303765 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 940303762} + m_CullTransparentMesh: 1 --- !u!1 &946061952 GameObject: m_ObjectHideFlags: 0 @@ -1858,6 +2015,7 @@ MonoBehaviour: m_EditorClassIdentifier: Output: {fileID: 1253661940} ConfirmToggle: {fileID: 1782090444} + GetTrasactionReceiptToggle: {fileID: 1873101809} ToInputField: {fileID: 649013321} ValueInputField: {fileID: 1901422923} DataInputField: {fileID: 1391622483} @@ -2282,6 +2440,7 @@ RectTransform: - {fileID: 946061953} - {fileID: 1799347062} - {fileID: 1782090443} + - {fileID: 1873101808} - {fileID: 1812049870} m_Father: {fileID: 1227009913} m_RootOrder: 0 @@ -2783,6 +2942,82 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1550326031} m_CullTransparentMesh: 1 +--- !u!1 &1699155304 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1699155305} + - component: {fileID: 1699155307} + - component: {fileID: 1699155306} + m_Layer: 5 + m_Name: Checkmark + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1699155305 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1699155304} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 940303763} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 30, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1699155306 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1699155304} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10901, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1699155307 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1699155304} + m_CullTransparentMesh: 1 --- !u!1 &1741513412 GameObject: m_ObjectHideFlags: 0 @@ -3043,7 +3278,7 @@ RectTransform: - {fileID: 1105336909} - {fileID: 1915690145} m_Father: {fileID: 1343113122} - m_RootOrder: 5 + m_RootOrder: 6 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -3229,6 +3464,93 @@ RectTransform: m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: -20, y: -20} m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1873101807 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1873101808} + - component: {fileID: 1873101809} + m_Layer: 5 + m_Name: GetTransactionReceiptToggle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1873101808 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1873101807} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 940303763} + - {fileID: 59520626} + m_Father: {fileID: 1343113122} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 1011.6831, y: -446} + m_SizeDelta: {x: 1991.3662, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1873101809 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1873101807} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9085046f02f69544eb97fd06b6048fe2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 940303764} + toggleTransition: 1 + graphic: {fileID: 1699155306} + m_Group: {fileID: 0} + onValueChanged: + m_PersistentCalls: + m_Calls: [] + m_IsOn: 1 --- !u!1 &1901422919 GameObject: m_ObjectHideFlags: 0 diff --git a/sample/Assets/Scripts/ZkEvm/ZkEvmSendTransactionScript.cs b/sample/Assets/Scripts/ZkEvm/ZkEvmSendTransactionScript.cs index 4bd69adc..b99b30db 100644 --- a/sample/Assets/Scripts/ZkEvm/ZkEvmSendTransactionScript.cs +++ b/sample/Assets/Scripts/ZkEvm/ZkEvmSendTransactionScript.cs @@ -1,9 +1,11 @@ using System; +using System.Threading; using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement; using Immutable.Passport; using Immutable.Passport.Model; +using Cysharp.Threading.Tasks; public class ZkEvmSendTransactionScript : MonoBehaviour { @@ -11,6 +13,7 @@ public class ZkEvmSendTransactionScript : MonoBehaviour [SerializeField] private Text Output; [SerializeField] private Toggle ConfirmToggle; + [SerializeField] private Toggle GetTrasactionReceiptToggle; [SerializeField] private InputField ToInputField; [SerializeField] private InputField ValueInputField; [SerializeField] private InputField DataInputField; @@ -24,6 +27,12 @@ void Start() { // Get Passport instance Passport = Passport.Instance; + + // Show get transaction receipt option if send transaction with confirmation toggle is off + ConfirmToggle.onValueChanged.AddListener(delegate + { + GetTrasactionReceiptToggle.gameObject.SetActive(!ConfirmToggle.isOn); + }); } else { @@ -39,7 +48,7 @@ void Start() /// public async void SendTransaction() { - ShowOutput("Called sendTransaction()..."); + ShowOutput("Sending transaction..."); try { @@ -51,22 +60,67 @@ public async void SendTransaction() data = DataInputField.text }; - // Send transaction with or without confirmation + // Check if confirmation is requested if (ConfirmToggle.isOn) { + // Send transaction with confirmation and display transaction status upon completion TransactionReceiptResponse response = await Passport.ZkEvmSendTransactionWithConfirmation(request); ShowOutput($"Transaction hash: {response.transactionHash}\nStatus: {GetTransactionStatusString(response.status)}"); } else { - string response = await Passport.ZkEvmSendTransaction(request); - ShowOutput($"Transaction hash: {response}"); + // Send transaction without confirmation + string transactionHash = await Passport.ZkEvmSendTransaction(request); + + // Check if receipt is requested + if (GetTrasactionReceiptToggle.isOn) + { + // Poll for the receipt and display transaction status + string? status = await PollStatus(transactionHash); + ShowOutput($"Transaction hash: {transactionHash}\nStatus: {GetTransactionStatusString(status)}"); + } + else + { + ShowOutput($"Transaction hash: {transactionHash}"); + } } } catch (Exception ex) { - ShowOutput($"Failed to request accounts: {ex.Message}"); + ShowOutput($"Failed to send transaction: {ex.Message}"); + } + } + + /// + /// Polls the status of the given transaction hash until either a status is retrieved or a timeout occurs. + /// + /// The hash of the transaction to poll. + /// The status of the transaction, or null if a timeout occurs. + static async UniTask PollStatus(string transactionHash) + { + var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + try + { + while (!cancellationTokenSource.Token.IsCancellationRequested) + { + TransactionReceiptResponse response = await Passport.Instance.ZkEvmGetTransactionReceipt(transactionHash); + if (response.status == null) + { + // The transaction is still being processed, poll for status again + await UniTask.Delay(delayTimeSpan: TimeSpan.FromSeconds(1), cancellationToken: cancellationTokenSource.Token); + } + else + { + return response.status; + } + } + } + catch (OperationCanceledException) + { + // Task was canceled due to timeout } + + return null; // Timeout or could not get transaction receipt } /// @@ -74,7 +128,7 @@ public async void SendTransaction() /// /// The transaction status code. /// A string representing the status. - private string GetTransactionStatusString(string status) + private string GetTransactionStatusString(string? status) { switch (status) {