Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Solana.Unity.SDK;
using UnityEngine.Scripting;

// ReSharper disable once CheckNamespace
Expand All @@ -11,6 +12,10 @@ public interface IAdapterOperations
[Preserve]
public Task<AuthorizationResult> Authorize(Uri identityUri, Uri iconUri, string identityName, string rpcCluster);
[Preserve]
public Task<AuthorizationResult> Authorize(Uri identityUri, Uri iconUri, string identityName,
string chain, string[] features, string[] addresses, string authToken,
JsonRequest.SignInPayload signInPayload);
[Preserve]
public Task<AuthorizationResult> Reauthorize(Uri identityUri, Uri iconUri, string identityName, string authToken);
[Preserve]
public Task Deauthorize(string authToken);
Expand All @@ -20,4 +25,6 @@ public interface IAdapterOperations
public Task<SignedResult> SignTransactions(IEnumerable<byte[]> transactions);
[Preserve]
public Task<SignedResult> SignMessages(IEnumerable<byte[]> messages, IEnumerable<byte[]> addresses);
[Preserve]
public Task<SignAndSendResult> SignAndSendTransactions(IEnumerable<byte[]> transactions, JsonRequest.SignAndSendOptions options);
}
41 changes: 34 additions & 7 deletions Runtime/codebase/SolanaMobileStack/JsonRpc20Client.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Scripting;

// ReSharper disable once CheckNamespace
Expand All @@ -11,26 +12,34 @@ namespace Solana.Unity.SDK
[Preserve]
public class JsonRpc20Client
{
private const string TAG = "[JsonRpc20]";

private delegate void MessageHandler(string message);

private event MessageHandler MessageEvent;

private readonly IMessageSender _messageSender;

private int _pendingRequests;
public int PendingRequests => _pendingRequests;

protected JsonRpc20Client(IMessageSender messageSender)
{
_messageSender = messageSender;
}

protected Task<T> SendRequest<T>(JsonRequest jsonRequest)
protected Task<T> SendRequest<T>(JsonRequest jsonRequest, string methodName = "Unknown")
{
var message = JsonConvert.SerializeObject(jsonRequest);
var messageBytes = System.Text.Encoding.UTF8.GetBytes(message);
Debug.Log($"{TAG} SendRequest | method={methodName} id={jsonRequest.Id} json_len={message.Length} byte_len={messageBytes.Length} json={message}");
_messageSender.Send(messageBytes);
System.Threading.Interlocked.Increment(ref _pendingRequests);
var authTaskCompletionSource = new TaskCompletionSource<T>();

// Register the message listener
RegisterListener(authTaskCompletionSource);
RegisterListener(authTaskCompletionSource, methodName);
authTaskCompletionSource.Task.ContinueWith(_ => System.Threading.Interlocked.Decrement(ref _pendingRequests));
return authTaskCompletionSource.Task;
}

Expand All @@ -44,10 +53,11 @@ public void Receive(string message)
/// Register a listener for the message event
/// </summary>
/// <param name="task"></param>
/// <param name="methodName"></param>
/// <typeparam name="T"></typeparam>
private void RegisterListener<T>(TaskCompletionSource<T> task)
private void RegisterListener<T>(TaskCompletionSource<T> task, string methodName)
{
var listener = new Action<string>(msg => Receiver(task, msg));
var listener = new Action<string>(msg => Receiver(task, msg, methodName));
MessageEvent += listener.Invoke;
task.Task.ContinueWith(_ => { MessageEvent -= listener.Invoke; });
}
Expand All @@ -57,26 +67,43 @@ private void RegisterListener<T>(TaskCompletionSource<T> task)
/// </summary>
/// <param name="task"></param>
/// <param name="message"></param>
/// <param name="methodName"></param>
/// <typeparam name="T"></typeparam>
private static void Receiver<T>(TaskCompletionSource<T> task, string message)
private static void Receiver<T>(TaskCompletionSource<T> task, string message, string methodName)
{
Debug.Log($"{TAG} Receiver | method={methodName} raw_response_len={message.Length} raw_response={message}");
try
{
var authorizationResult = JsonConvert.DeserializeObject<Response<T>>(message);
if (authorizationResult == null)
{
Debug.LogError($"{TAG} Receiver | method={methodName} RESULT=NULL_RESPONSE deserialization returned null raw_len={message.Length}");
task.SetException(new InvalidOperationException($"Response deserialized to null for method {methodName}"));
return;
}
if (authorizationResult.Error != null)
{
Debug.Log($"{TAG} Receiver | method={methodName} RESULT=ERROR id={authorizationResult.Id} code={authorizationResult.Error.Code} message={authorizationResult.Error.Message}");
task.SetException(new Exception(authorizationResult.Error.Message));
}
else
{
var resultJson = JsonConvert.SerializeObject(authorizationResult.Result);
var resultIsNull = authorizationResult.Result == null;
Debug.Log($"{TAG} Receiver | method={methodName} RESULT=SUCCESS id={authorizationResult.Id} result_null={resultIsNull} parsed_result={resultJson}");
task.SetResult(authorizationResult.Result);
}
}
catch (JsonException e)
{
Debug.LogError($"{TAG} Receiver | method={methodName} RESULT=PARSE_ERROR type={e.GetType().Name} message={e.Message} raw_len={message.Length}");
task.SetException(e);
}
catch (Exception e)
{
Debug.LogError($"{TAG} Receiver | method={methodName} RESULT=UNEXPECTED_ERROR type={e.GetType().Name} message={e.Message} stack={e.StackTrace}");
task.SetException(e);
}

}
}
}
}
106 changes: 106 additions & 0 deletions Runtime/codebase/SolanaMobileStack/JsonRpcClient/JsonRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,118 @@ public class JsonRequestParams
[RequiredMember]
public List<string> Addresses { get; set; }

[JsonProperty("chain", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public string Chain { get; set; }

[JsonProperty("features", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public List<string> Features { get; set; }

[JsonProperty("sign_in_payload", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public SignInPayload SignInPayloadData { get; set; }

[JsonProperty("options", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public SignAndSendOptions Options { get; set; }

[RequiredMember]
public JsonRequestParams()
{
}
}

[Serializable]
[Preserve]
public class SignInPayload
{
[JsonProperty("domain", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public string Domain { get; set; }

[JsonProperty("address", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public string Address { get; set; }

[JsonProperty("statement", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public string Statement { get; set; }

[JsonProperty("uri", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public string Uri { get; set; }

[JsonProperty("version", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public string Version { get; set; }

[JsonProperty("chain_id", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public string ChainId { get; set; }

[JsonProperty("nonce", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public string Nonce { get; set; }

[JsonProperty("issued_at", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public string IssuedAt { get; set; }

[JsonProperty("expiration_time", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public string ExpirationTime { get; set; }

[JsonProperty("not_before", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public string NotBefore { get; set; }

[JsonProperty("request_id", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public string RequestId { get; set; }

[JsonProperty("resources", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public List<string> Resources { get; set; }

[Preserve]
[RequiredMember]
public SignInPayload()
{
}
}

[Serializable]
[Preserve]
public class SignAndSendOptions
{
[JsonProperty("min_context_slot", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public ulong? MinContextSlot { get; set; }

[JsonProperty("commitment", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public string Commitment { get; set; }

[JsonProperty("skip_preflight", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public bool? SkipPreflight { get; set; }

[JsonProperty("max_retries", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public int? MaxRetries { get; set; }

[JsonProperty("wait_for_commitment_to_send_next_transaction", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public bool? WaitForCommitmentToSendNextTransaction { get; set; }

[Preserve]
[RequiredMember]
public SignAndSendOptions()
{
}
}

[JsonProperty("jsonrpc")]
[RequiredMember]
public string JsonRpc { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ public class AuthorizationResultAccounts
[JsonProperty("label")]
[RequiredMember]
public string Label { get; set; }

[JsonProperty("chains", NullValueHandling = NullValueHandling.Ignore)]
public List<string> Chains { get; set; }

[JsonProperty("features", NullValueHandling = NullValueHandling.Ignore)]
public List<string> Features { get; set; }

[JsonProperty("icon", NullValueHandling = NullValueHandling.Ignore)]
public string Icon { get; set; }
}


Expand All @@ -31,7 +40,10 @@ public class AuthorizationResultAccounts
[JsonProperty("accounts")]
[RequiredMember]
public List<AuthorizationResultAccounts> Accounts { get; set; }


[JsonProperty("sign_in_result", NullValueHandling = NullValueHandling.Ignore)]
public SignInResult SignInResult { get; set; }
Comment thread
mstevens843 marked this conversation as resolved.

[RequiredMember]
public byte[] PublicKey => Accounts is { Count: > 0 } ? Convert.FromBase64String(Accounts[0].Address) : null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ public class CapabilitiesResult

[JsonProperty("supported_transaction_versions")]
public string[] SupportedTransactionVersions { get; set; }

[JsonProperty("features", NullValueHandling = NullValueHandling.Ignore)]
public string[] Features { get; set; }
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using UnityEngine.Scripting;

// ReSharper disable once CheckNamespace

[Preserve]
public class SignAndSendResult
{
[JsonProperty("signatures")]
[RequiredMember]
public List<string> Signatures { get; set; }

[RequiredMember]
public List<byte[]> SignaturesBytes => Signatures is { Count: > 0 }
? Signatures.Select(Convert.FromBase64String).ToList()
: new List<byte[]>();
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Newtonsoft.Json;
using UnityEngine.Scripting;

// ReSharper disable once CheckNamespace

[Preserve]
public class SignInResult
{
[JsonProperty("address")]
[RequiredMember]
public string Address { get; set; }

[JsonProperty("signed_message")]
[RequiredMember]
public string SignedMessage { get; set; }

[JsonProperty("signature")]
[RequiredMember]
public string Signature { get; set; }

[JsonProperty("signature_type")]
[RequiredMember]
public string SignatureType { get; set; }
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading