# Plugin-based Smart Contract Quickstart

### Plugin-based Smart Contract Quickstart <a href="#plugin-based-smart-contract-quickstart" id="plugin-based-smart-contract-quickstart"></a>

zeknd supports EVM (Ethereum Virtual Machine) and plugin-based smart contracts. As an example, Plugin-based smart contracts can be created with go-zeknd.

In this quick tutorial, we will demonstrate how to use the Unity SDK to communicate with plugin-based smart contracts.

### #Sample Code <a href="#sample-code" id="sample-code"></a>

You can find all the code on this page and a ready-to-go Unity scene in the zeknd Unity SDK under `Assets/`zeknd`SDK/Samples/QuickStart`.

### #Connecting to a DAppChain <a href="#connecting-to-a-dappchain" id="connecting-to-a-dappchain"></a>

The `Contract` class provides a convenient way to interact with a smart contract running on a zeknd DAppChain. Let's write a method that creates a `Contract` instance to interact with the sample BluePrint smart contract provided in the zeknd SDK:

```
// zekndQuickStartSample.cs
using System;
using System.Threading.Tasks;
using UnityEngine;
using zeknd.Unity3d;
using zeknd.Unity3d.Samples;

public class zekndQuickStartSample : MonoBehavior
{
    async Task<Contract> GetContract(byte[] privateKey, byte[] publicKey)
    {
        var writer = RPCClientFactory.Configure()
            .WithLogger(Debug.unityLogger)
            .WithHTTP("http://127.0.0.1:46658/rpc")
            .Create();

        var reader = RPCClientFactory.Configure()
            .WithLogger(Debug.unityLogger)
            .WithHTTP("http://127.0.0.1:46658/query")
            .Create();

        var client = new DAppChainClient(writer, reader)
        {
            Logger = Debug.unityLogger
        };
        // required middleware
        client.TxMiddleware = new TxMiddleware(new ITxMiddlewareHandler[]{
            new NonceTxMiddleware{
                PublicKey = publicKey,
                Client = client
            },
            new SignedTxMiddleware(privateKey)
        });
        var contractAddr = await client.ResolveContractAddressAsync("BluePrint");
        var callerAddr = Address.FromPublicKey(publicKey);
        return new Contract(client, contractAddr, callerAddr);
    }
}
```

### #Writing data to a DAppChain <a href="#writing-data-to-a-dappchain" id="writing-data-to-a-dappchain"></a>

To mutate the state of a smart contract you need to call one of its public methods. To do so, a signed transaction must be sent to and validated by the DAppChain. Fortunately, the `Contract` class takes care of most of this when you use the `Contract.CallAsync()` method.

The BluePrint smart contract has a public `SetMsg` method that can be called to store an association between a key and a value. Note that this method doesn't return anything. Let's add a method to the zeknd`QuickStartSample` class that calls `BluePrint.SetMsg()`:

```
async Task CallContract(Contract contract)
{
    await contract.CallAsync("SetMsg", new MapEntry
    {
        Key = "123",
        Value = "hello!"
    });
}
```

Smart contract methods that mutate the state may return a value. The BluePrint smart contract has a public `SetMsgEcho` method that will store a key/value and return the key/value it stored. Let's add another method to the zeknd`QuickStartSample` class that calls `BluePrint.SetMsgEcho`.

```
async Task CallContractWithResult(Contract contract)
{
    var result = await contract.CallAsync<MapEntry>("SetMsgEcho", new MapEntry
    {
        Key = "321",
        Value = "456"
    });

    if (result != null)
    {
        // This should print: { "key": "321", "value": "456" } in the Unity console window.
        Debug.Log("Smart contract returned: " + result.ToString());
    }
    else
    {
        throw new Exception("Smart contract didn't return anything!");
    }
}
```

### #Reading data from a DAppChain <a href="#reading-data-from-a-dappchain" id="reading-data-from-a-dappchain"></a>

To read the state of a smart contract, you need to call one of its public read-only methods. Calling a read-only method doesn't modify the smart contract state. You can call a read-only method on a smart contract by using the `Contract.StaticCallAsync()` method.

The BluePrint smart contract has a public `GetMsg` method that can be called to look up an association between a key and a value. Let's add a method to the zeknd`QuickStartSample` class that calls `BluePrint.GetMsg`:

```
async Task StaticCallContract(Contract contract)
{
    var result = await contract.StaticCallAsync<MapEntry>("GetMsg", new MapEntry
    {
        Key = "123"
    });

    if (result != null)
    {
        // This should print: { "key": "123", "value": "hello!" } in the Unity console window
        // provided `zekndQuickStartSample.CallContract()` was called first.
        Debug.Log("Smart contract returned: " + result.ToString());
    }
    else
    {
        throw new Exception("Smart contract didn't return anything!");
    }
}
```

### #Putting it all together <a href="#putting-it-all-together" id="putting-it-all-together"></a>

Add the following method to the zeknd`QuickStartSample` class:

```
// Use this for initialization
async void Start()
{
    // The private key is used to sign transactions sent to the DAppChain.
    // Usually you'd generate one private key per player, or let them provide their own.
    // In this sample we just generate a new key every time.
    var privateKey = CryptoUtils.GeneratePrivateKey();
    var publicKey = CryptoUtils.PublicKeyFromPrivateKey(privateKey);

    var contract = await GetContract(privateKey, publicKey);
    await CallContract(contract);
    // This should print: { "key": "123", "value": "hello!" } in the Unity console window
    await StaticCallContract(contract);
    // This should print: { "key": "321", "value": "456" } in the Unity console window
    await CallContractWithResult(contract);
}
```

Now that we have all the code in place let's test it out:

1. Create an empty `GameObject` in a Unity scene and attach the zeknd`QuickStartSample` script to it.
2. Deploy the BluePrint smart contract on a local zeknd DAppChain node.
3. Hit `Play` in the Unity Editor.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developer.opzeknd.xyz/unity-sdk/plugin-based-smart-contract-quickstart.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
