diff --git a/Runtime/Plugins/SolanaWalletAdapterWebGL/SolanaWalletAdapterWebGL.jslib b/Runtime/Plugins/SolanaWalletAdapterWebGL/SolanaWalletAdapterWebGL.jslib index ebea7e0b..566ef92d 100644 --- a/Runtime/Plugins/SolanaWalletAdapterWebGL/SolanaWalletAdapterWebGL.jslib +++ b/Runtime/Plugins/SolanaWalletAdapterWebGL/SolanaWalletAdapterWebGL.jslib @@ -1,5 +1,7 @@ mergeInto(LibraryManager.library, { InitWalletAdapter: async function (callback) { + + const isXnft = Boolean("xnft" in window && window.xnft != undefined && window.xnft.solana != undefined && window.xnft.solana.publicKey != undefined); // Add UnityWalletAdapter from CDN if(window.walletAdapterLib == undefined){ console.log("Adding WalletAdapterLib") @@ -8,10 +10,11 @@ document.head.appendChild(script); script.onload = function() { console.log("WalletAdapterLib loaded"); - Module.dynCall_vi(callback); + Module.dynCall_vi(callback, isXnft); }; + }else{ + Module.dynCall_vi(callback, isXnft); } - console.log(window.walletAdapterLib); }, ExternGetWallets: async function(callback) { try { @@ -27,7 +30,12 @@ ExternConnectWallet: async function (walletNamePtr, callback) { try { const walletName = UTF8ToString(walletNamePtr) - var pubKey = await window.walletAdapterLib.connectWallet(walletName); + var pubKey; + if(walletName === 'XNFT'){ + pubKey = window.xnft.solana.publicKey.toString(); + } else { + pubKey = await window.walletAdapterLib.connectWallet(walletName); + } var bufferSize = lengthBytesUTF8(pubKey) + 1; var pubKeyPtr = _malloc(bufferSize); stringToUTF8(pubKey, pubKeyPtr, bufferSize); @@ -40,8 +48,14 @@ try { const walletName = UTF8ToString(walletNamePtr) var base64transaction = UTF8ToString(transactionPtr) - var signedTransaction = await window.walletAdapterLib.signTransaction(walletName, base64transaction); - var signature = signedTransaction.signature.toString('base64'); + let signedTransaction; + if(walletName === 'XNFT'){ + const transaction = window.walletAdapterLib.getTransactionFromStr(base64transaction); + signedTransaction = await window.xnft.solana.signTransaction(transaction); + } else { + signedTransaction = await window.walletAdapterLib.signTransaction(walletName, base64transaction); + } + let signature = signedTransaction.signature.toString('base64'); var bufferSize = lengthBytesUTF8(signature) + 1; var signaturePtr = _malloc(bufferSize); stringToUTF8(signature, signaturePtr, bufferSize); @@ -54,8 +68,15 @@ try { const walletName = UTF8ToString(walletNamePtr) var base64Message = UTF8ToString(messagePtr) - var signature = await window.walletAdapterLib.signMessage(walletName, base64Message); - var signatureStr = signature.toString('base64'); + let signatureStr; + if(walletName === 'XNFT'){ + const messageBytes = Uint8Array.from(atob(base64Message), (c) => c.charCodeAt(0)); + const signedMessage = await window.xnft.solana.signMessage(messageBytes); + signatureStr = JSON.stringify(Array.from(signedMessage)); + } else { + var signature = await window.walletAdapterLib.signMessage(walletName, base64Message); + signatureStr = signature.toString('base64'); + } var bufferSize = lengthBytesUTF8(signatureStr) + 1; var signaturePtr = _malloc(bufferSize); stringToUTF8(signatureStr, signaturePtr, bufferSize); @@ -69,7 +90,17 @@ const walletName = UTF8ToString(walletNamePtr) var base64transactionsStr = UTF8ToString(transactionsPtr) var base64transactions = base64transactionsStr.split(','); - var signedTransactions = await window.walletAdapterLib.signAllTransactions(walletName, base64transactions); + let signedTransactions; + if(walletName === 'XNFT'){ + let transactions = []; + for(var i = 0; i < base64transactions.length; i++){ + const transaction = window.walletAdapterLib.getTransactionFromStr(base64transactions[i]); + transactions.push(transaction); + } + signedTransactions = await window.xnft.solana.signAllTransactions(transactions); + } else { + signedTransactions = await window.walletAdapterLib.signAllTransactions(walletName, base64transactions); + } var signatures = []; for (var i = 0; i < signedTransactions.length; i++) { var signedTransaction = signedTransactions[i]; diff --git a/Runtime/Plugins/xNFT.jslib b/Runtime/Plugins/xNFT.jslib deleted file mode 100644 index ec2f04bb..00000000 --- a/Runtime/Plugins/xNFT.jslib +++ /dev/null @@ -1,58 +0,0 @@ -mergeInto(LibraryManager.library, { - ExternConnectXNFT: async function (callback) { - if ("xnft" in window && window.xnft != undefined && window.xnft.solana != undefined && window.xnft.solana.publicKey != undefined) { - try { - var pubKey = window.xnft.solana.publicKey.toString(); - var lenPubKey = lengthBytesUTF8(pubKey) + 1; - var strPtr = _malloc(lenPubKey); - stringToUTF8(pubKey, strPtr, lenPubKey); - Module.dynCall_vi(callback, strPtr); - } catch (err) { - console.error(err.message); - } - } else { - console.log("Not running in Backpack wallet"); - } - }, - - ExternSignTransactionXNFT: async function (transaction, callback) { - if ("xnft" in window && window.xnft != undefined && window.xnft.solana != undefined) { - try { - const messageBase58 = UTF8ToString(transaction); - const message = solanaWeb3.Message.from(bs58.decode(messageBase58)); - const tx = solanaWeb3.Transaction.populate(message); - const signedTransaction = await window.xnft.solana.signTransaction(tx); - var sign = bs58.encode(signedTransaction.signature); - var lenSign = lengthBytesUTF8(sign) + 1; - var strPtr = _malloc(lenSign); - stringToUTF8(sign, strPtr, lenSign); - console.log(strPtr); - Module.dynCall_vi(callback, strPtr); - } catch (err) { - console.error(err.message); - } - } else { - console.error("Not running in Backpack wallet"); - } - }, - - ExternSignMessageXNFT: async function (message, callback) { - if ('xnft' in window && window.xnft != undefined && window.xnft.solana != undefined) { - try { - const messageBase64String = UTF8ToString(message); - const messageBytes = Uint8Array.from(atob(messageBase64String), (c) => c.charCodeAt(0)); - const signedMessage = await window.xnft.solana.signMessage(messageBytes); - console.log(signedMessage); - var sign = JSON.stringify(Array.from(signedMessage)); - var lenSign = lengthBytesUTF8(sign) + 1; - var strPtr = _malloc(lenSign); - stringToUTF8(sign, strPtr, lenSign); - Module.dynCall_vi(callback, strPtr); - } catch (err) { - console.error(err.message); - } - } else { - console.error("Not running in Backpack wallet"); - } - }, -}); diff --git a/Runtime/Plugins/xNFT.jslib.meta b/Runtime/Plugins/xNFT.jslib.meta deleted file mode 100644 index 8f69c457..00000000 --- a/Runtime/Plugins/xNFT.jslib.meta +++ /dev/null @@ -1,32 +0,0 @@ -fileFormatVersion: 2 -guid: e8b6e98263eeea55d9c24a07b49f8234 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 1 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - - first: - WebGL: WebGL - second: - enabled: 1 - settings: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/codebase/Exporters/WebGLTemplatesExporter.cs b/Runtime/codebase/Exporters/WebGLTemplatesExporter.cs index c86a61a6..fb2b36f8 100644 --- a/Runtime/codebase/Exporters/WebGLTemplatesExporter.cs +++ b/Runtime/codebase/Exporters/WebGLTemplatesExporter.cs @@ -1,4 +1,4 @@ -#if UNITY_WEBGL && UNITY_EDITOR +#if UNITY_WEBGL && UNITY_EDITOR using UnityEngine; using UnityEditor; diff --git a/Runtime/codebase/Exporters/WebGLTemplatesExporter.cs.meta b/Runtime/codebase/Exporters/WebGLTemplatesExporter.cs.meta index 3712e794..47c0ab9d 100644 --- a/Runtime/codebase/Exporters/WebGLTemplatesExporter.cs.meta +++ b/Runtime/codebase/Exporters/WebGLTemplatesExporter.cs.meta @@ -1,11 +1,3 @@ -fileFormatVersion: 2 -guid: d26bbcb00a0eaa0d098bb5ed7e983e17 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: d41289880070433aa49f34521a109e46 +timeCreated: 1683883584 \ No newline at end of file diff --git a/Runtime/codebase/SolanaWalletAdapterWebGL/SolanaWalletAdapterWebGL.cs b/Runtime/codebase/SolanaWalletAdapterWebGL/SolanaWalletAdapterWebGL.cs index 1e5542d1..b6bbee88 100644 --- a/Runtime/codebase/SolanaWalletAdapterWebGL/SolanaWalletAdapterWebGL.cs +++ b/Runtime/codebase/SolanaWalletAdapterWebGL/SolanaWalletAdapterWebGL.cs @@ -22,7 +22,7 @@ public class SolanaWalletAdapterWebGL: WalletBase private static SolanaWalletAdapterWebGLOptions _walletOptions; private static TaskCompletionSource _loginTaskCompletionSource; private static TaskCompletionSource _getWalletsTaskCompletionSource; - private static TaskCompletionSource _loadedScriptTaskCompletionSource; + private static TaskCompletionSource _walletsInitializedTaskCompletionSource; private static TaskCompletionSource _signedTransactionTaskCompletionSource; private static TaskCompletionSource _signedAllTransactionsTaskCompletionSource; private static TaskCompletionSource _signedMessageTaskCompletionSource; @@ -72,19 +72,34 @@ public SolanaWalletAdapterWebGL( } private static async Task InitWallets() { - if (Wallets == null){ - _loadedScriptTaskCompletionSource = new TaskCompletionSource(); - InitWalletAdapter(OnScriptLoaded); - await _loadedScriptTaskCompletionSource.Task; + _currentWallet = null; + _walletsInitializedTaskCompletionSource = new TaskCompletionSource(); + InitWalletAdapter(OnWalletsInitialized); + bool isXnft = await _walletsInitializedTaskCompletionSource.Task; + if (isXnft){ + _currentWallet = new WalletSpecs() + { + name = "XNFT", + icon = "", + installed = true + }; + } else{ + _getWalletsTaskCompletionSource = new TaskCompletionSource(); + ExternGetWallets(OnWalletsLoaded); + var walletsData = await _getWalletsTaskCompletionSource.Task; + Wallets = JsonUtility.FromJson(walletsData).wallets; } - _getWalletsTaskCompletionSource = new TaskCompletionSource(); - ExternGetWallets(OnWalletsLoaded); - var walletsData = await _getWalletsTaskCompletionSource.Task; - Wallets = JsonUtility.FromJson(walletsData).wallets; - } - - + + + /// + /// Check whether it's an XNFT or not + /// + /// true if it's an XNFT, false otherwise + public static async Task IsXnft(){ + await InitWallets(); + return _currentWallet != null && _currentWallet.name == "XNFT"; + } protected override async Task _Login(string password = null) { @@ -99,29 +114,36 @@ protected override async Task _Login(string password = null) Debug.LogError("WalletAdapter _Login -> Exception: " + e); _loginTaskCompletionSource.SetResult(null); } - WalletAdapterUI.SetActive(false); + if (WalletAdapterUI != null ){ + WalletAdapterUI.SetActive(false); + } return await _loginTaskCompletionSource.Task; } private static async Task SetCurrentWallet() { await InitWallets(); - if (WalletAdapterUI == null) + if (_currentWallet == null) { - WalletAdapterUI = GameObject.Instantiate(_walletOptions.walletAdapterUIPrefab); + if (WalletAdapterUI == null) + { + WalletAdapterUI = GameObject.Instantiate(_walletOptions.walletAdapterUIPrefab); + } + + var waitForWalletSelectionTask = new TaskCompletionSource(); + var walletAdapterScreen = + WalletAdapterUI.transform.GetChild(0).gameObject.GetComponent(); + walletAdapterScreen.viewPortContent = WalletAdapterUI.transform.GetChild(0).Find("Scroll View") + .Find("Viewport").Find("Content").GetComponent(); + walletAdapterScreen.buttonPrefab = _walletOptions.walletAdapterButtonPrefab; + walletAdapterScreen.OnSelectedAction = walletName => + { + waitForWalletSelectionTask.SetResult(walletName); + }; + WalletAdapterUI.SetActive(true); + var walletName = await waitForWalletSelectionTask.Task; + _currentWallet = Array.Find(Wallets, wallet => wallet.name == walletName); } - - var waitForWalletSelectionTask = new TaskCompletionSource(); - var walletAdapterScreen = WalletAdapterUI.transform.GetChild(0).gameObject.GetComponent(); - walletAdapterScreen.viewPortContent = WalletAdapterUI.transform.GetChild(0).Find("Scroll View").Find("Viewport").Find("Content").GetComponent(); - walletAdapterScreen.buttonPrefab = _walletOptions.walletAdapterButtonPrefab; - walletAdapterScreen.OnSelectedAction = walletName => - { - waitForWalletSelectionTask.SetResult(walletName); - }; - WalletAdapterUI.SetActive(true); - var walletName = await waitForWalletSelectionTask.Task; - _currentWallet = Array.Find(Wallets, wallet => wallet.name == walletName); } protected override Task _SignTransaction(Transaction transaction) @@ -219,12 +241,12 @@ public static void OnMessageSigned(string signature) } /// - /// Called from javascript when the wallet adapter script is loaded + /// Called from javascript when the wallet adapter script is loaded. Returns whether it's an XNFT or not. /// [MonoPInvokeCallback(typeof(Action))] - private static void OnScriptLoaded(bool success) + private static void OnWalletsInitialized(bool isXnft) { - _loadedScriptTaskCompletionSource.SetResult(success); + _walletsInitializedTaskCompletionSource.SetResult(isXnft); } /// diff --git a/Runtime/codebase/Web3.cs b/Runtime/codebase/Web3.cs index a49c139b..0fecf525 100644 --- a/Runtime/codebase/Web3.cs +++ b/Runtime/codebase/Web3.cs @@ -141,13 +141,17 @@ private void Start() if(w == null) return; WalletBase = _web3AuthWallet; }; - // Try to login if running as an XNFT - LoginXNFT().AsUniTask().Forget(); } catch (Exception e) { Debug.Log("We3Auth session not detected, " + e.Message); } + + #if UNITY_WEBGL + LoginXNFT().AsUniTask().Forget(); + #endif + + } /// @@ -191,21 +195,18 @@ public async Task LoginInWeb3Auth(Provider provider) return acc; } - /// - /// Login to backpack, if running as an xnft - /// - /// - public async Task LoginXNFT() { - var xnftWallet = new XNFTWallet(rpcCluster, customRpc, webSocketsRpc, false); - var acc = await xnftWallet.Login(); - if (acc != null) - WalletBase = xnftWallet; - return acc; + var isXnft = await SolanaWalletAdapterWebGL.IsXnft(); + if (isXnft) + { + Debug.Log("xNFT detected"); + return await LoginWalletAdapter(); + } + Debug.Log("xNFT not detected"); + return null; } - - + /// /// Login using the solana wallet adapter /// diff --git a/Runtime/codebase/WebGLTemplates/xNFT/index.html b/Runtime/codebase/WebGLTemplates/xNFT/index.html index 07459ce9..ebabd186 100644 --- a/Runtime/codebase/WebGLTemplates/xNFT/index.html +++ b/Runtime/codebase/WebGLTemplates/xNFT/index.html @@ -7,167 +7,7 @@ - - - +
@@ -210,7 +50,7 @@ } var buildUrl = "Build"; - var loaderUrl = buildUrl + "/Solana.Unity-SDK.loader.js"; + var loaderUrl = buildUrl + "/{{{ LOADER_FILENAME }}}"; var config = { dataUrl: "Build/{{{ DATA_FILENAME }}}", frameworkUrl: "Build/{{{ FRAMEWORK_FILENAME }}}", diff --git a/Runtime/codebase/XNFTWallet.cs b/Runtime/codebase/XNFTWallet.cs deleted file mode 100644 index efb909c4..00000000 --- a/Runtime/codebase/XNFTWallet.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Threading.Tasks; -using AOT; -using Solana.Unity.Rpc.Models; -using Solana.Unity.Wallet; -using Solana.Unity.Wallet.Utilities; -using UnityEngine; - -// ReSharper disable once CheckNamespace - -namespace Solana.Unity.SDK -{ - public class XNFTWallet: WalletBase - { - - private static TaskCompletionSource _loginTaskCompletionSource; - private static TaskCompletionSource _signedTransactionTaskCompletionSource; - private static TaskCompletionSource _signedMessageTaskCompletionSource; - private static Transaction _currentTransaction; - private static Account _account; - - public XNFTWallet(RpcCluster rpcCluster = RpcCluster.DevNet, string customRpcUri = null, string customStreamingRpcUri = null, bool autoConnectOnStartup = false) - : base(rpcCluster, customRpcUri, customStreamingRpcUri, autoConnectOnStartup) - { - - } - - protected override Task _Login(string password = null) - { - _loginTaskCompletionSource = new TaskCompletionSource(); - try - { - ExternConnectXNFT(OnXNFTConnected); - } - catch (EntryPointNotFoundException) - { - _loginTaskCompletionSource.SetResult(null); - return _loginTaskCompletionSource.Task; - } - return _loginTaskCompletionSource.Task; - } - - protected override Task _SignTransaction(Transaction transaction) - { - _signedTransactionTaskCompletionSource = new TaskCompletionSource(); - var encode = Encoders.Base58.EncodeData(transaction.CompileMessage()); - _currentTransaction = transaction; - ExternSignTransactionXNFT(encode, OnTransactionSigned); - return _signedTransactionTaskCompletionSource.Task; - } - - protected override Task _SignAllTransactions(Transaction[] transactions) - { - throw new NotImplementedException(); - } - - public override Task SignMessage(byte[] message) - { - _signedMessageTaskCompletionSource = new TaskCompletionSource(); - ExternSignMessageXNFT(Convert.ToBase64String(message), OnMessageSigned); - return _signedMessageTaskCompletionSource.Task; - } - - protected override Task _CreateAccount(string mnemonic = null, string password = null) - { - throw new NotImplementedException(); - } - - #region WebGL Callbacks - - /// - /// Called from java script when the xnft approves the connection - /// - [MonoPInvokeCallback(typeof(Action))] - private static void OnXNFTConnected(string walletPubKey) - { - Debug.Log($"Wallet {walletPubKey} connected!"); - _account = new Account("", walletPubKey); - _loginTaskCompletionSource.SetResult(_account); - } - - /// - /// Called from java script when the xnft wallet signed the transaction and return the signature - /// that we then need to put into the transaction before we send it out. - /// - [MonoPInvokeCallback(typeof(Action))] - public static void OnTransactionSigned(string signature) - { - _currentTransaction.Signatures.Add(new SignaturePubKeyPair() - { - PublicKey = _account.PublicKey, - Signature = Encoders.Base58.DecodeData(signature) - }); - _signedTransactionTaskCompletionSource.SetResult(_currentTransaction); - } - - /// - /// Called from java script when the xnft wallet signed the message and return the signature. - /// - [MonoPInvokeCallback(typeof(Action))] - public static void OnMessageSigned(string signature) - { - var signatureArray = JsonUtility.FromJson(signature); - Debug.Log("SignatureArray: " + signatureArray); - _signedMessageTaskCompletionSource.SetResult(signatureArray); - } - - #endregion - - #if UNITY_WEBGL - - [DllImport("__Internal")] - private static extern void ExternConnectXNFT(Action callback); - - [DllImport("__Internal")] - private static extern void ExternSignTransactionXNFT(string transaction, Action callback); - - [DllImport("__Internal")] - private static extern void ExternSignMessageXNFT(string message, Action callback); - - #else - private static void ExternConnectXNFT(Action callback){} - private static void ExternSignTransactionXNFT(string transaction, Action callback){} - private static void ExternSignMessageXNFT(string message, Action callback){} - #endif - } -} \ No newline at end of file diff --git a/Runtime/codebase/XNFTWallet.cs.meta b/Runtime/codebase/XNFTWallet.cs.meta deleted file mode 100644 index 17cb70b2..00000000 --- a/Runtime/codebase/XNFTWallet.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5664e7b366df6aa49bf2054a6a45a11e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Samples~/Solana Wallet/Scripts/example/DropdownClusterSelector.cs b/Samples~/Solana Wallet/Scripts/example/DropdownClusterSelector.cs index 195b0b3f..5d3699de 100644 --- a/Samples~/Solana Wallet/Scripts/example/DropdownClusterSelector.cs +++ b/Samples~/Solana Wallet/Scripts/example/DropdownClusterSelector.cs @@ -1,6 +1,7 @@ using Solana.Unity.SDK; using TMPro; using UnityEngine; +using Cysharp.Threading.Tasks; // ReSharper disable once CheckNamespace @@ -32,5 +33,6 @@ public void RpcNodeDropdownSelected(int value) }; PlayerPrefs.SetInt("rpcCluster", value); PlayerPrefs.Save(); + Web3.Instance.LoginXNFT().AsUniTask().Forget(); } } diff --git a/Samples~/Solana Wallet/Scripts/example/screens/LoginScreen.cs b/Samples~/Solana Wallet/Scripts/example/screens/LoginScreen.cs index c5b23401..c406b384 100644 --- a/Samples~/Solana Wallet/Scripts/example/screens/LoginScreen.cs +++ b/Samples~/Solana Wallet/Scripts/example/screens/LoginScreen.cs @@ -54,7 +54,7 @@ private void Start() loginBtnTwitter.onClick.AddListener(delegate{LoginCheckerWeb3Auth(Provider.TWITTER);}); loginBtnWalletAdapter.onClick.AddListener(LoginCheckerWalletAdapter); loginBtnSms.onClick.AddListener(LoginCheckerSms); - loginBtnXNFT.onClick.AddListener(LoginCheckerXnft); + loginBtnXNFT.onClick.AddListener(LoginCheckerWalletAdapter); loginBtnXNFT.gameObject.SetActive(false); @@ -87,19 +87,6 @@ private async void LoginCheckerWeb3Auth(Provider provider) CheckAccount(account); } - public void TryLoginBackPack() - { - LoginCheckerXnft(); - } - - private async void LoginCheckerXnft() - { - if(Web3.Instance == null) return; - var account = await Web3.Instance.LoginXNFT(); - messageTxt.text = ""; - CheckAccount(account); - } - private async void LoginCheckerWalletAdapter() { if(Web3.Instance == null) return;