# Counter tutorial with C# and NetCasperSDK This example shows how to use the NetCasperSDK to: - send $CSPR from one account to another - Deploy the counter contract example to the network - Read the counter value - Call the `counter_inc` contract function to increase the counter. We are using a local network. Learn [here](https://docs.casperlabs.io/en/latest/dapp-dev-guide/setup-nctl.html) how to install your own local network. ### Get a new instance of the client Prepare an instance of the client and a couple of keys that will be used during the example: ```csharp static string nodeAddress = "http://207.154.217.11:11101/rpc"; static NetCasperClient casperSdk = new NetCasperClient(nodeAddress); static KeyPair faucetAcct = KeyPair.FromPem("/tmp/faucetact.pem"); static KeyPair account2 = KeyPair.FromPem("/tmp/myaccount2.pem"); ``` ### Send $CSPR from the faucet account to `account2` Use the `StandardTransfer` template to create a deploy object that orders a transfer of 2500 $CSPR. Sign it and deploy it to the network. Take the `deploy_hash` from the response and make a call to `GetDeploy` with a timeout of 120 seconds to obtain the result of the transfer (testnet usually needs a longer timeout). ```csharp public static async Task FundAccount() { var deploy = DeployTemplates.StandardTransfer( faucetAcct, account2.PublicKey, 2500000000000, 1200, "casper-net-1"); deploy.Sign(faucetAcct); var response = await casperSdk.PutDeploy(deploy); string deployHash = response.GetDeployHash(); var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(120)); response = await casperSdk.GetDeploy(deployHash, tokenSource.Token); File.WriteAllText("res_FundAccount.json", response.Result.GetRawText()); } ``` ### Deploy the counter contract You may find more information on the counter contract used in this example here: [A Counter Contract Tutorial](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/counter/index.html). If you haven't done yet, clone the repository and build the contract following the instruction in the README file. ``` git clone https://github.com/casper-ecosystem/counter cd counter cat README ``` Now use the `ContractDeploy` template to prepare a deploy object, sign it and deploy it. ```csharp public static async Task DeployContract(string wasmFile) { var wasmBytes = System.IO.File.ReadAllBytes(wasmFile); var deploy = DeployTemplates.ContractDeploy(wasmBytes, account2, // 500000000000, //payment "casper-net-1", //network 1, //gas-price 1800000); //ttl deploy.Sign(account2); var response = await casperSdk.PutDeploy(deploy); string deployHash = response.GetDeployHash(); var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(120)); response = await casperSdk.GetDeploy(deployHash, tokenSource.Token); Console.WriteLine(response.Result.GetRawText()); System.IO.File.WriteAllText("res_DeployContract.json", response.Result.GetRawText()); } ``` ### Get the counter value To get current counter value, call `GetAccountInfo` indicating the path of the key to retrieve: ```csharp public static async Task QueryState() { var response = await casperSdk.GetAccountInfo(account2.PublicKey, new List<string>() {"counter", "count"}); Console.WriteLine(response.Result.GetRawText()); System.IO.File.WriteAllText("res_QueryState.json", response.Result.GetRawText()); } ``` The output will look like the following: ``` { "api_version": "1.0.0", "stored_value": { "CLValue": { "cl_type": "I32", "bytes": "00000000", "parsed": 0 } }, "merkle_proof": "..." } ``` Alternatively, the contract hash and the `QueryState` method can be used to get the counter value instead of `GetAccountInfo`: ```csharp var response = await casperSdk.QueryState( "hash-d27328ad7692dfb029430d020c7d2c88d4b1d9f2a510c1712df9dbf4be74d85d", new List<string>() {"count"}); ``` ### Increment the counter Next, increment the counter by calling the `counter_inc` method. Use now the `ContractCall` template: ```csharp public static async Task CallCounterInc() { var deploy = DeployTemplates.ContractCall("counter", "counter_inc", new List<NamedArg>(), account2, 50000000000, "casper-net-1", 1, 1800000); deploy.Sign(account2); var response = await casperSdk.PutDeploy(deploy); string deployHash = response.GetDeployHash(); var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(120)); response = await casperSdk.GetDeploy(deployHash, tokenSource.Token); Console.WriteLine(response.Result.GetRawText()); System.IO.File.WriteAllText("res_CallCounterInc.json", response.Result.GetRawText()); } ``` ### Check the counter has a new value Calling the `QueryState()` method as above we'll now see that the counter has a new value: ``` { "api_version": "1.0.0", "stored_value": { "CLValue": { "cl_type": "I32", "bytes": "01000000", "parsed": 1 } }, "merkle_proof": "0300000000989ca079a ``` The tutorial also contains a second contract named `counter-call`. We can increment the count using that second contract instead of the session entry-point we used before. Call the `DeployContract()` function passing now the `contract-call.wasm` location. ### Full example code `Program.cs` ```csharp= using System; using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using NetCasperSDK; using NetCasperSDK.JsonRpc; using NetCasperSDK.Types; namespace CasperMain { public static class DeployCounterContract { static string nodeAddress = "http://207.154.217.11:11101/rpc"; static NetCasperClient casperSdk; static KeyPair faucetAcct = KeyPair.FromPem("/tmp/faucetact.pem"); static KeyPair account2 = KeyPair.FromPem("/tmp/myaccount2.pem"); public static async Task FundAccount() { var deploy = DeployTemplates.StandardTransfer( faucetAcct, account2.PublicKey, 2500000000000, 1200, "casper-net-1"); deploy.Sign(faucetAcct); var response = await casperSdk.PutDeploy(deploy); string deployHash = response.GetDeployHash(); var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(120)); response = await casperSdk.GetDeploy(deployHash, tokenSource.Token); File.WriteAllText("res_FundAccount.json", response.Result.GetRawText()); } public static async Task DeployContract(string wasmFile) { var wasmBytes = System.IO.File.ReadAllBytes(wasmFile); var deploy = DeployTemplates.ContractDeploy(wasmBytes, account2, 500000000000, "casper-net-1", 1, 1800000); deploy.Sign(account2); var response = await casperSdk.PutDeploy(deploy); string deployHash = response.GetDeployHash(); var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(120)); response = await casperSdk.GetDeploy(deployHash, tokenSource.Token); Console.WriteLine(response.Result.GetRawText()); System.IO.File.WriteAllText("res_DeployContract.json", response.Result.GetRawText()); } public static async Task QueryState() { var response = await casperSdk.GetAccountInfo(account2.PublicKey, new List<string>() {"counter", "count"}); Console.WriteLine(response.Result.GetRawText()); System.IO.File.WriteAllText("res_QueryState.json", response.Result.GetRawText()); } public static async Task CallCounterInc() { var deploy = DeployTemplates.ContractCall("counter", "counter_inc", new List<NamedArg>(), account2, 50000000000, "casper-net-1", 1, 1800000); deploy.Sign(account2); var response = await casperSdk.PutDeploy(deploy); string deployHash = response.GetDeployHash(); var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(120)); response = await casperSdk.GetDeploy(deployHash, tokenSource.Token); Console.WriteLine(response.Result.GetRawText()); System.IO.File.WriteAllText("res_CallCounterInc.json", response.Result.GetRawText()); } public async static Task Main(string[] args) { // use a logginghandler to print out all communication with the node // var loggingHandler = new RpcLoggingHandler(new HttpClientHandler()) { LoggerStream = new StreamWriter(Console.OpenStandardOutput()) }; casperSdk = new NetCasperClient(nodeAddress, loggingHandler); try { await FundAccount(); await DeployContract("/tmp/counter-define.wasm"); await QueryState(); await CallCounterInc(); await QueryState(); await DeployContract("/tmp/counter_call.wasm"); await QueryState(); } catch (RpcClientException e) { Console.WriteLine(e.RpcError.Message); } catch (Exception e) { Console.WriteLine(e.Message); } } } } ``` `CounterContract.csproj` ```xml= <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net5.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="NetCasperSDK" Version="0.9.2" /> </ItemGroup> </Project> ```