---
description: How to query Substrate chain state and how to sign and submit extrinsics.
---

# Substrate

Before reading this, it is very helpful to understand:

* SCALE: [https://docs.substrate.io/reference/scale-codec/](https://docs.substrate.io/reference/scale-codec/)
* Substrate.Net.Api: [https://youtu.be/TsdL6ULM7Mc?si=DmHZ4BgvCA8eXrHC](https://youtu.be/TsdL6ULM7Mc?si=DmHZ4BgvCA8eXrHC)

Make sure you have correctly registered your substrate chain to PlutoFramework according to this tutorial:

{% content-ref url="register-new-chain" %}
[register-new-chain](register-new-chain)
{% endcontent-ref %}

## About PlutoFrameworkSubstrateClient

SubstrateClient is the main communicator with Substrate chains. In fact, PlutoFramework creates a new independent instance of SubstrateClient for each Substrate chain it connects to and maintains this connection to be ready to query new state or submit extrinsics at any time.&#x20;

We have created a SubstrateClient wrapper called `PlutoFrameworkSubstrateClient` that handles the UI synchronization, listens to extrinsic status callbacks, handles reconnections and more.

At the moment, there are 2 main ways to get access to the SubstrateClient.

1\) Through ISubstrateClientLoadable interfaces implemented on a component.

```csharp
// Example of such implemented interface method
public Task LoadAsync(PlutoFrameworkSubstrateClient client, CancellationToken token)
{
    // You can allow only your chain.
    if (client is null || client.Endpoint.Key != Constants.EndpointEnum.YourChain || !client.SubstrateClient.IsConnected)
    {
        return Task.FromResult(0);
    }

    return ((IdentityViewModel)BindingContext).GetIdentityAsync((PolkadotPeople.NetApi.Generated.SubstrateClientExt)client.SubstrateClient, token);
}
```

2\) `GetOrAddSubstrateClientAsync` method:

{% code overflow="wrap" %}
```csharp
var client = await SubstrateClientModel.GetOrAddSubstrateClientAsync(EndpointEnum.YourChain, CancellationToken.None)
```
{% endcode %}

Both of these ways give you PlutoFrameworkSubstrateClient. To get access to the SubstrateClient. just write:

<pre class="language-csharp"><code class="lang-csharp"><strong>var substrateClient = (YourChain.NetApi.Generated.SubstrateClientExt)client.SubstrateClient;
</strong></code></pre>

## Query chain state (Pallet storage)

I recommend creating your own model class in `PlutoFramework.Model` folder to make the code reusable and testable.

Then, find the pallet storages you want to query from in your Chain generated folder.

Example: If I would want to query `System.Account` storage on PolkadotAssetHub parachain, I need to use the following method found in `Generated/PolkadotAssetHub.NetApi/Generated/Storage/MainSystem.cs`:

```csharp
/// <summary>
/// >> Account
///  The full account information for a particular account ID.
/// </summary>
public async Task<PolkadotAssetHub.NetApi.Generated.Model.frame_system.AccountInfo> Account(PolkadotAssetHub.NetApi.Generated.Model.sp_core.crypto.AccountId32 key, string blockhash, CancellationToken token)
{
    string parameters = SystemStorage.AccountParams(key);
    var result = await _client.GetStorageAsync<PolkadotAssetHub.NetApi.Generated.Model.frame_system.AccountInfo>(parameters, blockhash, token);
    return result;
}
```

This is the code example of querying such storage:

<pre class="language-csharp"><code class="lang-csharp"><strong>var token = CancellationToken.None;
</strong><strong>
</strong><strong>// I make sure that the client is PolkadotAssetHub
</strong><strong>if (client.Endpoint.Key != EndpointEnum.PolkadotAssetHub)
</strong>{
    return;
}
    
var substrateClient = (PolkadotAssetHub.NetApi.Generated.SubstrateClientExt)client.SubstrateClient;

// Example Substrate address
var substrateAddress = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";

// Parameter of the query
var account = new PolkadotAssetHub.NetApi.Generated.Model.sp_core.crypto.AccountId32();
account.Create(Utils.GetPublicKeyFrom(substrateAddress));

// Query chain state
<strong>var result = await substrateClient.SystemStorage.Account(
</strong><strong>     account,
</strong><strong>     null,
</strong><strong>     token
</strong><strong>);
</strong></code></pre>

{% hint style="success" %}
Please, use the generated classes and functions. Why?

It makes sure that your application code is always up-to-date, even if your blockchain get upgraded. You can simple sync the mobile application code by regenerating the C# blockchain representation by running `./generator.sh <Your chain name>` command.
{% endhint %}

## Submitting extrinsics

Submitting extrinsics works very similarly to querying on-chain data.

You are also <mark style="color:red;">**strongly**</mark> recommended to utilise the generated classes and functions, also found in the `Generated/Storage/MainSomething.cs` files, but found in the lower portion of the file.&#x20;

Example: If I want to call `Balances.transfer_keep_alive` extrinsic, I need to use the following method found in `Generated/PolkadotAssetHub.NetApi/Generated/Storage/MainBalances.cs`.

```csharp
/// <summary>
/// >> BalancesCalls
/// </summary>
public sealed class BalancesCalls
{
    // ...
    
    /// <summary>
    /// >> transfer_keep_alive
    /// Contains a variant per dispatchable extrinsic that this pallet has.
    /// </summary>
    public static Method TransferKeepAlive(PolkadotAssetHub.NetApi.Generated.Model.sp_runtime.multiaddress.EnumMultiAddress dest, Substrate.NetApi.Model.Types.Base.BaseCom<Substrate.NetApi.Model.Types.Primitive.U128> value)
    {
        System.Collections.Generic.List<byte> byteArray = new List<byte>();
        byteArray.AddRange(dest.Encode());
        byteArray.AddRange(value.Encode());
        return new Method(10, "Balances", 3, "transfer_keep_alive", byteArray.ToArray());
    }
    
    // ...
}
```

Example of such call:

<pre class="language-csharp"><code class="lang-csharp">var token = CancellationToken.None;

// Example Substrate address
var substrateAddress = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";
var amount = 10_000_000_000 // 1 DOT
<strong>
</strong><strong>var accountId = new AccountId32();
</strong>accountId.Create(Utils.GetPublicKeyFrom(substrateAddress));

var multiAddress = new EnumMultiAddress();
multiAddress.Create(0, accountId);

var baseComAmount = new BaseCom&#x3C;U128>();
baseComAmount.Create(amount);

// Extrinsic Call itself
var method = BalancesCalls.TransferKeepAlive(multiAddress, baseComAmount);

// Submitting the extrinsic
var transactionAnalyzerConfirmationViewModel = DependencyService.Get&#x3C;TransactionAnalyzerConfirmationViewModel>();
await transactionAnalyzerConfirmationViewModel.LoadAsync(
    client, // PlutoFrameworkSubstrateClient
    method,
    showDAppView: false,
    token: token
);
</code></pre>

{% hint style="warning" %}
In Substrate.Net.Api Method is synonyme to Call.

Do not get confused by the namings.
{% endhint %}

The last 2 lines are used to summon a confirmation popup for the user before they actually submit the extrinsic. This shows the TransactionAnalyzer simulated result, extrinsic payload can be expanded, estimated fees are shown and more. Your users will be sure that they have not accidentally misclicked or that they have not been hacked/scammed by someone. Accidents happen and it is better to be safe than sorry.

{% hint style="warning" %}
Always use Transaction Analyzer before submitting an extrinsic
{% endhint %}

{% content-ref url="transaction-analyzer" %}
[transaction-analyzer](transaction-analyzer)
{% endcontent-ref %}
