Last active
March 4, 2022 19:22
-
-
Save nasdf/d8b7fb4e570e563e990c52501bdfdfa7 to your computer and use it in GitHub Desktop.
Unity3D NFT License
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Nethereum.Signer; | |
using System; | |
using System.Numerics; | |
using System.Runtime.InteropServices; | |
using System.Threading.Tasks; | |
using UnityEngine; | |
public class NFTLicense : MonoBehaviour | |
{ | |
[DllImport("__Internal")] | |
private static extern void Web3Connect(); | |
[DllImport("__Internal")] | |
private static extern string ConnectAccount(); | |
[DllImport("__Internal")] | |
private static extern void SetConnectAccount(string value); | |
private static string PREFS_SIGNATURE = "license-signature"; | |
private static string PREFS_EXPIRATION = "license-expiration"; | |
private static string MESSAGE_SALT = "replace-with-your-salt"; // TODO | |
public string chain = "polygon"; | |
public string network = "mainnet"; | |
public string contract = "0xb85ed41d49Eba25aE6186921Ea63b6055903e810"; // TODO | |
public string tokenId = "<INSERT YOUR LICENSE ID HERE>"; // TODO | |
private string address; | |
private string signature; | |
private string expiration; | |
public async void OnLogin() | |
{ | |
// restore from preferences if previously logged in | |
signature = PlayerPrefs.GetString(PREFS_SIGNATURE, ""); | |
expiration = PlayerPrefs.GetString(PREFS_EXPIRATION, ""); | |
// initialize web3 provider | |
Web3Connect(); | |
// connect an account | |
address = ConnectAccount(); | |
while (address == "") | |
{ | |
await new WaitForSeconds(1f); | |
address = ConnectAccount(); | |
} | |
// reset login message | |
SetConnectAccount(""); | |
// verify NFT license ownership | |
var authorized = await IsAuthorized(); | |
while (!authorized) | |
{ | |
await new WaitForSeconds(1f); | |
authorized = await SignIn(); | |
} | |
Debug.Log("SUCCESS"); | |
} | |
private async Task<bool> IsAuthorized() | |
{ | |
// make sure the signature expiration is still valid | |
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); | |
if (!long.TryParse(expiration, out var result) || now > result) | |
{ | |
Debug.Log("token expired"); | |
return false; | |
} | |
// recover the signer address from the original message | |
var signer = new EthereumMessageSigner(); | |
var message = MESSAGE_SALT + expiration; | |
var recovered = signer.EncodeUTF8AndEcRecover(message, signature); | |
// make sure the signer address matches the current address | |
if (!String.Equals(recovered, address, StringComparison.OrdinalIgnoreCase)) | |
{ | |
Debug.Log("address mismatch"); | |
Debug.Log(recovered); | |
Debug.Log(address); | |
return false; | |
} | |
// ensure the address has at least one license | |
BigInteger balanceOf = await ERC1155.BalanceOf(chain, network, contract, address, tokenId); | |
Debug.Log(balanceOf); | |
return balanceOf > 0; | |
} | |
private async Task<bool> SignIn() | |
{ | |
// sign out the previous account | |
SignOut(); | |
// create an expiration timestamp 12 hours from now | |
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); | |
expiration = $"{timestamp + (60 * 60 * 12)}"; | |
// sign the expiration so we can prove ownership | |
var message = MESSAGE_SALT + expiration; | |
signature = await Web3GL.Sign(message); | |
// check if the user is authorized | |
var authorized = await IsAuthorized(); | |
if (!authorized) | |
{ | |
return false; | |
} | |
// save the signature and expiration so we can verify later | |
PlayerPrefs.SetString(PREFS_SIGNATURE, signature); | |
PlayerPrefs.SetString(PREFS_EXPIRATION, expiration); | |
PlayerPrefs.Save(); | |
return true; | |
} | |
private void SignOut() | |
{ | |
PlayerPrefs.DeleteKey(PREFS_SIGNATURE); | |
PlayerPrefs.DeleteKey(PREFS_EXPIRATION); | |
PlayerPrefs.Save(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment