Plugin for integrating the Nano cryptocurrency into Unity.
Available on the Unity asset store
Tested on Windows/Linux/MacOS/Android/iOS/HTML with Unity 2020.3.2f1
Features include: functions for processing blocks, creating seeds + reading/saving them to disk in password-protected encrypted files. Generating qr codes, listening for payments to single accounts, private key payouts and many more.
The easiest way to get started is to open up the scene in Scenes/SampleScene.unity. This provides a demo level to explore all the available functionality and connects to a publically available nodejs server.
NanoUtils.cs
contains various generic functions such as creating seeds, encrypting/decrypting them using AES with a password, converting to accounts, converting between Raw and Nano and various other things.
NanoWebsocket.cs
maintains the websocket connection to the proxies.
NanoManager.cs
is where all other functionality is located
NanoAmount.cs
is a helper class for storing and manipulating the raw units in Nano
RPC.cs
connects to a server forward proxy for the nano node
NanoDemo.cs
contains content for the sample scene which illustrates all the functionality available.
TestUtils.cs
contains test for various things.
To set up using the Nano plugin copy the Nano folder across to your project. The Scripts/Scenes folders are not required for deployment. A simple example of setting up the necessary functions with the public servers is:
using NanoPlugin;
public class NanoDemo : MonoBehaviour
{
void Start()
{
// Initialize the NanoManager & NanoWebsocket
nanoManager = gameObject.AddComponent<NanoManager>();
nanoManager.rpcURL = "http://95.216.164.23:28103"; // Modify url to RPC server host:port
nanoManager.defaultRep = "nano_387tj8fjeo6r35ry5tjppympp8dct4d1ogpis7uaxsw8ywsrgp6shfge7two";
nanoWebsocket = gameObject.AddComponent<NanoWebSocket>();
nanoWebsocket.url = "ws://95.216.164.23:28104"; // Modify url to websocket server host:port
nanoManager.Websocket = nanoWebsocket;
}
private NanoWebSocket websocket;
private NanoManager nanoManager;
};
byte[] privateKey = NanoUtils.GeneratePrivateKey();
string hexPrivateKey = NanoUtils.ByteArrayToHexString(privateKey);
byte[] privateKey = NanoUtils.HexStringToByteArray(hexPrivateKey);
string address = NanoUtils.PrivateKeyToAddress(privateKey);
string publicKey = NanoUtils.PrivateKeyToPublicKeyHexString(privateKey);
string publicKey = NanoUtils.AddressToPublicKeyHexString(address);
string address = NanoUtils.PublicKeyToAddress(publicKey);
These are low level building block functions which are not always necessary, it is recommened to use the utility functions mentioned below which encapsulates most of this.
// First we get the frontier
yield return nanoManager.AccountInfo(address, (accountInfo) =>
{
var previous = accountInfo.frontier;
var rep = accountInfo.representative;
if (previous != null)
// account exists
});
List<PendingBlock> pendingBlocks = null;
yield return nanoManager.PendingBlocks(address, (responsePendingBlocks) =>
{
pendingBlocks = responsePendingBlocks;
});
if (pendingBlocks != null && pendingBlocks.Count > 0)
....
var block = nanoManager.CreateBlock(address, NanoUtils.HexStringToByteArray(privateKey), newBalance, link, previous, rep, work);
nanoManager.Process(block, BlockType.send, (hash) =>
{
if (hash != null)
// Block is processed
}
var texture2D = NanoUtils.GenerateQRCodeTextureWithAmount(250, address, numRawPayToPlay, 50);
var sprite = Sprite.Create(texture2D, new Rect(0.0f, 0.0f, texture2D.width, texture2D.height), new Vector2(0.5f, 0.5f), 100.0f);
IEnumerator SendWaitConfHandler()
{
yield return nanoManager.SendWaitConf(toAddress, amount, privateKey, (error, hash) =>
{
if (!error)
{
Debug.Log("Send wait confirmed!!");
}
else
{
Debug.Log("Error with SendWaitConf");
}
});
}
private IEnumerator SendHandler()
{
yield return nanoManager.Send(toAddress, amount, privateKey, (error, hash) =>
{
if (!error)
{
Debug.Log("Send confirmed!!");
}
else
{
Debug.Log("Error with Send");
}
});
}
yield return nanoManager.ReceiveWaitConf(address, pendingBlock, privateKey, (error, hash) => { }
yield return nanoManager.Receive(address, pendingBlock, privateKey, (error, hash) => { }
nanoManager.AutomatePocketing(address, privateKey, (block) =>
{
// block is the block received for the
});
// Register a confirmation listener, can have multiple of these
nanoManager.AddConfirmationListener((websocketConfirmationResponse) =>
{
var block = websocketConfirmationResponse.message.block;
// Do something, show a ball etc
});
// Set up the pipelining for the above confirmation listener
nanoManager.ListenAllConfirmations();
Note: Make sure that config.js
on the server has listen_all = true
Recommendation setups for:
Listen to payment - Have 1 seed per arcade machine, start at first index then increment each time a payment is needed. This only checks pending blocks, don't have anything else pocketing these funds automatically. Every time a new payment is needed, move to the next index. Only 1 payment can be listening at any 1 time!
Create a QR code for the account/amount required. Then listen for the payment. For payouts do a similar process with showing a QR Code (use the variant taking a private key), and listen for payout.
Create seed for player and store it encrypted with password (also check for local seed files if they want to open them)
Loop through seed files, save seed & send and wait for confirmation.
Process seed (as above), create & sign block locally and hand off to server.
Server does validation (checks block is valid) then does appropriate action and send response to client.
Requires running a nano node, as well as npm
and nodejs
being installed.
- Run the
nano_node
binary after enabling rpc and websocket inconfig-node.toml
file.nano_node --daemon
cd TestServer
- Modify the
config.js
settings to be applicable for your system. npm install
node server.js
A nano node is required to be running which the websocket & http server (for RPC requests) will communicate with. Websocket & RPC should be enabled in the node-config.toml
nano file.
A http server (for RPC requests) is definitely needed for communicating with the nano node via JSON-RPC, a test nodejs script is supplied for this called server.js
. A websocket server to receive notifications from the nano network is highly recommended to make the most use of the plugin functionality. Another test server called websocket_node.js
listening for confirmations for blocks in real-time on the nano network. server_work_callback.js
communicate with dpow (distributed POW) for work generation, a work_peer
in node-config.toml
should be set up for this, all these scripts are found in the ./TestServer subdirectory. Running server.js
will also run websocket_node.js
& server_work_callback,js
. The websocket script makes 2 connections to the node, 1 is filtered output and 1 gets all websocket events (usual for visualisers). If you only need filtered output (recommended!) then disable allow_listen_all=false
in config.js
, this is the default.
Limitations
- The test servers should not be used in production due to lack of security/ddos protection. Likely canditates for a future version are the NanoRPCProxy.
Any donation contributions are welcome: nano_15qry5fsh4mjbsgsqj148o8378cx5ext4dpnh5ex99gfck686nxkiuk9uouy