logo

Developing Smart Contracts

#

This guide shows how to develop a smart contract using the GreeterContract as an example. You’ll learn to create your own basic contract.

Steps for Developing Smart Contracts#

  • Install template: Install the aelf smart contract templates using the dotnet command.
  • Initialize project: Create the project structure and base contract code.
  • Define the contract: Use a protobuf file to define methods and types.
  • Implement contract code: Write the logic for the contract methods.
  • Test smart contracts: Create unit tests for the contracts.
  • The Greeter contract includes an AddGreeters method to add a new greeter and a GetGreeters method to list all greeters.

    Install Template#

  • To install the template, run:
  • 1
    dotnet new --install AElf.ContractTemplates
  • Verify installation with:
  • 1
    dotnet new uninstall

    Initialize Project#

  • Create a project named GreeterContract with:
  • 1
    dotnet new aelf -n GreeterContract -N AElf.Contracts.Greeter

    This generates the following structure:

    1
    .
    2
    ├── src
    3
    │ ├── GreeterContract.cs
    4
    │ ├── GreeterContract.csproj
    5
    │ ├── GreeterContractState.cs
    6
    │ └── Protobuf
    7
    │ ├── contract
    8
    │ │ └── hello_world_contract.proto
    9
    │ └── message
    10
    │ └── authority_info.proto
    11
    └── test
    12
    ├── GreeterContract.Tests.csproj
    13
    ├── GreeterContractTests.cs
    14
    ├── Protobuf
    15
    │ ├── message
    16
    │ │ └── authority_info.proto
    17
    │ └── stub
    18
    │ └── hello_world_contract.proto
    19
    └── _Setup.cs
  • Define the Contract Create a greeter_contract.proto file to define the contract:
  • 1
    syntax = "proto3";
    2
    3
    import "aelf/options.proto";
    4
    import "google/protobuf/empty.proto";
    5
    import "google/protobuf/wrappers.proto";
    6
    option csharp_namespace = "AElf.Contracts.Greeter";
    7
    8
    service GreeterContract {
    9
    option (aelf.csharp_state) = "AElf.Contracts.Greeter.GreeterContractState";
    10
    11
    rpc AddGreeters (google.protobuf.StringValue) returns (google.protobuf.Empty) {}
    12
    rpc GetGreeters (google.protobuf.Empty) returns (GreeterList) {
    13
    option (aelf.is_view) = true;
    14
    }
    15
    }
    16
    17
    message GreeterList {
    18
    repeated string greeter = 1;
    19
    }
  • Implement Contract Code Run dotnet build in the src folder to compile the proto files. Implement the contract logic in GreeterContract.cs:
  • 1
    using AElf.Sdk.CSharp;
    2
    using Google.Protobuf.WellKnownTypes;
    3
    4
    namespace AElf.Contracts.Greeter
    5
    {
    6
    public class GreeterContract : GreeterContractContainer.GreeterContractBase
    7
    {
    8
    public override Empty AddGreeters(StringValue input)
    9
    {
    10
    Assert(!string.IsNullOrWhiteSpace(input.Value), "Invalid name.");
    11
    12
    var greeterList = State.GreeterList.Value ?? new GreeterList();
    13
    if (!greeterList.Greeter.Contains(input.Value))
    14
    {
    15
    greeterList.Greeter.Add(input.Value);
    16
    }
    17
    State.GreeterList.Value = greeterList;
    18
    19
    return new Empty();
    20
    }
    21
    22
    public override GreeterList GetGreeters(Empty input)
    23
    {
    24
    return State.GreeterList.Value ?? new GreeterList();
    25
    }
    26
    }
    27
    }
  • Define the contract state in GreeterContractState.cs:
  • 1
    using AElf.Sdk.CSharp.State;
    2
    3
    namespace AElf.Contracts.Greeter
    4
    {
    5
    public class GreeterContractState : ContractState
    6
    {
    7
    public SingletonState<GreeterList> GreeterList { get; set; }
    8
    }
    9
    }
  • Test Smart Contracts Use the AElf.ContractTestKit for testing. The test folder contains the necessary files for unit testing.
  • Setup the testing context in _Setup.cs:
  • 1
    using AElf.Cryptography.ECDSA;
    2
    using AElf.Testing.TestBase;
    3
    4
    namespace AElf.Contracts.Greeter
    5
    {
    6
    public class Module : ContractTestModule<GreeterContract> { }
    7
    8
    public class TestBase : ContractTestBase<Module>
    9
    {
    10
    internal readonly GreeterContractContainer.GreeterContractStub GreeterContractStub;
    11
    private ECKeyPair DefaultKeyPair => Accounts[0].KeyPair;
    12
    13
    public TestBase()
    14
    {
    15
    GreeterContractStub = GetGreeterContractContractStub(DefaultKeyPair);
    16
    }
    17
    18
    private GreeterContractContainer.GreeterContractStub GetGreeterContractContractStub(ECKeyPair senderKeyPair)
    19
    {
    20
    return GetTester<GreeterContractContainer.GreeterContractStub>(ContractAddress, senderKeyPair);
    21
    }
    22
    }
    23
    }
  • Write unit tests in GreeterContractTests.cs:
  • 1
    using System.Threading.Tasks;
    2
    using Google.Protobuf.WellKnownTypes;
    3
    using Shouldly;
    4
    using Xunit;
    5
    6
    namespace AElf.Contracts.Greeter
    7
    {
    8
    public class GreeterContractTests : TestBase
    9
    {
    10
    [Fact]
    11
    public async Task AddGreetersTest()
    12
    {
    13
    var user1 = new StringValue { Value = "Tom" };
    14
    var user2 = new StringValue { Value = "Jerry" };
    15
    var expectList = new GreeterList();
    16
    expectList.Greeter.Add(user1.Value);
    17
    expectList.Greeter.Add(user2.Value);
    18
    19
    await GreeterContractStub.AddGreeters.SendAsync(user1);
    20
    await GreeterContractStub.AddGreeters.SendAsync(user2);
    21
    22
    var greeterList = await GreeterContractStub.GetGreeters.CallAsync(new Empty());
    23
    greeterList.ShouldBe(expectList);
    24
    }
    25
    }
    26
    }

    Edited on: 16 July 2024 05:34:15 GMT+0