Skip to content

Repository files navigation

Unity3d Sample Template Net472 / Netstandard

Sample template to get started working with Unity3d development using Nethereum, from smart contracts, code generation to Unity integration. Unity Version used is 2022.3.21

Template structure and projects

Sample.Unity

The main unity example project including the following code examples:

  • Output to the log the current BlockNumber using Unity.UI both in Async and coroutines
  • Ether transfer using Unity.UI and coroutines
  • Using 1559 Suggestion strategies or Legacy mode when tranfering Ether
  • Smart contract deployment (ERC20), Transactions (Transfer) and Querying (Balance)
  • Cross Platform architecture for both Coroutines and Task to enable the reuse of your code using different deployments Native /Desktop or Browser using Metamask)
  • Using a Nethereum contract integration project (Sample.DotNet)
  • Metamask connectivity in browser

The example includes the reference to the openupm com.nethereum.unity package which includes the Nethereum main dlls for .net472 and netstandard https://github.com/Nethereum/Nethereum.Unity. Check the package for installation information, or the Package configuration (Manifest.json) section in this document.

Sample.DotNet This folder is the "generic" standalone .net integration project and tests.

Sample.DotNet.Contracts

This is the standard Nethereum integration project, but adapted to work with Unity, including both an .asmdef and package.json files.

The csproj has been modified to output the bin and obj files to a build folder so it can be referenced by the Sample.Unity project.

 <BaseOutputPath>..\Build\$(MSBuildProjectName)\bin</BaseOutputPath>
<BaseIntermediateOutputPath>..\Build\$(MSBuildProjectName)\obj</BaseIntermediateOutputPath>

Sample.DotNet.Tests

This the standard test project supported by Nethereum.XUnitEthereumClients and a testchain included in the testchain folder (using geth by default and included)

Sample.Solidity.Contracts

This includes the ERC2O smart contract that is used in the examples.

Important Notes:

  • All the examples are self contained, to simplify them, so when working with the browser you will need "Connect" per example.
  • WebGL: When using Web3 with Tasks this requires something like the WebGLThreadingPatcher https://github.com/VolodymyrBS/WebGLThreadingPatcher, or any other way to enable wasm with Task threading support. Note if you are using Unity V6 you will require to use https://github.com/Nethereum/WebGLThreadingPatcher that includes a fix, not yet available on the main repository.
  • To support AOT and WebGL this sample uses the Nethereum dlls packaged for Net472AOT or NetstandardAOT with the custom Newtonsoft Json.Net by Unity (already added as a package reference)
  • Please remember to remove System.HttpClient and UnityEngine of the Nethereum release package if using the nethereum dlls directly
  • Nethereum.Unity.Metamask is only supported in WebGL at the moment, the Metamask SDK will be supported shortly, currently work in progresss (if you require access to small PoC let me know) image
  • If creating a custom index.html file, or rebuilding webgl in a new folder, the script needs to instantiate nethereumUnityInstance as per the example here: https://github.com/Nethereum/Unity3dSampleTemplate/Sample.Unity/blob/master/webgl/index.html#L107
  • When building to Desktop and other platforms (not web), you will requited to use "https" instead of "http" as the newer versions of Unity validate this.

Desktop demo

Desktop

Browser demo

WebglWebglEIP

Test Chain

To run a local blockchain you can just use the preconfigured chain includes in Sample.DotNet/testchain. All the examples use the chainId "31337" as default.

Package configuration (Manifest.json)

Here is the example of the packages in manifest.json included in the Sample.Unity/packages folder

{
"scopedRegistries": [
{
"name": "package.openupm.com",
"url": "https://package.openupm.com",
"scopes": [
"com.nethereum.unity"
]
}
],
"dependencies": {
"com.nethereum.unity": "4.19.2",
"com.tools.webglthreadingpatcher": "file:../../WebGLThreadingPatcher",
"com.contracts.dotnet.sample": "file:../../Sample.DotNet/Sample.DotNet.Contracts",
"com.unity.nuget.newtonsoft-json": "3.2.1",
...
  • Scoped registries that uses openupm to include "com.nethereum.unity".
  • Webglthreadingpatcher has been downloaded from its github repository and added as folder dependency.
  • Sample dotnet integration project: "com.contracts.dotnet.sample": "file:../../Sample.DotNet/Sample.DotNet.Contracts"
  • Newtonsoft json: "com.unity.nuget.newtonsoft-json": "3.2.1"

Code examples

BlockNumber query Async (vanilla Nethereum)

usingSystem;usingSystem.Net.Security;usingSystem.Security.Cryptography.X509Certificates;usingUnityEngine;usingUnityEngine.UI;usingNethereum.Web3;usingSystem.Threading.Tasks;usingNethereum.Unity.Rpc;publicclassGetLatestBlockVanillaNethereum:MonoBehaviour{privatestaticboolTrustCertificate(objectsender,X509Certificatex509Certificate,X509Chainx509Chain,SslPolicyErrorssslPolicyErrors){// all certificates are acceptedreturntrue;}publicstringUrl="http://localhost:8545";publicInputFieldResultBlockNumber;publicInputFieldResultBlockNumberConstant;publicInputFieldInputUrl;// Use this for initializationasyncvoidStart(){InputUrl.text=Url;awaitCheckBlockNumberPeriodically();}publicasyncTaskCheckBlockNumberPeriodically(){varwait=1000;while(true){awaitTask.Delay(wait);wait=1000;varweb3=newWeb3(newUnityWebRequestRpcTaskClient(newUri(InputUrl.text)));varblockNumber=awaitweb3.Eth.Blocks.GetBlockNumber.SendRequestAsync();ResultBlockNumberConstant.text=blockNumber.Value.ToString();}}publicasyncvoidGetBlockNumber(){Url=InputUrl.text;//This is to workaround issue with certificates https://forum.unity.com/threads/how-to-allow-self-signed-certificate.522183///Uncomment if needed//ServicePointManager.ServerCertificateValidationCallback = TrustCertificate;varweb3=newWeb3(newUnityWebRequestRpcTaskClient(newUri(InputUrl.text)));varblockNumber=awaitweb3.Eth.Blocks.GetBlockNumber.SendRequestAsync();ResultBlockNumber.text=blockNumber.Value.ToString();}}

BlockNumber query Coroutines

usingSystem.Collections;usingUnityEngine;usingUnityEngine.UI;usingNethereum.Unity.Rpc;publicclassGetLatestBlockCoroutine:MonoBehaviour{publicstringUrl="http://localhost:8545";publicInputFieldResultBlockNumber;publicInputFieldInputUrl;// Use this for initializationvoidStart(){InputUrl.text=Url;}publicvoidGetBlockNumberRequest(){Url=InputUrl.text;StartCoroutine(GetBlockNumber());}publicIEnumeratorGetBlockNumber(){varblockNumberRequest=newEthBlockNumberUnityRequest(InputUrl.text);yieldreturnblockNumberRequest.SendRequest();if(blockNumberRequest.Exception!=null){UnityEngine.Debug.Log(blockNumberRequest.Exception.Message);}else{ResultBlockNumber.text=blockNumberRequest.Result.Value.ToString();}}}

Simple Ether transfer using Coroutines

To transfer Ether Nethereum provides a specific Unity Request, the EthTransferUnityRequest.

The EthTransferUnityRequest it is instantiated with the "url" of our Ethereum client, the private key to be able to sign transactions and our account address (the same of the private key).

varurl="http://localhost:8545";varprivateKey="0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7";varethTransfer=newEthTransferUnityRequest(url,privateKey,"YOURCHAINID");

Once our unity request is instantiated it we can initiate the transfer as follows using Legacy Mode providing 2 Gwei as the gas price

varreceivingAddress="0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe";yieldreturnethTransfer.TransferEther(receivingAddress,1.1m,2);

Here we have specified the receivingAddress, the amount to send and the optional gas price in Gwei. The request will automatically convert the gas price to Wei.

We can validate afterwards if we have had any exception as following:

if (ethTransfer.Exception != null)
{
Debug.Log(ethTransfer.Exception.Message);
yield break;
}

If no errors have occurred we can retrieve the transaction hash from the Request and Poll every 2 seconds to wait for the transaction to be mined.

vartransactionHash=ethTransfer.Result;//create a poll to get the receipt when minedvartransactionReceiptPolling=newTransactionReceiptPollingRequest(url);//checking every 2 seconds for the receiptyieldreturntransactionReceiptPolling.PollForReceipt(transactionHash,2);

Finally we can check the balance of our recieving account, using EthGetBalanceUnityRequest. Note that we specify we want the balance for the latest Block when doing the request.

varbalanceRequest=newEthGetBalanceUnityRequest(url);yieldreturnbalanceRequest.SendRequest(receivingAddress,BlockParameter.CreateLatest());

We can convert the result in Wei to Eth using the default Wei UnitConvertor.

Debug.Log("Balance of account:"+UnitConversion.Convert.FromWei(balanceRequest.Result.Value));

Transfer using Task / Web3

To transfer Ether using Web3 and Tasks we can use the same example as the Netherum playground http://playground.nethereum.com/csharp/id/1003

varprivateKey="0x7580e7fb49df1c861f0050fae31c2224c6aba908e116b8da44ee8cd927b990b0";varchainId=444444444500;//Nethereum test chain, chainIdvaraccount=newAccount(privateKey,chainId);//Now let's create an instance of Web3 using our account pointing to our nethereum testchainvarweb3=newWeb3(account,"http://testchain.nethereum.com:8545");web3.TransactionManager.UseLegacyAsDefault=true;//Using legacy option instead of 1559// Lets transfer 1.11 Ethervartransaction=awaitweb3.Eth.GetEtherTransferService().TransferEtherAndWaitForReceiptAsync("0x13f022d72158410433cbd66f5dd8bf6d2d129924",1.11m);

EIP 1559 Fee suggestion using the strategies provided and Legacy Mode Coroutines

Here are some examples of using the provided fee suggestion strategies using coroutines, TimePreference, MedianFeeHistory or LegacyMode to use the old mode or to use with other chains.

To use LegacyMode you have to provide the GasPrice or it can be force the LegacyMode by setting UseLegacyAsDefault to true.

if(feeStrategy==FeeStrategy.TimePreference){Debug.Log("Time Preference");vartimePreferenceFeeSuggestion=newTimePreferenceFeeSuggestionUnityRequestStrategy(Url);yieldreturntimePreferenceFeeSuggestion.SuggestFees();if(timePreferenceFeeSuggestion.Exception!=null){Debug.Log(timePreferenceFeeSuggestion.Exception.Message);yieldbreak;}//lets get the first one so it is higher priorityDebug.Log(timePreferenceFeeSuggestion.Result.Length);if(timePreferenceFeeSuggestion.Result.Length>0){Debug.Log(timePreferenceFeeSuggestion.Result[0].MaxFeePerGas);Debug.Log(timePreferenceFeeSuggestion.Result[0].MaxPriorityFeePerGas);}varfee=timePreferenceFeeSuggestion.Result[0];yieldreturnethTransfer.TransferEther(receivingAddress,Amount,fee.MaxPriorityFeePerGas.Value,fee.MaxFeePerGas.Value);if(ethTransfer.Exception!=null){Debug.Log(ethTransfer.Exception.Message);yieldbreak;}}if(feeStrategy==FeeStrategy.MedianFeeHistory){Debug.Log("MedianFeeHistory mode");varmedianPriorityFeeStrategy=newMedianPriorityFeeHistorySuggestionUnityRequestStrategy(Url);yieldreturnmedianPriorityFeeStrategy.SuggestFee();if(medianPriorityFeeStrategy.Exception!=null){Debug.Log(medianPriorityFeeStrategy.Exception.Message);yieldbreak;}Debug.Log(medianPriorityFeeStrategy.Result.MaxFeePerGas);Debug.Log(medianPriorityFeeStrategy.Result.MaxPriorityFeePerGas);varfee=medianPriorityFeeStrategy.Result;yieldreturnethTransfer.TransferEther(receivingAddress,Amount,fee.MaxPriorityFeePerGas.Value,fee.MaxFeePerGas.Value);if(ethTransfer.Exception!=null){Debug.Log(ethTransfer.Exception.Message);yieldbreak;}}if(feeStrategy==FeeStrategy.Legacy){Debug.Log("Legacy mode");//I am forcing the legacy mode but also I am including the gas priceethTransfer.UseLegacyAsDefault=true;yieldreturnethTransfer.TransferEther(receivingAddress,Amount,GasPriceGwei);if(ethTransfer.Exception!=null){Debug.Log(ethTransfer.Exception.Message);yieldbreak;}}

#EIP 1559 using Web3 / Tasks

This will be the same as the example of the Nethereum playground http://playground.nethereum.com/csharp/id/1076

Smart contract Integration

This sample covers all the steps of smart contract integration using the ERC20 standard token.

Declare our smart contract definition

First step is to include our smart contract definition, this can be code generated using the vscode solidity extension or the console code generation tool. This will be reused for both Web3 / Tasks and Coroutines

usingNethereum.ABI.FunctionEncoding.Attributes;usingNethereum.ABI.Model;usingNethereum.Contracts;usingSystem.Numerics;//NOTE: All Contract definitions can be code generated using the vscode solidity extension, using the .net libraries or directly in the playground using the abi produced by the solidity compiler///// //********* CONTRACT DEFINITION *******//*** Deployment message**** //// To deploy a contract we will create a class inheriting from the ContractDeploymentMessage, // here we can include our compiled byte code and other constructor parameters.// As we can see below the StandardToken deployment message includes the compiled bytecode // of the ERC20 smart contract and the constructor parameter with the “totalSupply” of tokens.// Each parameter is described with an attribute Parameter, including its name "totalSupply", type "uint256" and order.publicclassStandardTokenDeployment:ContractDeploymentMessage{publicstaticstringBYTECODE="0x60606040526040516020806106f5833981016040528080519060200190919050505b80600160005060003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005081905550806000600050819055505b506106868061006f6000396000f360606040523615610074576000357c010000000000000000000000000000000000000000000000000000000090048063095ea7b31461008157806318160ddd146100b657806323b872dd146100d957806370a0823114610117578063a9059cbb14610143578063dd62ed3e1461017857610074565b61007f5b610002565b565b005b6100a060048080359060200190919080359060200190919050506101ad565b6040518082815260200191505060405180910390f35b6100c36004805050610674565b6040518082815260200191505060405180910390f35b6101016004808035906020019091908035906020019091908035906020019091905050610281565b6040518082815260200191505060405180910390f35b61012d600480803590602001909190505061048d565b6040518082815260200191505060405180910390f35b61016260048080359060200190919080359060200190919050506104cb565b6040518082815260200191505060405180910390f35b610197600480803590602001909190803590602001909190505061060b565b6040518082815260200191505060405180910390f35b600081600260005060003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005060008573ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905061027b565b92915050565b600081600160005060008673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050541015801561031b575081600260005060008673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005060003373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000505410155b80156103275750600082115b1561047c5781600160005060008573ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828282505401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a381600160005060008673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282825054039250508190555081600260005060008673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005060003373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828282505403925050819055506001905061048656610485565b60009050610486565b5b9392505050565b6000600160005060008373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000505490506104c6565b919050565b600081600160005060003373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050541015801561050c5750600082115b156105fb5781600160005060003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282825054039250508190555081600160005060008573ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828282505401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905061060556610604565b60009050610605565b5b92915050565b6000600260005060008473ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005060008373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005054905061066e565b92915050565b60006000600050549050610683565b9056";publicStandardTokenDeployment():base(BYTECODE){}[Parameter("uint256","totalSupply")]publicBigIntegerTotalSupply{get;set;}}//*** FUNCTION MESSAGES **** ///// We can call the functions of smart contract to query the state of a smart contract or do any computation, // which will not affect the state of the blockchain.// To do so, we will need to create a class which inherits from "FunctionMessage". // First we will decorate the class with a "Function" attribute, including the name and return type.// Each parameter of the function will be a property of the class, each of them decorated with the "Parameter" attribute, // including the smart contract’s parameter name, type and parameter order.// For the ERC20 smart contract, the "balanceOf" function definition, // provides the query interface to get the token balance of a given address. // As we can see this function includes only one parameter "\_owner", of the type "address".[Function("balanceOf","uint256")]publicclassBalanceOfFunction:FunctionMessage{[Parameter("address","_owner",1)]publicstringOwner{get;set;}}// Another type of smart contract function will be a transaction // that will change the state of the smart contract (or smart contracts).// For example The "transfer" function definition for the ERC20 smart contract, // includes the parameters “\_to”, which is an address parameter as a string, and the “\_value” // or TokenAmount we want to transfer.// In a similar way to the "balanceOf" function, all the parameters include the solidity type, // the contract’s parameter name and parameter order.// Note: When working with functions, it is very important to have the parameters types and function name correct //as all of these make the signature of the function.[Function("transfer","bool")]publicclassTransferFunction:FunctionMessage{[Parameter("address","_to",1)]publicstringTo{get;set;}[Parameter("uint256","_value",2)]publicBigIntegerTokenAmount{get;set;}}// Finally, smart contracts also have events. Events defined in smart contracts write in the blockchain log, // providing a way to retrieve further information when a smart contract interaction occurs.// To create an Event definition, we need to create a class that inherits from IEventDTO, decorated with the Event attribute.// The Transfer Event is similar to a Function: it also includes parameters with name, order and type. // But also a boolean value indicating if the parameter is indexed or not.// Indexed parameters will allow us later on to query the blockchain for those values.[Event("Transfer")]publicclassTransferEventDTO:IEventDTO{[Parameter("address","_from",1,true)]publicstringFrom{get;set;}[Parameter("address","_to",2,true)]publicstringTo{get;set;}[Parameter("uint256","_value",3,false)]publicBigIntegerValue{get;set;}publicstaticEventABIGetEventABI(){returnEventExtensions.GetEventABI<TransferEventDTO>();}}// ### Multiple return types or complex objects// Functions of smart contracts can return one or multiple values in a single call. To decode the returned values, we use a FunctionOutputDTO.// Function outputs are classes which are decorated with a FunctionOutput attribute and implement the interface IFunctionOutputDTO.// An example of this is the following implementation that can be used to return the single value of the Balance on the ERC20 smart contract.[FunctionOutput]publicclassBalanceOfOutputDTO:IFunctionOutputDTO{[Parameter("uint256","balance",1)]publicBigIntegerBalance{get;set;}}

Erc20 Coroutines

Targetting multiple platforms Desktop / Native / Browser using Coroutines

Before we start interacting with the smart contract is best to describe how we are going to create our connection to interact with the client and signed transactions.

Using the IUnityRpcRequestClientFactory and the IContractTransactionUnityRequest you can change the way your transactions are signed reusing all your code.

In this example we are either signing or querying the chain using our provided url / private key / chainId when we are in a desktop / mobile / console environment or if we are in a browser we use Metamask to sign our transactions.

publicIUnityRpcRequestClientFactoryGetUnityRpcRequestClientFactory(){
#if UNITY_WEBGLif(IsWebGL()){if(MetamaskWebglInterop.IsMetamaskAvailable()){returnnewMetamaskWebglCoroutineRequestRpcClientFactory(_selectedAccountAddress,null,60000);}else{// DisplayError("Metamask is not available, please install it");returnnull;}}else{
#endif
Url=InputUrl.text;returnnewUnityWebRequestRpcClientFactory(Url);
#if UNITY_WEBGL}
#endif
}publicIContractTransactionUnityRequestGetTransactionUnityRequest(){
#if UNITY_WEBGLif(IsWebGL()){if(MetamaskWebglInterop.IsMetamaskAvailable()){returnnewMetamaskTransactionCoroutineUnityRequest(_selectedAccountAddress,GetUnityRpcRequestClientFactory());}else{DisplayError("Metamask is not available, please install it");returnnull;}}else{
#endif
Url=InputUrl.text;PrivateKey=InputPrivateKey.text;ChainId=BigInteger.Parse(InputChainId.text);varaccount=newNethereum.Web3.Accounts.Account(InputPrivateKey.text);NewAccountSelected(account.Address);returnnewTransactionSignedUnityRequest(Url,PrivateKey,ChainId);
#if UNITY_WEBGL}
#endif
}

Contract deployment using Coroutines

To deploy a smart contract we create a IContractTransactionUnityRequest using the way highlighted in "Targetting multiple platforms Desktop / Native / Browser using Coroutines" Creating a new StandardTokenDeployment contract definition we set the constructor parameters and send the transaction. Finally we we create TransactionReceiptPollingRequest to poll for the transaction receipt and retrieve the newly deployed contract address from the transaction receipt.

vartransactionRequest=GetTransactionUnityRequest();transactionRequest.UseLegacyAsDefault=true;vardeployContract=newStandardTokenDeployment(){TotalSupply=Nethereum.Web3.Web3.Convert.ToWei(10000000),FromAddress=_selectedAccountAddress};//deploy the contract and True indicates we want to estimate the gasyieldreturntransactionRequest.SignAndSendDeploymentContractTransaction(deployContract);if(transactionRequest.Exception!=null){Debug.Log(transactionRequest.Exception.Message);DisplayError(transactionRequest.Exception.Message);yieldbreak;}vartransactionHash=transactionRequest.Result;Debug.Log("Deployment transaction hash:"+transactionHash);//create a poll to get the receipt when minedvartransactionReceiptPolling=newTransactionReceiptPollingRequest(GetUnityRpcRequestClientFactory());//checking every 2 seconds for the receiptyieldreturntransactionReceiptPolling.PollForReceipt(transactionHash,2);vardeploymentReceipt=transactionReceiptPolling.Result;ResultContractAddress.text=deploymentReceipt.ContractAddress;

Query smart contract Coroutines

To Query a smart contract we need to create a new QueryUnityRequest providing the FunctionType and ReturnType. We then will yield the Query and the query result Result object will provide us the Ouput of the contract already decoded.

//Query request using our acccount and the contracts address (no parameters needed and default values)varqueryRequest=newQueryUnityRequest<BalanceOfFunction,BalanceOfOutputDTO>(GetUnityRpcRequestClientFactory(),_selectedAccountAddress);yieldreturnqueryRequest.Query(newBalanceOfFunction(){Owner=AddressTo},contractAddress);//Getting the dto response already decodedvardtoResult=queryRequest.Result;Debug.Log(dtoResult.Balance);

Transfer transaction Coroutines

To send a transaction to interact with a smart contract has similar steps to the deployment. We first create a TransactionSignedUnityRequest and our Function including any parameters, once the transaction is send we poll for the transaction receipt which will confirm the success of the transaction.

Using the transaction receipt we can decoded any logs / events for that transaction.

vartransactionRequest=GetTransactionUnityRequest();transactionRequest.UseLegacyAsDefault=true;// use legacy herevartransferFunction=newTransferFunction{To=AddressTo,TokenAmount=Nethereum.Web3.Web3.Convert.ToWei(Amount),FromAddress=_selectedAccountAddress};yieldreturntransactionRequest.SignAndSendTransaction(transferFunction,contractAddress);if(transactionRequest.Exception!=null){Debug.Log(transactionRequest.Exception.Message);DisplayError(transactionRequest.Exception.Message);yieldbreak;}vartransactionTransferHash=transactionRequest.Result;ResultTxnHash.text=transactionTransferHash;Debug.Log("Transfer transaction hash:"+transactionTransferHash);vartransactionReceiptPolling=newTransactionReceiptPollingRequest(GetUnityRpcRequestClientFactory());yieldreturntransactionReceiptPolling.PollForReceipt(transactionTransferHash,2);vartransferReceipt=transactionReceiptPolling.Result;vartransferEvent=transferReceipt.DecodeAllEvents<TransferEventDTO>();Debug.Log("Transferred amount from event: "+transferEvent[0].Event.Value);

Logs and Events Coroutines

To retrived the logs / events of a smart contract we use the EthGetLogsUnityRequest combined with a FilterInput specific to our Event. FilterInputs can be created using the EventDTO extension GetEventABI(). Once we have yield the request, we can decode all matching events using the Result.DecodeAllEvents, extension method.

vargetLogsRequest=newEthGetLogsUnityRequest(GetUnityRpcRequestClientFactory());vareventTransfer=TransferEventDTO.GetEventABI();yieldreturngetLogsRequest.SendRequest(eventTransfer.CreateFilterInput(contractAddress,_selectedAccountAddress));vareventDecoded=getLogsRequest.Result.DecodeAllEvents<TransferEventDTO>();Debug.Log("Transferred amount from get logs event: "+eventDecoded[0].Event.Value);

Full sample ERC20 Corutines

usingNethereum.Contracts;usingNethereum.Hex.HexTypes;usingNethereum.Unity.Contracts;
#if UNITY_WEBGLusingNethereum.Unity.Metamask;
#endif
usingNethereum.Unity.Rpc;usingNethereum.Util;usingSystem.Collections;usingSystem.Numerics;usingUnityEngine;usingUnityEngine.UI;usingDebug=UnityEngine.Debug;publicclassMultiplatformErc20Coroutine:MonoBehaviour{publicstringUrl="http://localhost:8545";publicBigIntegerChainId=444444444500;publicstringPrivateKey="0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7";publicstringAddressTo="0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe";privatestring_selectedAccountAddress;privatebool_isMetamaskInitialised=false;publicdecimalAmount=1.1m;publicInputFieldInputUrl;publicInputFieldInputChainId;publicInputFieldInputPrivateKey;publicInputFieldInputAddressTo;publicInputFieldInputAmount;publicInputFieldResultBalanceAddressTo;publicInputFieldResultTxnHash;publicInputFieldResultContractAddress;publicButtonBtnMetamaskConnect;publicTextLblError;voidStart(){if(IsWebGL())// using pk etc only on desktop as an example{InputUrl.enabled=false;InputPrivateKey.enabled=false;InputChainId.enabled=false;}else{InputUrl.text=Url;InputPrivateKey.text=PrivateKey;InputChainId.text=ChainId.ToString();BtnMetamaskConnect.enabled=false;}InputAddressTo.text=AddressTo;InputAmount.text=Amount.ToString();}publicboolIsWebGL(){
#if UNITY_WEBGLreturntrue;
#else
returnfalse;
#endif
}publicasyncvoidDeployRequest(){StartCoroutine(DeployERC20UsingCoroutines());}publicIEnumeratorDeployERC20UsingCoroutines(){vartransactionRequest=GetTransactionUnityRequest();transactionRequest.UseLegacyAsDefault=true;vardeployContract=newStandardTokenDeployment(){TotalSupply=Nethereum.Web3.Web3.Convert.ToWei(10000000),FromAddress=_selectedAccountAddress};//deploy the contract and True indicates we want to estimate the gasyieldreturntransactionRequest.SignAndSendDeploymentContractTransaction(deployContract);if(transactionRequest.Exception!=null){Debug.Log(transactionRequest.Exception.Message);DisplayError(transactionRequest.Exception.Message);yieldbreak;}vartransactionHash=transactionRequest.Result;Debug.Log("Deployment transaction hash:"+transactionHash);//create a poll to get the receipt when minedvartransactionReceiptPolling=newTransactionReceiptPollingRequest(GetUnityRpcRequestClientFactory());//checking every 2 seconds for the receiptyieldreturntransactionReceiptPolling.PollForReceipt(transactionHash,2);vardeploymentReceipt=transactionReceiptPolling.Result;ResultContractAddress.text=deploymentReceipt.ContractAddress;}publicasyncvoidTransferRequest(){StartCoroutine(TransferErc20AndGetBalance());}publicIEnumeratorTransferErc20AndGetBalance(){AddressTo=InputAddressTo.text;Amount=System.Decimal.Parse(InputAmount.text);varcontractAddress=ResultContractAddress.text;//initialising the transaction request sendervartransactionRequest=GetTransactionUnityRequest();transactionRequest.UseLegacyAsDefault=true;vartransferFunction=newTransferFunction{To=AddressTo,TokenAmount=Nethereum.Web3.Web3.Convert.ToWei(Amount),FromAddress=_selectedAccountAddress};yieldreturntransactionRequest.SignAndSendTransaction(transferFunction,contractAddress);if(transactionRequest.Exception!=null){Debug.Log(transactionRequest.Exception.Message);DisplayError(transactionRequest.Exception.Message);yieldbreak;}vartransactionTransferHash=transactionRequest.Result;ResultTxnHash.text=transactionTransferHash;Debug.Log("Transfer transaction hash:"+transactionTransferHash);vartransactionReceiptPolling=newTransactionReceiptPollingRequest(GetUnityRpcRequestClientFactory());yieldreturntransactionReceiptPolling.PollForReceipt(transactionTransferHash,2);vartransferReceipt=transactionReceiptPolling.Result;vartransferEvent=transferReceipt.DecodeAllEvents<TransferEventDTO>();Debug.Log("Transferred amount from event: "+transferEvent[0].Event.Value);vargetLogsRequest=newEthGetLogsUnityRequest(GetUnityRpcRequestClientFactory());vareventTransfer=TransferEventDTO.GetEventABI();yieldreturngetLogsRequest.SendRequest(eventTransfer.CreateFilterInput(contractAddress,_selectedAccountAddress));vareventDecoded=getLogsRequest.Result.DecodeAllEvents<TransferEventDTO>();Debug.Log("Transferred amount from get logs event: "+eventDecoded[0].Event.Value);varqueryRequest=newQueryUnityRequest<BalanceOfFunction,BalanceOfOutputDTO>(GetUnityRpcRequestClientFactory(),_selectedAccountAddress);yieldreturnqueryRequest.Query(newBalanceOfFunction(){Owner=AddressTo},contractAddress);//Getting the dto response already decodedvardtoResult=queryRequest.Result;Debug.Log(dtoResult.Balance);varbalanceReceiver=UnitConversion.Convert.FromWei(dtoResult.Balance);ResultBalanceAddressTo.text=balanceReceiver.ToString();Debug.Log("Balance of account:"+balanceReceiver);}publicvoidDisplayError(stringerrorMessage){LblError.text=errorMessage;}publicvoidMetamaskConnect(){
#if UNITY_WEBGLif(IsWebGL()){if(MetamaskWebglInterop.IsMetamaskAvailable()){MetamaskWebglInterop.EnableEthereum(gameObject.name,nameof(EthereumEnabled),nameof(DisplayError));}else{DisplayError("Metamask is not available, please install it");}}
#endif
}publicvoidEthereumEnabled(stringaddressSelected){
#if UNITY_WEBGLif(IsWebGL()){if(!_isMetamaskInitialised){MetamaskWebglInterop.EthereumInit(gameObject.name,nameof(NewAccountSelected),nameof(ChainChanged));MetamaskWebglInterop.GetChainId(gameObject.name,nameof(ChainChanged),nameof(DisplayError));_isMetamaskInitialised=true;}NewAccountSelected(addressSelected);}
#endif
}publicvoidChainChanged(stringchainId){print(chainId);ChainId=newHexBigInteger(chainId).Value;InputChainId.text=ChainId.ToString();}publicvoidNewAccountSelected(stringaccountAddress){_selectedAccountAddress=accountAddress;}publicIUnityRpcRequestClientFactoryGetUnityRpcRequestClientFactory(){
#if UNITY_WEBGLif(IsWebGL()){if(MetamaskWebglInterop.IsMetamaskAvailable()){returnnewMetamaskWebglCoroutineRequestRpcClientFactory(_selectedAccountAddress,null,60000);}else{// DisplayError("Metamask is not available, please install it");returnnull;}}else{
#endif
Url=InputUrl.text;returnnewUnityWebRequestRpcClientFactory(Url);
#if UNITY_WEBGL}
#endif
}publicIContractTransactionUnityRequestGetTransactionUnityRequest(){
#if UNITY_WEBGLif(IsWebGL()){if(MetamaskWebglInterop.IsMetamaskAvailable()){returnnewMetamaskTransactionCoroutineUnityRequest(_selectedAccountAddress,GetUnityRpcRequestClientFactory());}else{DisplayError("Metamask is not available, please install it");returnnull;}}else{
#endif
Url=InputUrl.text;PrivateKey=InputPrivateKey.text;ChainId=BigInteger.Parse(InputChainId.text);varaccount=newNethereum.Web3.Accounts.Account(InputPrivateKey.text);NewAccountSelected(account.Address);returnnewTransactionSignedUnityRequest(Url,PrivateKey,ChainId);
#if UNITY_WEBGL}
#endif
}

Full Sample ERC20 Unity Coroutines

usingSystem.Collections;usingUnityEngine;usingUnityEngine.UI;usingNethereum.Unity.Rpc;usingNethereum.RPC.Eth.DTOs;usingNethereum.Util;usingDebug=UnityEngine.Debug;
#if UNITY_WEBGLusingNethereum.Unity.Metamask;
#endif
usingNethereum.Unity.FeeSuggestions;usingNethereum.Unity.Contracts;usingSystem.Numerics;usingNethereum.Hex.HexTypes;publicclassMultiplatformTransfer:MonoBehaviour{publicstringUrl="http://localhost:8545";publicBigIntegerChainId=444444444500;publicstringPrivateKey="0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7";publicstringAddressTo="0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe";privatestring_selectedAccountAddress;privatebool_isMetamaskInitialised=false;publicdecimalAmount=1.1m;publicstringTransactionHash="";publicdecimalBalanceAddressTo=0m;publicInputFieldInputUrl;publicInputFieldInputChainId;publicInputFieldInputPrivateKey;publicInputFieldInputAddressTo;publicInputFieldInputAmount;publicInputFieldResultBalanceAddressTo;publicInputFieldResultTxnHash;publicButtonBtnMetamaskConnect;publicTextLblError;voidStart(){if(IsWebGL()){InputUrl.enabled=false;InputPrivateKey.enabled=false;InputChainId.enabled=false;}else{InputUrl.text=Url;InputPrivateKey.text=PrivateKey;InputChainId.text=ChainId.ToString();BtnMetamaskConnect.enabled=false;}InputAddressTo.text=AddressTo;InputAmount.text=Amount.ToString();}publicboolIsWebGL(){
#if UNITY_WEBGLreturntrue;
#else
returnfalse;
#endif
}publicvoidTransferRequest(){StartCoroutine(TransferEther());}publicIEnumeratorTransferEther(){AddressTo=InputAddressTo.text;Amount=System.Decimal.Parse(InputAmount.text);//initialising the transaction request sendervarethTransfer=newEthTransferUnityRequest(GetTransactionUnityRequest());varreceivingAddress=AddressTo;vartimePreferenceFeeSuggestion=newTimePreferenceFeeSuggestionUnityRequestStrategy(Url);yieldreturntimePreferenceFeeSuggestion.SuggestFees();if(timePreferenceFeeSuggestion.Exception!=null){Debug.Log(timePreferenceFeeSuggestion.Exception.Message);yieldbreak;}//lets get the first one so it is higher priorityDebug.Log(timePreferenceFeeSuggestion.Result.Length);if(timePreferenceFeeSuggestion.Result.Length>0){Debug.Log(timePreferenceFeeSuggestion.Result[0].MaxFeePerGas);Debug.Log(timePreferenceFeeSuggestion.Result[0].MaxPriorityFeePerGas);}varfee=timePreferenceFeeSuggestion.Result[0];yieldreturnethTransfer.TransferEther(receivingAddress,Amount,fee.MaxPriorityFeePerGas.Value,fee.MaxFeePerGas.Value);if(ethTransfer.Exception!=null){Debug.Log("Error transferring Ether using Time Preference Fee Estimation Strategy: "+ethTransfer.Exception.Message);yieldbreak;}TransactionHash=ethTransfer.Result;ResultTxnHash.text=TransactionHash;Debug.Log("Transfer transaction hash:"+TransactionHash);//create a poll to get the receipt when minedvartransactionReceiptPolling=newTransactionReceiptPollingRequest(Url);//checking every 2 seconds for the receiptyieldreturntransactionReceiptPolling.PollForReceipt(TransactionHash,2);Debug.Log("Transaction mined");varbalanceRequest=newEthGetBalanceUnityRequest(Url);yieldreturnbalanceRequest.SendRequest(receivingAddress,BlockParameter.CreateLatest());BalanceAddressTo=UnitConversion.Convert.FromWei(balanceRequest.Result.Value);ResultBalanceAddressTo.text=BalanceAddressTo.ToString();Debug.Log("Balance of account:"+BalanceAddressTo);}publicvoidDisplayError(stringerrorMessage){LblError.text=errorMessage;}publicvoidMetamaskConnect(){
#if UNITY_WEBGLif(IsWebGL()){if(MetamaskInterop.IsMetamaskAvailable()){MetamaskInterop.EnableEthereum(gameObject.name,nameof(EthereumEnabled),nameof(DisplayError));}else{DisplayError("Metamask is not available, please install it");}}
#endif
}publicvoidEthereumEnabled(stringaddressSelected){
#if UNITY_WEBGLif(IsWebGL()){if(!_isMetamaskInitialised){MetamaskInterop.EthereumInit(gameObject.name,nameof(NewAccountSelected),nameof(ChainChanged));MetamaskInterop.GetChainId(gameObject.name,nameof(ChainChanged),nameof(DisplayError));_isMetamaskInitialised=true;}NewAccountSelected(addressSelected);}
#endif
}publicvoidChainChanged(stringchainId){print(chainId);ChainId=newHexBigInteger(chainId).Value;InputChainId.text=ChainId.ToString();}publicvoidNewAccountSelected(stringaccountAddress){_selectedAccountAddress=accountAddress;}publicIUnityRpcRequestClientFactoryGetUnityRpcRequestClientFactory(){
#if UNITY_WEBGLif(IsWebGL()){if(MetamaskInterop.IsMetamaskAvailable()){returnnewMetamaskRequestRpcClientFactory(_selectedAccountAddress,null,1000);}else{// DisplayError("Metamask is not available, please install it");returnnull;}}else{
#endif
Url=InputUrl.text;returnnewUnityWebRequestRpcClientFactory(Url);
#if UNITY_WEBGL}
#endif
}publicIContractTransactionUnityRequestGetTransactionUnityRequest(){
#if UNITY_WEBGLif(IsWebGL()){if(MetamaskInterop.IsMetamaskAvailable()){returnnewMetamaskTransactionUnityRequest(_selectedAccountAddress,GetUnityRpcRequestClientFactory());}else{DisplayError("Metamask is not available, please install it");returnnull;}}else{
#endif
Url=InputUrl.text;PrivateKey=InputPrivateKey.text;ChainId=BigInteger.Parse(InputChainId.text);returnnewTransactionSignedUnityRequest(Url,PrivateKey,ChainId);
#if UNITY_WEBGL}
#endif
}}

Erc20 Web3 / Tasks

Targetting multiple platforms Desktop / Native / Browser using Web3 / Tasks

To target multiple platforms using Web3 / Tasks we use the same method as in the generic Nethereum, we can use a HostProvider like the MetamaskHostProvider which is instantiated using the MetamaskWebGlFactory or create a Web3 instance using the private key, abstracting this in a method / factory will allow us to add other ways to create a web3 instance or using other HostProviders.

privateasyncTask<IWeb3>GetWeb3Async(){
#if UNITY_WEBGLMetamaskHostProvidermetamaskHost=MetamaskWebglHostProvider.CreateOrGetCurrentInstance();metamaskHost.SelectedAccountChanged+=MetamaskHost_SelectedAccountChanged;awaitmetamaskHost.EnableProviderAsync();_selectedAccountAddress=metamaskHost.SelectedAccount;returnawaitmetamaskHost.GetWeb3Async();
#else
Url=InputUrl.text;PrivateKey=InputPrivateKey.text;ChainId=BigInteger.Parse(InputChainId.text);varaccount=newAccount(PrivateKey,ChainId);_selectedAccountAddress=account.Address;returnnewWeb3(account,Url);
#endif
}

Deployment ERC20 using Web3 / Tasks

Once we have a Web3 instance, deployment is done the same way as in Nethereum, this example shows you how to deploy using DeploymentHandlers, but if you code generated the service to wrap the handlers you can use it the same way. For more information about Deployment / Transactions / Querying smart contracts check the Nethereum playground example http://playground.nethereum.com/csharp/id/1007

varweb3=awaitGetWeb3Async();web3.TransactionManager.UseLegacyAsDefault=true;web3.TransactionReceiptPolling.SetPollingRetryIntervalInMilliseconds(2000);// 2 seconds polling for receiptsvardeployContract=newStandardTokenDeployment(){TotalSupply=Nethereum.Web3.Web3.Convert.ToWei(10000000),FromAddress=_selectedAccountAddress};vardeploymentHandler=web3.Eth.GetContractDeploymentHandler<StandardTokenDeployment>();vartransactionReceiptDeployment=awaitdeploymentHandler.SendRequestAndWaitForReceiptAsync(deployContract);varcontractAddress=transactionReceiptDeployment.ContractAddress;

Erc20 Transfer and Querying and Logs using Web3 / Tasks

This example demonstrates how to make a Erc20 Transfer / Query the balance, decode an Event from the TransactionReceipt log and get the Logs. This uses contract handlers but if you code generated the service to wrap the handlers you can use it the same way. For more information about Deployment / Transactions / Querying smart contracts check the Nethereum playground example http://playground.nethereum.com/csharp/id/1007, and the full introduction on Events and Logs in the Nethereum Playground http://playground.nethereum.com/csharp/id/1008

varweb3=awaitGetWeb3Async();web3.TransactionManager.UseLegacyAsDefault=true;web3.TransactionReceiptPolling.SetPollingRetryIntervalInMilliseconds(2000);// 2 seconds polling for receipts//Note this could use the services generated by the code generator to simplify it further//or web3.Eth.ERC20 presets AddressTo=InputAddressTo.text;Amount=System.Decimal.Parse(InputAmount.text);varcontractAddress=ResultContractAddress.text;vartransferFunction=newTransferFunction{To=AddressTo,TokenAmount=Nethereum.Web3.Web3.Convert.ToWei(Amount),FromAddress=_selectedAccountAddress};vartransferHandler=web3.Eth.GetContractTransactionHandler<TransferFunction>();vartransactionTransferReceipt=awaittransferHandler.SendRequestAndWaitForReceiptAsync(contractAddress,transferFunction);Console.WriteLine("Transaction hash transfer is: "+transactionTransferReceipt.TransactionHash);ResultTxnHash.text=transactionTransferReceipt.TransactionHash;varbalanceOfFunctionMessage=newBalanceOfFunction(){Owner=AddressTo,};varbalanceHandler=web3.Eth.GetContractQueryHandler<BalanceOfFunction>();varbalance=awaitbalanceHandler.QueryAsync<BigInteger>(contractAddress,balanceOfFunctionMessage);varbalanceReceiver=UnitConversion.Convert.FromWei(balance);ResultBalanceAddressTo.text=balanceReceiver.ToString();Console.WriteLine("Balance of receiver after transfer: "+balance);vartransferEvent=transactionTransferReceipt.DecodeAllEvents<TransferEventDTO>();Debug.Log("Transferred amount from event: "+transferEvent[0].Event.Value);vartransferEventHandler=web3.Eth.GetEvent<TransferEventDTO>(contractAddress);varfilterInput=transferEventHandler.CreateFilterInput(_selectedAccountAddress);varevents=awaittransferEventHandler.GetAllChangesAsync(filterInput);Debug.Log("Transferred amount from get logs event: "+events[0].Event.Value);

Full Sample ERC20 Unity Web3 / Tasks

usingNethereum.BlockchainProcessing.BlockStorage.Entities;usingNethereum.Contracts;usingNethereum.Hex.HexTypes;usingNethereum.Metamask;usingNethereum.Unity.Contracts;
#if UNITY_WEBGLusingNethereum.Unity.Metamask;
#endif
usingNethereum.Unity.Rpc;usingNethereum.Util;usingNethereum.Web3;usingNethereum.Web3.Accounts;usingSystem;usingSystem.Collections;usingSystem.Numerics;usingSystem.Threading.Tasks;usingUnityEngine;usingUnityEngine.UI;usingDebug=UnityEngine.Debug;publicclassMultiplatformErc20Web3Task:MonoBehaviour{publicstringUrl="http://localhost:8545";publicBigIntegerChainId=444444444500;publicstringPrivateKey="0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7";publicstringAddressTo="0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe";privatestring_selectedAccountAddress;privatebool_isMetamaskInitialised=false;publicdecimalAmount=1.1m;publicInputFieldInputUrl;publicInputFieldInputChainId;publicInputFieldInputPrivateKey;publicInputFieldInputAddressTo;publicInputFieldInputAmount;publicInputFieldResultBalanceAddressTo;publicInputFieldResultTxnHash;publicInputFieldResultContractAddress;publicButtonBtnMetamaskConnect;publicTextLblError;privateMetamaskHostProvidermetamaskHost;voidStart(){if(IsWebGL())// using pk etc only on desktop as an example{InputUrl.enabled=false;InputPrivateKey.enabled=false;InputChainId.enabled=false;
#if UNITY_WEBGLmetamaskHost=MetamaskWebglHostProvider.CreateOrGetCurrentInstance();metamaskHost.SelectedAccountChanged+=MetamaskHost_SelectedAccountChanged;
#endif
}else{InputUrl.text=Url;InputPrivateKey.text=PrivateKey;InputChainId.text=ChainId.ToString();BtnMetamaskConnect.enabled=false;}InputAddressTo.text=AddressTo;InputAmount.text=Amount.ToString();}privateTaskMetamaskHost_SelectedAccountChanged(stringarg){_selectedAccountAddress=arg;returnTask.CompletedTask;}publicboolIsWebGL(){
#if UNITY_WEBGLreturntrue;
#else
returnfalse;
#endif
}publicasyncvoidDeployRequest(){awaitDeployERC20Async();}publicasyncTaskDeployERC20Async(){varweb3=awaitGetWeb3Async();web3.TransactionManager.UseLegacyAsDefault=true;web3.TransactionReceiptPolling.SetPollingRetryIntervalInMilliseconds(2000);// 2 seconds polling for receiptsvardeployContract=newStandardTokenDeployment(){TotalSupply=Nethereum.Web3.Web3.Convert.ToWei(10000000),FromAddress=_selectedAccountAddress};vardeploymentHandler=web3.Eth.GetContractDeploymentHandler<StandardTokenDeployment>();vartransactionReceiptDeployment=awaitdeploymentHandler.SendRequestAndWaitForReceiptAsync(deployContract);varcontractAddress=transactionReceiptDeployment.ContractAddress;ResultContractAddress.text=contractAddress;}publicasyncvoidTransferRequest(){awaitTransferErc20AndGetBalanceAsync();}publicasyncTaskTransferErc20AndGetBalanceAsync(){varweb3=awaitGetWeb3Async();web3.TransactionManager.UseLegacyAsDefault=true;web3.TransactionReceiptPolling.SetPollingRetryIntervalInMilliseconds(2000);// 2 seconds polling for receipts//Note this could use the services generated by the code generator to simplify it further//or web3.Eth.ERC20 presets AddressTo=InputAddressTo.text;Amount=System.Decimal.Parse(InputAmount.text);varcontractAddress=ResultContractAddress.text;vartransferFunction=newTransferFunction{To=AddressTo,TokenAmount=Nethereum.Web3.Web3.Convert.ToWei(Amount),FromAddress=_selectedAccountAddress};vartransferHandler=web3.Eth.GetContractTransactionHandler<TransferFunction>();vartransactionTransferReceipt=awaittransferHandler.SendRequestAndWaitForReceiptAsync(contractAddress,transferFunction);Console.WriteLine("Transaction hash transfer is: "+transactionTransferReceipt.TransactionHash);ResultTxnHash.text=transactionTransferReceipt.TransactionHash;varbalanceOfFunctionMessage=newBalanceOfFunction(){Owner=AddressTo,};varbalanceHandler=web3.Eth.GetContractQueryHandler<BalanceOfFunction>();varbalance=awaitbalanceHandler.QueryAsync<BigInteger>(contractAddress,balanceOfFunctionMessage);varbalanceReceiver=UnitConversion.Convert.FromWei(balance);ResultBalanceAddressTo.text=balanceReceiver.ToString();Console.WriteLine("Balance of receiver after transfer: "+balance);vartransferEvent=transactionTransferReceipt.DecodeAllEvents<TransferEventDTO>();Debug.Log("Transferred amount from event: "+transferEvent[0].Event.Value);vartransferEventHandler=web3.Eth.GetEvent<TransferEventDTO>(contractAddress);varfilterInput=transferEventHandler.CreateFilterInput(_selectedAccountAddress);varevents=awaittransferEventHandler.GetAllChangesAsync(filterInput);Debug.Log("Transferred amount from get logs event: "+events[0].Event.Value);}publicvoidDisplayError(stringerrorMessage){LblError.text=errorMessage;}publicvoidMetamaskConnect(){
#if UNITY_WEBGLif(IsWebGL()){if(MetamaskWebglInterop.IsMetamaskAvailable()){MetamaskWebglInterop.EnableEthereum(gameObject.name,nameof(EthereumEnabled),nameof(DisplayError));}else{DisplayError("Metamask is not available, please install it");}}
#endif
}publicvoidEthereumEnabled(stringaddressSelected){
#if UNITY_WEBGLif(IsWebGL()){if(!_isMetamaskInitialised){MetamaskWebglInterop.EthereumInit(gameObject.name,nameof(NewAccountSelected),nameof(ChainChanged));MetamaskWebglInterop.GetChainId(gameObject.name,nameof(ChainChanged),nameof(DisplayError));_isMetamaskInitialised=true;}NewAccountSelected(addressSelected);}
#endif
}publicvoidChainChanged(stringchainId){print(chainId);ChainId=newHexBigInteger(chainId).Value;InputChainId.text=ChainId.ToString();}publicvoidNewAccountSelected(stringaccountAddress){_selectedAccountAddress=accountAddress;}privatestringGetSelectedAccount(){return_selectedAccountAddress;}privateasyncTask<IWeb3>GetWeb3Async(){
#if UNITY_WEBGLawaitmetamaskHost.EnableProviderAsync();_selectedAccountAddress=metamaskHost.SelectedAccount;returnawaitmetamaskHost.GetWeb3Async();
#else
Url=InputUrl.text;PrivateKey=InputPrivateKey.text;ChainId=BigInteger.Parse(InputChainId.text);varaccount=newAccount(PrivateKey,ChainId);_selectedAccountAddress=account.Address;returnnewWeb3(account,Url);
#endif
}}

Credits

About

Unity3d sample template to work with Nethereum

Resources

Stars

87 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages