diff --git a/Runtime/codebase/SessionWallet.cs b/Runtime/codebase/SessionWallet.cs index 69cd53d..3ba1c00 100644 --- a/Runtime/codebase/SessionWallet.cs +++ b/Runtime/codebase/SessionWallet.cs @@ -21,6 +21,7 @@ public class SessionWallet : InGameWallet public PublicKey SessionTokenPDA { get; protected set; } public static SessionWallet Instance; + private static WalletBase _externalWallet; private SessionWallet(RpcCluster rpcCluster = RpcCluster.DevNet, string customRpcUri = null, string customStreamingRpcUri = null, @@ -58,25 +59,28 @@ private static PublicKey FindSessionToken(PublicKey TargetProgram, Account Accou sessionSigner: Account.PublicKey ); } - + + public void SignInitSessionTx(Transaction tx) + { + tx.PartialSign(new[] { _externalWallet.Account, Account }); + } + + /// /// Creates a new SessionWallet instance and logs in with the provided password if a session wallet exists, otherwise creates a new account and logs in. /// /// The target program to interact with. /// The password to decrypt the session keystore. - /// The Solana RPC cluster to connect to. - /// A custom URI to connect to the Solana RPC cluster. - /// A custom URI to connect to the Solana streaming RPC cluster. - /// Whether to automatically connect to the Solana RPC cluster on startup. + /// The external wallet /// A SessionWallet instance. - public static async Task GetSessionWallet(PublicKey targetProgram, string password, RpcCluster rpcCluster = RpcCluster.DevNet, - string customRpcUri = null, string customStreamingRpcUri = null, - bool autoConnectOnStartup = false) + public static async Task GetSessionWallet(PublicKey targetProgram, string password, WalletBase externalWallet = null) { if(Instance != null) return Instance; - SessionWallet sessionWallet = new SessionWallet(rpcCluster, customRpcUri, customStreamingRpcUri, autoConnectOnStartup); + externalWallet ??= Web3.Wallet; + _externalWallet = externalWallet; + SessionWallet sessionWallet = new SessionWallet(externalWallet.RpcCluster, externalWallet.ActiveRpcClient.NodeAddress.ToString()); sessionWallet.TargetProgram = targetProgram; - sessionWallet.EncryptedKeystoreKey = $"{Web3.Account.PublicKey}_SessionKeyStore"; + sessionWallet.EncryptedKeystoreKey = $"{_externalWallet.Account.PublicKey}_SessionKeyStore"; var derivedPassword = DeriveSessionPassword(password); if (sessionWallet.HasSessionWallet()) @@ -89,10 +93,10 @@ public static async Task GetSessionWallet(PublicKey targetProgram sessionWallet.DeleteSessionWallet(); sessionWallet.Logout(); Instance = null; - return await GetSessionWallet(targetProgram, password, rpcCluster, customRpcUri, customStreamingRpcUri, autoConnectOnStartup); + return await GetSessionWallet(targetProgram, password, externalWallet); } - sessionWallet.SessionTokenPDA = FindSessionToken(targetProgram, sessionWallet.Account, Web3.Account); + sessionWallet.SessionTokenPDA = FindSessionToken(targetProgram, sessionWallet.Account, _externalWallet.Account); Debug.Log(sessionWallet.SessionTokenPDA); @@ -109,14 +113,14 @@ public static async Task GetSessionWallet(PublicKey targetProgram } Debug.Log("Session Token is invalid"); - await sessionWallet.PrepareLogout(); + await sessionWallet.CloseSession(); sessionWallet.Logout(); Instance = null; - return await GetSessionWallet(targetProgram, password, rpcCluster, customRpcUri, customStreamingRpcUri, autoConnectOnStartup); + return await GetSessionWallet(targetProgram, password, externalWallet); } sessionWallet.Account = await sessionWallet.CreateAccount(password: derivedPassword); - sessionWallet.SessionTokenPDA = FindSessionToken(targetProgram, sessionWallet.Account, Web3.Account); + sessionWallet.SessionTokenPDA = FindSessionToken(targetProgram, sessionWallet.Account, _externalWallet.Account); return sessionWallet; } @@ -133,7 +137,7 @@ public TransactionInstruction CreateSessionIX(bool topUp, long sessionValidity) { SessionToken = SessionTokenPDA, SessionSigner = Account.PublicKey, - Authority = Web3.Account, + Authority = _externalWallet.Account, TargetProgram = TargetProgram, SystemProgram = SystemProgram.ProgramIdKey, }; @@ -155,7 +159,7 @@ public TransactionInstruction RevokeSessionIX() { SessionToken = SessionTokenPDA, // Only the authority of the session token can receive the refund - Authority = Web3.Account, + Authority = _externalWallet.Account, SystemProgram = SystemProgram.ProgramIdKey, }; @@ -185,8 +189,15 @@ public async Task IsSessionTokenValid() return SessionToken.Deserialize(Convert.FromBase64String(sessionTokenData)).ValidUntil > DateTimeOffset.UtcNow.ToUnixTimeSeconds(); } + public async Task Authority() + { + var sessionTokenData = (await ActiveRpcClient.GetAccountInfoAsync(SessionTokenPDA)).Result.Value.Data[0]; + if (sessionTokenData == null) return null; + return SessionToken.Deserialize(Convert.FromBase64String(sessionTokenData)).Authority; + } + private static string DeriveSessionPassword(string password) { - var rawData = Web3.Account.PublicKey.Key + password + Application.platform; + var rawData = _externalWallet.Account.PublicKey.Key + password + Application.platform; using SHA256 sha256Hash = SHA256.Create(); // ComputeHash - returns byte array var bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); @@ -207,7 +218,7 @@ private void DeleteSessionWallet() /// NOTE: You must call PrepareLogout before calling Logout to ensure that the session token account is revoked and the refund is issued. /// /// A task that represents the asynchronous operation. - public async Task PrepareLogout() + public async Task CloseSession(Commitment commitment = Commitment.Confirmed) { Debug.Log("Preparing Logout"); // Revoke Session @@ -215,7 +226,7 @@ public async Task PrepareLogout() { FeePayer = Account, Instructions = new List(), - RecentBlockHash = await Web3.BlockHash() + RecentBlockHash = await GetBlockHash(commitment) }; // Get balance and calculate refund @@ -226,9 +237,8 @@ public async Task PrepareLogout() tx.Add(RevokeSessionIX()); // Issue Refund - tx.Add(SystemProgram.Transfer(Account.PublicKey, Web3.Account.PublicKey, (ulong)refund)); - var rest = await SignAndSendTransaction(tx); - Debug.Log("Session refund transaction: " + rest.RawRpcResponse); + tx.Add(SystemProgram.Transfer(Account.PublicKey, _externalWallet.Account.PublicKey, (ulong)refund)); + var rest = await SignAndSendTransaction(tx, commitment: commitment); DeleteSessionWallet(); } }