-
Notifications
You must be signed in to change notification settings - Fork 1
Local blockchain development
If you want to start working with Unity on a blockchain the minimum requirement is that you can access a blockchain. The following possibilities exist.
- Target a hosted Blockchain, through a (secure) web socket
- Target a local Blockchain, through a HTTP-connection
In the next step, you will create the individual SDK to access your local blockchain.
To create your Extension library, which builds upon the Substrate .NET API, you will need to have your local blockchain up and running, you can follow either the Toolchain readme
dotnet new install Substrate.DotNet.Template
Create a directory called Substrate.MyNode.NET (mkdir Substrate.MyNode.NET) then change into this directory (cd Substrate.MyNode.NET) and execute the commands. (Make sure to change to the version of the template you previously installed) For not local blockchain make sure to replace ws://127.0.0.1:9944 with the secure web socket node URL.
dotnet new sln
dotnet new substrate \
--sdk_version 0.4.8 \
--rest_service Substrate.MyNode.NET.RestService \
--net_api Substrate.MyNode.NET.NetApiExt \
--rest_client Substrate.MyNode.NET.RestClient \
--metadata_websocket ws://127.0.0.1:9944 \
--generate_openapi_documentation false \
--force \
--allow-scripts yes
As a result of the generation you will have now a c# solution including your extension, and additional services like a REST-Services and a REST-Client, the DLLs are builder as part of the toolchain execution and can be found under the following directory ..\Substrate.MyNode.NET\Substrate.MyNode.NET.NetApiExt\bin\Release you can choose between NET6.0, NETStandard2.0, and NETStandard2.1, we suggest you always choose the highest NETStandard that you Unity version is using. Please verify this on the Unity page .NET profile support.
Copy the Substrate.MyNode.NET.NetApiExt.dll
into the Unity Asset/Plugins folder and you are ready to go!
using Substrate.MyNode.NET.NetApiExt.Generated;
using Substrate.NetApi.Model.Extrinsics;
using System;
using System.Threading.Tasks;
namespace MyNode
{
internal class Program
{
static async Task Main(string[] args)
{
var client = new SubstrateClientExt(new Uri("ws://127.0.0.1:9944"), ChargeTransactionPayment.Default());
await client.ConnectAsync();
Console.WriteLine($"Client is connected? {client.IsConnected}");
await client.CloseAsync();
}
}
}
using Schnorrkel.Keys;
using Serilog;
using StreamJsonRpc;
using Substrate.MyNode.NET.NetApiExt.Generated;
using Substrate.MyNode.NET.NetApiExt.Generated.Model.sp_core.crypto;
using Substrate.MyNode.NET.NetApiExt.Generated.Model.sp_runtime.multiaddress;
using Substrate.MyNode.NET.NetApiExt.Generated.Storage;
using Substrate.NetApi;
using Substrate.NetApi.Model.Extrinsics;
using Substrate.NetApi.Model.Rpc;
using Substrate.NetApi.Model.Types;
using Substrate.NetApi.Model.Types.Base;
using Substrate.NetApi.Model.Types.Primitive;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MyNode
{
internal class Program
{
public static MiniSecret MiniSecretAlice => new MiniSecret(Utils.HexToByteArray("0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a"), ExpandMode.Ed25519);
public static Account Alice => Account.Build(KeyType.Sr25519, MiniSecretAlice.ExpandToSecret().ToBytes(), MiniSecretAlice.GetPair().Public.Key);
static async Task Main(string[] args)
{
var yourAccount = Alice; // local blockchain use alice account
var client = new SubstrateClientExt(new Uri("ws://127.0.0.1:9944"), ChargeTransactionPayment.Default());
// connect to substrate node
await client.ConnectAsync();
// leave if we can't connect
if (!client.IsConnected)
{
Console.WriteLine($"Couldn't connect to local host.");
return;
}
// ... do something with the client
// direct rpc call module chain
var blockHash = await client.Chain.GetBlockHashAsync();
// direct rpc call module system
var name = await client.System.NameAsync();
// extension storage rpc call
var blocknumber = await client.SystemStorage.Number(CancellationToken.None);
// extension extrinsic rpc call
EnumMultiAddress address = new EnumMultiAddress();
var account = new AccountId32();
account.Create(Utils.GetPublicKeyFrom("5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"));
address.Create(MultiAddress.Id, account);
var amount = new BaseCom<U128>(1000000000000);
var extrinsicMethod = BalancesCalls.TransferKeepAlive(address, amount);
string subscription = null;
try
{
subscription = await client.Author.SubmitAndWatchExtrinsicAsync(ActionExtrinsicUpdate, extrinsicMethod, yourAccount, ChargeTransactionPayment.Default(), 64, CancellationToken.None);
Console.WriteLine($"BalancesCalls.TransferKeepAlive: {subscription}");
}
catch (RemoteInvocationException e)
{
Log.Error("RemoteInvocationException: {0}", e.Message);
}
// disconnect from substrate node
await client.CloseAsync();
}
private static void ActionExtrinsicUpdate(string subscription, ExtrinsicStatus status)
{
// call back for extrinsic update
}
}
}