Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b136ff4

Browse files
authoredOct 25, 2024··
Merge pull request #327 from immutable/chore/update-version-1.28.0
chore: update version
2 parents e8d89db + b0e3fe8 commit b136ff4

21 files changed

+31371
-3
lines changed
 

‎src/Packages/Marketplace/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "com.immutable.marketplace",
3-
"version": "1.27.2",
3+
"version": "1.28.0",
44
"description": "Marketplace package for the Immutable SDK for Unity",
55
"displayName": "Immutable Marketplace",
66
"author": {

‎src/Packages/Passport/Runtime/Scripts/Private/Helpers/SdkVersionInfoHelpers.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public class SdkVersionInfoHelpers
44
{
55
public static string GetSdkVersionInfo()
66
{
7-
return "1.27.2";
7+
return "1.28.0";
88
}
99
}
1010
}

‎src/Packages/Passport/Samples~/Scenes/AuthenticatedScene.unity‎

Lines changed: 6646 additions & 0 deletions
Large diffs are not rendered by default.

‎src/Packages/Passport/Samples~/Scenes/ImxNftTransfer.unity‎

Lines changed: 5552 additions & 0 deletions
Large diffs are not rendered by default.

‎src/Packages/Passport/Samples~/Scenes/SelectAuthMethod.unity‎

Lines changed: 2320 additions & 0 deletions
Large diffs are not rendered by default.

‎src/Packages/Passport/Samples~/Scenes/UnauthenticatedScene.unity‎

Lines changed: 3384 additions & 0 deletions
Large diffs are not rendered by default.

‎src/Packages/Passport/Samples~/Scenes/ZkEvmGetBalance.unity‎

Lines changed: 2615 additions & 0 deletions
Large diffs are not rendered by default.

‎src/Packages/Passport/Samples~/Scenes/ZkEvmGetTransactionReceipt.unity‎

Lines changed: 2615 additions & 0 deletions
Large diffs are not rendered by default.

‎src/Packages/Passport/Samples~/Scenes/ZkEvmSendTransaction.unity‎

Lines changed: 4165 additions & 0 deletions
Large diffs are not rendered by default.

‎src/Packages/Passport/Samples~/Scenes/ZkEvmSignTypedData.unity‎

Lines changed: 2615 additions & 0 deletions
Large diffs are not rendered by default.

‎src/Packages/Passport/Samples~/Scripts/AuthenticatedScript.cs‎

Lines changed: 432 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using UnityEngine;
2+
3+
/// <summary>
4+
/// Adjusts the UI to fit within the safe area on mobile devices.
5+
/// </summary>
6+
public class SafeArea : MonoBehaviour
7+
{
8+
#if (UNITY_ANDROID && !UNITY_EDITOR) || (UNITY_IPHONE && !UNITY_EDITOR)
9+
private RectTransform rectTransform;
10+
private Rect safeArea;
11+
private Vector2 minAnchor;
12+
private Vector2 maxAnchor;
13+
#endif
14+
15+
void Start()
16+
{
17+
#if (UNITY_ANDROID && !UNITY_EDITOR) || (UNITY_IPHONE && !UNITY_EDITOR)
18+
rectTransform = GetComponent<RectTransform>();
19+
safeArea = Screen.safeArea;
20+
21+
minAnchor = safeArea.position;
22+
maxAnchor = minAnchor + safeArea.size;
23+
24+
minAnchor.x /= Screen.width;
25+
minAnchor.y /= Screen.height;
26+
maxAnchor.x /= Screen.width;
27+
maxAnchor.y /= Screen.height;
28+
29+
rectTransform.anchorMin = minAnchor;
30+
rectTransform.anchorMax = maxAnchor;
31+
#endif
32+
}
33+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
using System.Collections.Generic;
2+
using System;
3+
using UnityEngine;
4+
using UnityEngine.UI;
5+
using UnityEngine.SceneManagement;
6+
using Immutable.Passport;
7+
using Immutable.Passport.Model;
8+
9+
public class ImxNftTransferScript : MonoBehaviour
10+
{
11+
#pragma warning disable CS8618
12+
[SerializeField] private Text Output;
13+
14+
[SerializeField] private InputField TokenIdInput1;
15+
[SerializeField] private InputField TokenAddressInput1;
16+
[SerializeField] private InputField ReceiverInput1;
17+
18+
[SerializeField] private InputField TokenIdInput2;
19+
[SerializeField] private InputField TokenAddressInput2;
20+
[SerializeField] private InputField ReceiverInput2;
21+
22+
private Passport Passport;
23+
#pragma warning restore CS8618
24+
25+
void Start()
26+
{
27+
if (Passport.Instance != null)
28+
{
29+
// Get Passport instance
30+
Passport = Passport.Instance;
31+
}
32+
else
33+
{
34+
ShowOutput("Passport instance is null");
35+
}
36+
}
37+
38+
/// <summary>
39+
/// Transfers NFTs to the specified receivers based on the provided details.
40+
/// </summary>
41+
public async void Transfer()
42+
{
43+
// Check if all necessary input fields are filled
44+
if (!string.IsNullOrWhiteSpace(TokenIdInput1.text) &&
45+
!string.IsNullOrWhiteSpace(TokenAddressInput1.text) &&
46+
!string.IsNullOrWhiteSpace(ReceiverInput1.text))
47+
{
48+
ShowOutput("Transferring NFTs...");
49+
50+
try
51+
{
52+
// Gather all NFT transfer details
53+
List<NftTransferDetails> transferDetails = GetTransferDetails();
54+
55+
// Perform batch transfer if multiple NFTs are specified
56+
if (transferDetails.Count > 1)
57+
{
58+
CreateBatchTransferResponse response = await Passport.ImxBatchNftTransfer(transferDetails.ToArray());
59+
ShowOutput($"Successfully transferred {response.transfer_ids.Length} NFTs.");
60+
}
61+
// Perform a single transfer if only one NFT is specified
62+
else
63+
{
64+
NftTransferDetails nftTransferDetail = transferDetails[0];
65+
UnsignedTransferRequest transferRequest = UnsignedTransferRequest.ERC721(
66+
nftTransferDetail.receiver,
67+
nftTransferDetail.tokenId,
68+
nftTransferDetail.tokenAddress
69+
);
70+
CreateTransferResponseV1 response = await Passport.ImxTransfer(transferRequest);
71+
ShowOutput($"NFT transferred successfully. Transfer ID: {response.transfer_id}");
72+
}
73+
}
74+
catch (Exception ex)
75+
{
76+
ShowOutput($"Failed to transfer NFTs: {ex.Message}");
77+
}
78+
}
79+
else
80+
{
81+
ShowOutput("Please fill in all required fields for the first NFT transfer.");
82+
}
83+
}
84+
85+
/// <summary>
86+
/// Constructs a list of NFT transfer details from the input fields.
87+
/// </summary>
88+
/// <returns>A list of <see cref="NftTransferDetails"/> objects representing the NFTs to transfer.</returns>
89+
private List<NftTransferDetails> GetTransferDetails()
90+
{
91+
// Initialise the list to store transfer details
92+
List<NftTransferDetails> details = new List<NftTransferDetails>();
93+
94+
// Add the first NFT transfer details
95+
if (!string.IsNullOrWhiteSpace(TokenIdInput1.text) &&
96+
!string.IsNullOrWhiteSpace(TokenAddressInput1.text) &&
97+
!string.IsNullOrWhiteSpace(ReceiverInput1.text))
98+
{
99+
details.Add(new NftTransferDetails(
100+
ReceiverInput1.text,
101+
TokenIdInput1.text,
102+
TokenAddressInput1.text
103+
));
104+
}
105+
106+
// Add the second NFT transfer details if provided
107+
if (!string.IsNullOrWhiteSpace(TokenIdInput2.text) &&
108+
!string.IsNullOrWhiteSpace(TokenAddressInput2.text) &&
109+
!string.IsNullOrWhiteSpace(ReceiverInput2.text))
110+
{
111+
details.Add(new NftTransferDetails(
112+
ReceiverInput2.text,
113+
TokenIdInput2.text,
114+
TokenAddressInput2.text
115+
));
116+
}
117+
118+
return details;
119+
}
120+
121+
122+
/// <summary>
123+
/// Navigates back to the authenticated scene.
124+
/// </summary>
125+
public void Cancel()
126+
{
127+
SceneManager.LoadScene("AuthenticatedScene");
128+
}
129+
130+
/// <summary>
131+
/// Prints the specified <code>message</code> to the output box.
132+
/// </summary>
133+
/// <param name="message">The message to print</param>
134+
private void ShowOutput(string message)
135+
{
136+
if (Output != null)
137+
{
138+
Output.text = message;
139+
}
140+
}
141+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
public static class SampleAppManager
2+
{
3+
/// <summary>
4+
/// Indicates whether the running platform supports PKCE.
5+
/// </summary>
6+
public static bool SupportsPKCE { get; set; }
7+
8+
/// <summary>
9+
/// Indicates whether the selected authentication method is PKCE.
10+
/// </summary>
11+
public static bool UsePKCE { get; set; }
12+
13+
/// <summary>
14+
/// Indicates whether the user is connected to IMX.
15+
/// </summary>
16+
public static bool IsConnectedToImx { get; set; }
17+
18+
/// <summary>
19+
/// Indicates whether the user is connected to zkEVM.
20+
/// </summary>
21+
public static bool IsConnectedToZkEvm { get; set; }
22+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
using System;
2+
using UnityEngine;
3+
using UnityEngine.UI;
4+
using UnityEngine.SceneManagement;
5+
using Immutable.Passport;
6+
using Immutable.Passport.Core.Logging;
7+
8+
public class SelectAuthMethodScript : MonoBehaviour
9+
{
10+
#pragma warning disable CS8618
11+
[SerializeField] private GameObject TopPadding;
12+
[SerializeField] private Text Output;
13+
[SerializeField] private Button UseDeviceCodeAuthButton;
14+
[SerializeField] private Button UsePKCEButton;
15+
#pragma warning restore CS8618
16+
17+
void Start()
18+
{
19+
// Determine if PKCE is supported based on the platform
20+
SampleAppManager.SupportsPKCE = IsPKCESupported();
21+
22+
// WebGL does not support Device Code Auth, so we'll use PKCE by default instead.
23+
#if UNITY_WEBGL
24+
UsePKCE();
25+
#else
26+
// If PKCE is not supported, initialise Passport to use Device Code Auth
27+
if (!SampleAppManager.SupportsPKCE)
28+
{
29+
UseDeviceCodeAuth();
30+
}
31+
#endif
32+
}
33+
34+
/// <summary>
35+
/// Checks if the current platform supports PKCE authentication.
36+
/// </summary>
37+
private bool IsPKCESupported()
38+
{
39+
#if (UNITY_ANDROID && !UNITY_EDITOR_WIN) || (UNITY_IPHONE && !UNITY_EDITOR_WIN) || UNITY_STANDALONE_OSX || UNITY_WEBGL
40+
return true;
41+
#else
42+
return false;
43+
#endif
44+
}
45+
46+
/// <summary>
47+
/// Initialises Passport to use Device Code Auth
48+
/// </summary>
49+
public void UseDeviceCodeAuth()
50+
{
51+
SampleAppManager.UsePKCE = false;
52+
InitialisePassport(logoutRedirectUri: "https://www.immutable.com");
53+
}
54+
55+
/// <summary>
56+
/// Initialises Passport to use PKCE with the specified redirect URIs.
57+
/// </summary>
58+
public void UsePKCE()
59+
{
60+
SampleAppManager.UsePKCE = true;
61+
#if UNITY_WEBGL
62+
string url = Application.absoluteURL;
63+
Uri uri = new Uri(url);
64+
string scheme = uri.Scheme;
65+
string hostWithPort = uri.IsDefaultPort ? uri.Host : $"{uri.Host}:{uri.Port}";
66+
string fullPath = uri.AbsolutePath.EndsWith("/") ? uri.AbsolutePath : uri.AbsolutePath.Substring(0, uri.AbsolutePath.LastIndexOf('/') + 1);
67+
68+
string redirectUri = $"{scheme}://{hostWithPort}{fullPath}callback.html";
69+
string logoutRedirectUri = $"{scheme}://{hostWithPort}{fullPath}logout.html";
70+
71+
InitialisePassport(redirectUri: redirectUri, logoutRedirectUri: logoutRedirectUri);
72+
#else
73+
InitialisePassport(redirectUri: "immutablerunner://callback", logoutRedirectUri: "immutablerunner://logout");
74+
#endif
75+
}
76+
77+
/// <summary>
78+
/// Initialises Passport.
79+
/// </summary>
80+
/// <param name="redirectUri">(Android, iOS and macOS only) The URL to which auth will redirect the browser after
81+
/// authorisation has been granted by the user</param>
82+
/// <param name="logoutRedirectUri">The URL to which auth will redirect the browser
83+
/// after log out is complete</param>
84+
private async void InitialisePassport(string redirectUri = null, string logoutRedirectUri = null)
85+
{
86+
ShowOutput("Initialising Passport...");
87+
88+
try
89+
{
90+
// Set the log level for the SDK
91+
Passport.LogLevel = LogLevel.Info;
92+
93+
// Initialise Passport
94+
string environment = Immutable.Passport.Model.Environment.SANDBOX;
95+
#if UNITY_WEBGL
96+
string clientId = "UnB98ngnXIZIEJWGJOjVe1BpCx5ix7qc";
97+
#else
98+
string clientId = "mp6rxfMDwwZDogcdgNrAaHnG0qMlXuMK";
99+
#endif
100+
Passport passport = await Passport.Init(clientId, environment, redirectUri, logoutRedirectUri);
101+
102+
// Navigate to the unauthenticated scene after initialising Passport
103+
SceneManager.LoadScene("UnauthenticatedScene");
104+
}
105+
catch (Exception ex)
106+
{
107+
Debug.LogException(ex, this);
108+
ShowOutput($"Initialise Passport error: {ex.Message}");
109+
}
110+
}
111+
112+
/// <summary>
113+
/// Prints the specified <code>message</code> to the output box.
114+
/// </summary>
115+
/// <param name="message">The message to print</param>
116+
private void ShowOutput(string message)
117+
{
118+
if (Output != null)
119+
{
120+
Output.text = message;
121+
}
122+
}
123+
}
Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
using System;
2+
using Cysharp.Threading.Tasks;
3+
using UnityEngine;
4+
using UnityEngine.UI;
5+
using UnityEngine.SceneManagement;
6+
using Immutable.Passport;
7+
8+
public class UnauthenticatedScript : MonoBehaviour
9+
{
10+
#pragma warning disable CS8618
11+
[SerializeField] private GameObject TopPadding;
12+
[SerializeField] private Text Output;
13+
// Login buttons
14+
[SerializeField] private GameObject LoginButtons;
15+
// Re-login buttons
16+
[SerializeField] private GameObject ReloginButtons;
17+
[SerializeField] private InputField DeviceCodeTimeoutMs;
18+
19+
private Passport Passport;
20+
#pragma warning restore CS8618
21+
22+
async void Start()
23+
{
24+
if (Passport.Instance != null)
25+
{
26+
// Get Passport instance
27+
Passport = Passport.Instance;
28+
29+
// Check if the user has logged in before
30+
await CheckHasCredentialsSaved();
31+
}
32+
else
33+
{
34+
ShowOutput("Passport Instance is null");
35+
}
36+
}
37+
38+
/// <summary>
39+
/// Checks if the user has logged in previously and updates the UI to display the appropriate buttons and fields.
40+
/// </summary>
41+
private async UniTask CheckHasCredentialsSaved()
42+
{
43+
bool hasCredsSaved = await Passport.HasCredentialsSaved();
44+
45+
// Show re-login buttons if user has credentials saved
46+
ReloginButtons.SetActive(hasCredsSaved);
47+
48+
// Show login buttons if user does not have any credentials saved
49+
LoginButtons.SetActive(!hasCredsSaved);
50+
51+
// Only show timeout field if Device Code Auth is selected as the auth method and no credentials are saved
52+
DeviceCodeTimeoutMs.gameObject.SetActive(!hasCredsSaved && !SampleAppManager.UsePKCE);
53+
}
54+
55+
/// <summary>
56+
/// Logs into Passport using the selected auth method.
57+
/// Defaults to Device Code Auth when running as a Windows Standalone application or in the Unity Editor on Windows.
58+
/// </summary>
59+
public async void Login()
60+
{
61+
// Get timeout
62+
var timeoutMs = GetDeviceCodeTimeoutMs();
63+
string formattedTimeout = timeoutMs != null ? $"{timeoutMs} ms" : "none";
64+
65+
ShowOutput($"Logging in (timeout: {formattedTimeout})...");
66+
67+
try
68+
{
69+
// Login using the appropriate login method
70+
if (SampleAppManager.SupportsPKCE && SampleAppManager.UsePKCE)
71+
{
72+
#if (UNITY_ANDROID && !UNITY_EDITOR_WIN) || (UNITY_IPHONE && !UNITY_EDITOR_WIN) || UNITY_STANDALONE_OSX || UNITY_WEBGL
73+
await Passport.LoginPKCE();
74+
#endif
75+
}
76+
else
77+
{
78+
await Passport.Login(timeoutMs: timeoutMs);
79+
}
80+
81+
// Navigate to the authenticated scene upon successful login
82+
NavigateToAuthenticatedScene(connectedToImx: false);
83+
}
84+
catch (OperationCanceledException)
85+
{
86+
ShowOutput("Failed to login: cancelled");
87+
}
88+
catch (Exception ex)
89+
{
90+
await Logout();
91+
ShowOutput($"Failed to login: {ex.Message}");
92+
}
93+
}
94+
95+
/// <summary>
96+
/// Logs into Passport using the selected auth method.
97+
/// Defaults to Device Code Auth when running as a Windows Standalone application or in the Unity Editor on Windows.
98+
///
99+
/// This function also connects to IMX, which initialises the user's wallet and sets up the IMX provider.
100+
/// </summary>
101+
public async void Connect()
102+
{
103+
// Get timeout
104+
var timeoutMs = GetDeviceCodeTimeoutMs();
105+
string formattedTimeout = timeoutMs != null ? $"{timeoutMs} ms" : "none";
106+
107+
ShowOutput($"Connecting (timeout: {formattedTimeout})...");
108+
109+
try
110+
{
111+
// Login and connect to IMX using the appropriate connect method
112+
if (SampleAppManager.SupportsPKCE && SampleAppManager.UsePKCE)
113+
{
114+
#if (UNITY_ANDROID && !UNITY_EDITOR_WIN) || (UNITY_IPHONE && !UNITY_EDITOR_WIN) || UNITY_STANDALONE_OSX || UNITY_WEBGL
115+
await Passport.ConnectImxPKCE();
116+
#endif
117+
}
118+
else
119+
{
120+
await Passport.ConnectImx(timeoutMs: timeoutMs);
121+
}
122+
123+
// Navigate to the authenticated scene upon successful login and connection to IMX
124+
NavigateToAuthenticatedScene(connectedToImx: true);
125+
}
126+
catch (OperationCanceledException)
127+
{
128+
ShowOutput("Failed to connect: cancelled");
129+
}
130+
catch (Exception ex)
131+
{
132+
await Logout();
133+
ShowOutput($"Failed to connect: {ex.Message}");
134+
}
135+
}
136+
137+
/// <summary>
138+
/// Uses the existing credentials to re-login to Passport.
139+
/// </summary>
140+
public async void Relogin()
141+
{
142+
ShowOutput("Re-logging into Passport using saved credentials...");
143+
144+
try
145+
{
146+
bool loggedIn = await Passport.Login(useCachedSession: true);
147+
148+
if (loggedIn)
149+
{
150+
// Navigate to the authenticated scene upon successful login
151+
NavigateToAuthenticatedScene(connectedToImx: false);
152+
}
153+
else
154+
{
155+
// Failed to re-login, so remove existing credentials and restart
156+
ClearStorageCacheAndRestart();
157+
ShowOutput("Could not re-login using saved credentials");
158+
}
159+
}
160+
catch (Exception ex)
161+
{
162+
// Failed to re-login, so remove existing credentials and restart
163+
ClearStorageCacheAndRestart();
164+
ShowOutput($"Failed to re-login: {ex.Message}");
165+
}
166+
}
167+
168+
/// <summary>
169+
/// Uses existing credentials to re-login to Passport and reconnect to IMX.
170+
/// The SDK initialises the user's wallet and sets up the IMX provider during reconnection.
171+
/// </summary>
172+
public async void Reconnect()
173+
{
174+
ShowOutput("Reconnecting to Passport using saved credentials...");
175+
176+
try
177+
{
178+
bool connected = await Passport.ConnectImx(useCachedSession: true);
179+
180+
if (connected)
181+
{
182+
// Navigate to the authenticated scene upon successful login and connection to IMX
183+
NavigateToAuthenticatedScene(connectedToImx: true);
184+
}
185+
else
186+
{
187+
// Failed to reconnect, so remove existing credentials and restart
188+
ClearStorageCacheAndRestart();
189+
ShowOutput("Could not reconnect using saved credentials");
190+
}
191+
}
192+
catch (Exception ex)
193+
{
194+
// Failed to reconnect, so remove existing credentials and restart
195+
ClearStorageCacheAndRestart();
196+
ShowOutput($"Failed to reconnect: {ex.Message}");
197+
}
198+
}
199+
200+
/// <summary>
201+
/// Logs out of Passport using the selected auth method.
202+
/// Defaults to Device Code Auth when running as a Windows Standalone application or in the Unity Editor on Windows.
203+
/// </summary>
204+
private async UniTask Logout()
205+
{
206+
try
207+
{
208+
// Logout using the appropriate logout method
209+
if (SampleAppManager.SupportsPKCE && SampleAppManager.UsePKCE)
210+
{
211+
#if (UNITY_ANDROID && !UNITY_EDITOR_WIN) || (UNITY_IPHONE && !UNITY_EDITOR_WIN) || UNITY_STANDALONE_OSX || UNITY_WEBGL
212+
await Passport.LogoutPKCE();
213+
#endif
214+
}
215+
else
216+
{
217+
await Passport.Logout();
218+
}
219+
}
220+
catch (Exception ex)
221+
{
222+
ShowOutput($"Failed to logout: {ex.Message}");
223+
}
224+
}
225+
226+
/// <summary>
227+
/// Clears the underlying WebView storage and cache, including any saved credentials.
228+
/// </summary>
229+
public void ClearStorageAndCache()
230+
{
231+
#if (UNITY_IPHONE && !UNITY_EDITOR) || (UNITY_ANDROID && !UNITY_EDITOR)
232+
Passport.ClearStorage();
233+
Passport.ClearCache(true);
234+
235+
// Show login buttons as saved credentials are removed
236+
ShowLoginButtons();
237+
ShowOutput("Cleared storage and cache");
238+
#else
239+
ShowOutput("Available for Android and iOS devices only");
240+
#endif
241+
}
242+
243+
/// <summary>
244+
/// Clears the WebView storage and cache, then updates the UI to show login-related buttons and fields.
245+
/// </summary>
246+
private void ClearStorageCacheAndRestart()
247+
{
248+
ClearStorageAndCache();
249+
ShowLoginButtons();
250+
}
251+
252+
/// <summary>
253+
/// Updates the UI to show login buttons and fields, hiding relogin buttons.
254+
/// </summary>
255+
private void ShowLoginButtons()
256+
{
257+
ReloginButtons.SetActive(false);
258+
LoginButtons.SetActive(true);
259+
DeviceCodeTimeoutMs.gameObject.SetActive(!SampleAppManager.UsePKCE);
260+
}
261+
262+
/// <summary>
263+
/// Gets the Device Code Auth timeout the user entered in
264+
/// </summary>
265+
/// <returns></returns>
266+
private long? GetDeviceCodeTimeoutMs()
267+
{
268+
return string.IsNullOrEmpty(DeviceCodeTimeoutMs.text) ? null : long.Parse(DeviceCodeTimeoutMs.text);
269+
}
270+
271+
/// <summary>
272+
/// Records whether the user has only logged in or also connected to IMX.
273+
/// This ensures the sample app displays the correct buttons in the authenticated scene.
274+
/// Navigates the user to the authenticated scene.
275+
/// </summary>
276+
/// <param name="connectedToImx">Indicates if the user is connected to IMX</param>
277+
private void NavigateToAuthenticatedScene(bool connectedToImx)
278+
{
279+
SampleAppManager.IsConnectedToImx = connectedToImx;
280+
SceneManager.LoadScene("AuthenticatedScene");
281+
}
282+
283+
/// <summary>
284+
/// Prints the specified <code>message</code> to the output box.
285+
/// </summary>
286+
/// <param name="message">The message to print</param>
287+
private void ShowOutput(string message)
288+
{
289+
if (Output != null)
290+
{
291+
Output.text = message;
292+
}
293+
}
294+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using System.Globalization;
2+
using System.Numerics;
3+
using System;
4+
using UnityEngine;
5+
using UnityEngine.UI;
6+
using UnityEngine.SceneManagement;
7+
using Immutable.Passport;
8+
9+
public class ZkEvmGetBalanceScript : MonoBehaviour
10+
{
11+
#pragma warning disable CS8618
12+
[SerializeField] private Text Output;
13+
[SerializeField] private InputField AddressInput;
14+
15+
private Passport Passport;
16+
#pragma warning restore CS8618
17+
18+
void Start()
19+
{
20+
if (Passport.Instance != null)
21+
{
22+
// Get Passport instance
23+
Passport = Passport.Instance;
24+
}
25+
else
26+
{
27+
ShowOutput("Passport instance is null");
28+
}
29+
}
30+
31+
/// <summary>
32+
/// Gets the balance of the account for the specified address.
33+
/// The balance is obtained in hexadecimal format and then converted to decimal for display.
34+
/// </summary>
35+
public async void GetBalance()
36+
{
37+
ShowOutput("Getting account balance...");
38+
39+
try
40+
{
41+
// Retrieve the balance in hexadecimal format
42+
string balanceHex = await Passport.ZkEvmGetBalance(AddressInput.text);
43+
44+
// Convert the hexadecimal balance to a BigInteger for decimal representation
45+
var balanceDec = BigInteger.Parse(balanceHex.Replace("0x", ""), NumberStyles.HexNumber);
46+
47+
// Ensure the number is positive
48+
if (balanceDec < 0)
49+
{
50+
balanceDec = BigInteger.Parse("0" + balanceHex.Replace("0x", ""), NumberStyles.HexNumber);
51+
}
52+
53+
// Display both hexadecimal and decimal representations of the balance
54+
ShowOutput($"Balance:\nHex: {balanceHex}\nDec: {balanceDec}");
55+
}
56+
catch (Exception ex)
57+
{
58+
ShowOutput($"Failed to get balance: {ex.Message}");
59+
}
60+
}
61+
62+
63+
64+
/// <summary>
65+
/// Navigates back to the authenticated scene.
66+
/// </summary>
67+
public void Cancel()
68+
{
69+
SceneManager.LoadScene("AuthenticatedScene");
70+
}
71+
72+
/// <summary>
73+
/// Prints the specified <code>message</code> to the output box.
74+
/// </summary>
75+
/// <param name="message">The message to print</param>
76+
private void ShowOutput(string message)
77+
{
78+
if (Output != null)
79+
{
80+
Output.text = message;
81+
}
82+
}
83+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
using System;
2+
using UnityEngine;
3+
using UnityEngine.UI;
4+
using UnityEngine.SceneManagement;
5+
using Immutable.Passport;
6+
using Immutable.Passport.Model;
7+
8+
public class ZkEvmGetTransactionReceiptScript : MonoBehaviour
9+
{
10+
#pragma warning disable CS8618
11+
[SerializeField] private Text Output;
12+
[SerializeField] private InputField TransactionHash;
13+
14+
private Passport Passport;
15+
#pragma warning restore CS8618
16+
17+
void Start()
18+
{
19+
if (Passport.Instance != null)
20+
{
21+
// Get Passport instance
22+
Passport = Passport.Instance;
23+
}
24+
else
25+
{
26+
ShowOutput("Passport instance is null");
27+
}
28+
}
29+
30+
/// <summary>
31+
/// Retrieves the transaction receipt for a given transaction hash using the Ethereum JSON-RPC <c>eth_getTransactionReceipt</c> method.
32+
/// </summary>
33+
public async void GetZkEvmTransactionReceipt()
34+
{
35+
ShowOutput("Getting transaction receipt...");
36+
37+
try
38+
{
39+
// Retrieve the transaction receipt using the provided hash
40+
TransactionReceiptResponse response = await Passport.ZkEvmGetTransactionReceipt(TransactionHash.text);
41+
42+
// Display the transaction status
43+
string status = $"Status: {GetTransactionStatusString(response.status)}";
44+
ShowOutput(status);
45+
}
46+
catch (Exception ex)
47+
{
48+
ShowOutput($"Failed to retrieve transaction receipt: {ex.Message}");
49+
}
50+
}
51+
52+
/// <summary>
53+
/// Converts transaction status code to a human-readable string.
54+
/// </summary>
55+
/// <param name="status">The transaction status code.</param>
56+
/// <returns>A string representing the status.</returns>
57+
private string GetTransactionStatusString(string status)
58+
{
59+
switch (status)
60+
{
61+
case "1":
62+
case "0x1":
63+
return "Success";
64+
case "0":
65+
case "0x0":
66+
return "Failed";
67+
case null:
68+
return "Still processing";
69+
default:
70+
return "Unknown status";
71+
}
72+
}
73+
74+
/// <summary>
75+
/// Navigates back to the authenticated scene.
76+
/// </summary>
77+
public void Cancel()
78+
{
79+
SceneManager.LoadScene("AuthenticatedScene");
80+
}
81+
82+
/// <summary>
83+
/// Prints the specified <code>message</code> to the output box.
84+
/// </summary>
85+
/// <param name="message">The message to print</param>
86+
private void ShowOutput(string message)
87+
{
88+
if (Output != null)
89+
{
90+
Output.text = message;
91+
}
92+
}
93+
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
using System;
2+
using System.Threading;
3+
using UnityEngine;
4+
using UnityEngine.UI;
5+
using UnityEngine.SceneManagement;
6+
using Immutable.Passport;
7+
using Immutable.Passport.Model;
8+
using Cysharp.Threading.Tasks;
9+
10+
public class ZkEvmSendTransactionScript : MonoBehaviour
11+
{
12+
#pragma warning disable CS8618
13+
[SerializeField] private Text Output;
14+
15+
[SerializeField] private Toggle ConfirmToggle;
16+
[SerializeField] private Toggle GetTrasactionReceiptToggle;
17+
[SerializeField] private InputField ToInputField;
18+
[SerializeField] private InputField ValueInputField;
19+
[SerializeField] private InputField DataInputField;
20+
21+
private Passport Passport;
22+
#pragma warning restore CS8618
23+
24+
void Start()
25+
{
26+
if (Passport.Instance != null)
27+
{
28+
// Get Passport instance
29+
Passport = Passport.Instance;
30+
31+
// Show get transaction receipt option if send transaction with confirmation toggle is off
32+
ConfirmToggle.onValueChanged.AddListener(delegate
33+
{
34+
GetTrasactionReceiptToggle.gameObject.SetActive(!ConfirmToggle.isOn);
35+
});
36+
}
37+
else
38+
{
39+
ShowOutput("Passport instance is null");
40+
}
41+
}
42+
43+
/// <summary>
44+
/// Constructs a transaction using the provided To, Value, and Data fields.
45+
/// Sends the transaction to the network and signs it with the currently authenticated Passport account.
46+
/// If confirmation is requested, the function waits for the transaction to be included in a block,
47+
/// and displays the transaction status upon completion.
48+
/// </summary>
49+
public async void SendTransaction()
50+
{
51+
ShowOutput("Sending transaction...");
52+
53+
try
54+
{
55+
// Create transaction request
56+
TransactionRequest request = new TransactionRequest
57+
{
58+
to = ToInputField.text,
59+
value = ValueInputField.text,
60+
data = DataInputField.text
61+
};
62+
63+
// Check if confirmation is requested
64+
if (ConfirmToggle.isOn)
65+
{
66+
// Send transaction with confirmation and display transaction status upon completion
67+
TransactionReceiptResponse response = await Passport.ZkEvmSendTransactionWithConfirmation(request);
68+
ShowOutput($"Transaction hash: {response.transactionHash}\nStatus: {GetTransactionStatusString(response.status)}");
69+
}
70+
else
71+
{
72+
// Send transaction without confirmation
73+
string transactionHash = await Passport.ZkEvmSendTransaction(request);
74+
75+
// Check if receipt is requested
76+
if (GetTrasactionReceiptToggle.isOn)
77+
{
78+
// Poll for the receipt and display transaction status
79+
string? status = await PollStatus(transactionHash);
80+
ShowOutput($"Transaction hash: {transactionHash}\nStatus: {GetTransactionStatusString(status)}");
81+
}
82+
else
83+
{
84+
ShowOutput($"Transaction hash: {transactionHash}");
85+
}
86+
}
87+
}
88+
catch (Exception ex)
89+
{
90+
ShowOutput($"Failed to send transaction: {ex.Message}");
91+
}
92+
}
93+
94+
/// <summary>
95+
/// Polls the status of the given transaction hash until either a status is retrieved or a timeout occurs.
96+
/// </summary>
97+
/// <param name="transactionHash">The hash of the transaction to poll.</param>
98+
/// <returns>The status of the transaction, or null if a timeout occurs.</returns>
99+
static async UniTask<string?> PollStatus(string transactionHash)
100+
{
101+
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(10));
102+
try
103+
{
104+
while (!cancellationTokenSource.Token.IsCancellationRequested)
105+
{
106+
TransactionReceiptResponse response = await Passport.Instance.ZkEvmGetTransactionReceipt(transactionHash);
107+
if (response.status == null)
108+
{
109+
// The transaction is still being processed, poll for status again
110+
await UniTask.Delay(delayTimeSpan: TimeSpan.FromSeconds(1), cancellationToken: cancellationTokenSource.Token);
111+
}
112+
else
113+
{
114+
return response.status;
115+
}
116+
}
117+
}
118+
catch (OperationCanceledException)
119+
{
120+
// Task was canceled due to timeout
121+
}
122+
123+
return null; // Timeout or could not get transaction receipt
124+
}
125+
126+
/// <summary>
127+
/// Converts transaction status code to a human-readable string.
128+
/// </summary>
129+
/// <param name="status">The transaction status code.</param>
130+
/// <returns>A string representing the status.</returns>
131+
private string GetTransactionStatusString(string? status)
132+
{
133+
switch (status)
134+
{
135+
case "1":
136+
case "0x1":
137+
return "Success";
138+
case "0":
139+
case "0x0":
140+
return "Failed";
141+
case null:
142+
return "Still processing";
143+
default:
144+
return "Unknown status";
145+
}
146+
}
147+
148+
/// <summary>
149+
/// Navigates back to the authenticated scene.
150+
/// </summary>
151+
public void Cancel()
152+
{
153+
SceneManager.LoadScene("AuthenticatedScene");
154+
}
155+
156+
/// <summary>
157+
/// Prints the specified <code>message</code> to the output box.
158+
/// </summary>
159+
/// <param name="message">The message to print</param>
160+
private void ShowOutput(string message)
161+
{
162+
if (Output != null)
163+
{
164+
Output.text = message;
165+
}
166+
}
167+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using System;
2+
using UnityEngine;
3+
using UnityEngine.UI;
4+
using UnityEngine.SceneManagement;
5+
using Immutable.Passport;
6+
using Immutable.Passport.Model;
7+
8+
public class ZkEvmSignTypedDataScript : MonoBehaviour
9+
{
10+
#pragma warning disable CS8618
11+
[SerializeField] private Text Output;
12+
[SerializeField] private InputField Payload;
13+
14+
private Passport Passport;
15+
#pragma warning restore CS8618
16+
17+
void Start()
18+
{
19+
if (Passport.Instance != null)
20+
{
21+
// Get Passport instance
22+
Passport = Passport.Instance;
23+
}
24+
else
25+
{
26+
ShowOutput("Passport instance is null");
27+
}
28+
}
29+
30+
/// <summary>
31+
/// Retrieves the transaction receipt for a given transaction hash using the Ethereum JSON-RPC <c>eth_getTransactionReceipt</c> method.
32+
/// </summary>
33+
public async void SignTypedData()
34+
{
35+
ShowOutput("Signing payload...");
36+
37+
try
38+
{
39+
// Sign the given payload
40+
string signature = await Passport.ZkEvmSignTypedDataV4(Payload.text);
41+
ShowOutput(signature);
42+
}
43+
catch (Exception ex)
44+
{
45+
ShowOutput($"Failed to retrieve transaction receipt: {ex.Message}");
46+
}
47+
}
48+
49+
/// <summary>
50+
/// Navigates back to the authenticated scene.
51+
/// </summary>
52+
public void Cancel()
53+
{
54+
SceneManager.LoadScene("AuthenticatedScene");
55+
}
56+
57+
/// <summary>
58+
/// Prints the specified <code>message</code> to the output box.
59+
/// </summary>
60+
/// <param name="message">The message to print</param>
61+
private void ShowOutput(string message)
62+
{
63+
if (Output != null)
64+
{
65+
Output.text = message;
66+
}
67+
}
68+
}

‎src/Packages/Passport/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "com.immutable.passport",
3-
"version": "1.27.2",
3+
"version": "1.28.0",
44
"description": "The Immutable SDK for Unity helps you integrate your game with Immutable Passport.\n\nFor a complete working example, please visit https://github.com/immutable/unity-immutable-sdk/tree/main/sample.",
55
"displayName": "Immutable Passport",
66
"author": {

0 commit comments

Comments
 (0)
Please sign in to comment.