Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added new contract templates #54

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
temp
.DS_Store

# Rider
.idea/
21 changes: 21 additions & 0 deletions templates/ExpenseTrackerContract/.template.config/template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "http://json.schemastore.org/template",
"author": "AElf",
"classifications": [
"AElf/SmartContract"
],
"identity": "AElf.Contract.ExpenseTracker.Template",
"name": "AElf Contract ExpenseTracker Template",
"shortName": "aelf-expense-tracker",
"tags": {
"language": "C#",
"type": "project"
},
"sourceName": "ExpenseTracker",
"symbols": {
"NamespacePath": {
"type": "parameter",
"replaces": "AElf.Contracts.ExpenseTracker"
}
}
}
117 changes: 117 additions & 0 deletions templates/ExpenseTrackerContract/src/ExpenseTracker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using Google.Protobuf.WellKnownTypes;
using System.Collections.Generic;

namespace AElf.Contracts.ExpenseTracker
{
public class ExpenseTracker : ExpenseTrackerContainer.ExpenseTrackerBase
{
public override Empty Initialize(Empty input)
{
if (State.Initialized.Value)
{
return new Empty();
}
State.Initialized.Value = true;
State.Owner.Value = Context.Sender;
State.ExpenseIds.Value = "";
State.ExpenseCounter.Value = 0;
return new Empty();
}

public override StringValue AddExpense(ExpenseInput input)
{
if (!State.Initialized.Value)
{
return new StringValue { Value = "Contract not initialized." };
}
var expenseId = (State.ExpenseCounter.Value + 1).ToString();
State.ExpenseCounter.Value++;
var timestamp = Context.CurrentBlockTime.Seconds;
State.Expenses[expenseId] = new Expense
{
ExpenseId = expenseId,
Description = input.Description,
Category = input.Category,
Amount = input.Amount, // Now using int64 for amount
Currency = input.Currency,
CreatedAt = timestamp,
UpdatedAt = timestamp,
Owner = Context.Sender.ToString().Trim('"'),
};
State.ExpenseExistence[expenseId] = true;

var existingExpenseIds = State.ExpenseIds.Value;
existingExpenseIds += string.IsNullOrEmpty(existingExpenseIds) ? expenseId : $",{expenseId}";
State.ExpenseIds.Value = existingExpenseIds;

return new StringValue { Value = expenseId };
}

public override Empty UpdateExpense(ExpenseUpdateInput input)
{
var expense = State.Expenses[input.ExpenseId];
if (expense == null)
{
return new Empty(); // Handle case if expense doesn't exist
}
expense.Description = input.Description ?? expense.Description;
expense.Category = input.Category ?? expense.Category;
expense.Amount = input.Amount != 0 ? input.Amount : expense.Amount; // Now using int64 for amount
expense.Currency = input.Currency ?? expense.Currency;
expense.UpdatedAt = Context.CurrentBlockTime.Seconds;

State.Expenses[input.ExpenseId] = expense;
return new Empty();
}

public override Empty DeleteExpense(StringValue input)
{
State.Expenses.Remove(input.Value);
State.ExpenseExistence.Remove(input.Value);

var existingExpenseIds = State.ExpenseIds.Value.Split(',');
var newExpenseIds = new List<string>(existingExpenseIds.Length);
foreach (var expenseId in existingExpenseIds)
{
if (expenseId != input.Value)
{
newExpenseIds.Add(expenseId);
}
}
State.ExpenseIds.Value = string.Join(",", newExpenseIds);

return new Empty();
}

public override ExpenseList ListExpenses(StringValue input)
{
var owner = input.Value; // Get the owner value from the input
var expenseList = new ExpenseList();
var expenseIds = State.ExpenseIds.Value.Split(',');
foreach (var expenseId in expenseIds)
{
var expense = State.Expenses[expenseId];
if (expense != null && expense.Owner == owner) // Filter expenses by owner
{
expenseList.Expenses.Add(expense);
}
}
return expenseList;
}

public override Expense GetExpense(StringValue input)
{
var expense = State.Expenses[input.Value];
if (expense == null)
{
return new Expense { ExpenseId = input.Value, Description = "Expense not found." };
}
return expense;
}

public override BoolValue GetInitialStatus(Empty input)
{
return new BoolValue { Value = State.Initialized.Value };
}
}
}
27 changes: 27 additions & 0 deletions templates/ExpenseTrackerContract/src/ExpenseTracker.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>AElf.Contracts.ExpenseTracker</RootNamespace>
<IsContract>true</IsContract>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
</PropertyGroup>
<PropertyGroup>
<ObjPath>$(MSBuildProjectDirectory)/$(BaseIntermediateOutputPath)$(Configuration)/$(TargetFramework)/</ObjPath>
</PropertyGroup>

<Target Name="ProtoGeneratedRecognition" AfterTargets="CoreCompile">
<ItemGroup>
<Compile Include="$(ObjPath)Protobuf/**/*.cs" />
</ItemGroup>
</Target>

<ItemGroup>
<PackageReference Include="AElf.Sdk.CSharp" Version="1.5.0" />
<PackageReference Include="AElf.Tools" Version="1.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>

15 changes: 15 additions & 0 deletions templates/ExpenseTrackerContract/src/ExpenseTrackerState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using AElf.Sdk.CSharp.State;
using AElf.Types;

namespace AElf.Contracts.ExpenseTracker
{
public class ExpenseTrackerState : ContractState
{
public BoolState Initialized { get; set; }
public SingletonState<Address> Owner { get; set; }
public MappedState<string, Expense> Expenses { get; set; } // Mapping of expense ID to Expense
public MappedState<string, bool> ExpenseExistence { get; set; } // Mapping to track expense existence
public StringState ExpenseIds { get; set; } // Concatenated string of expense IDs
public Int32State ExpenseCounter { get; set; } // Counter for generating unique IDs
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
syntax = "proto3";
import "aelf/options.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/wrappers.proto";
import "Protobuf/reference/acs12.proto";
// The namespace of this class
option csharp_namespace = "AElf.Contracts.ExpenseTracker";
service ExpenseTracker {
option (aelf.csharp_state) = "AElf.Contracts.ExpenseTracker.ExpenseTrackerState";
option (aelf.base) = "Protobuf/reference/acs12.proto";
rpc Initialize (google.protobuf.Empty) returns (google.protobuf.Empty) {
}
rpc AddExpense (ExpenseInput) returns (google.protobuf.StringValue) {
}
rpc UpdateExpense (ExpenseUpdateInput) returns (google.protobuf.Empty) {
}
rpc DeleteExpense (google.protobuf.StringValue) returns (google.protobuf.Empty) {
}
rpc ListExpenses (google.protobuf.StringValue) returns (ExpenseList) {
option (aelf.is_view) = true;
}
rpc GetExpense (google.protobuf.StringValue) returns (Expense) {
option (aelf.is_view) = true;
}
rpc GetInitialStatus (google.protobuf.Empty) returns (google.protobuf.BoolValue) {
option (aelf.is_view) = true;
}
}

message Expense {
string expense_id = 1;
string description = 2;
string category = 3;
int64 amount = 4; // Store as cents
string currency = 5;
string owner = 6;
int64 created_at = 7;
int64 updated_at = 8;
}

message ExpenseInput {
string description = 1;
string category = 2;
int64 amount = 3; // Store as cents
string currency = 4;
}

message ExpenseUpdateInput {
string expense_id = 1;
string description = 2;
string category = 3;
int64 amount = 4; // Store as cents
string currency = 5;
}

message ExpenseList {
repeated Expense expenses = 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
syntax = "proto3";

import "aelf/core.proto";

option csharp_namespace = "AElf.Contracts.ExpenseTracker";

message AuthorityInfo {
aelf.Address contract_address = 1;
aelf.Address owner_address = 2;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* AElf Standards ACS12(User Contract Standard)
*
* Used to manage user contract.
*/
syntax = "proto3";

package acs12;

import public "aelf/options.proto";
import public "google/protobuf/empty.proto";
import public "google/protobuf/wrappers.proto";
import "aelf/core.proto";

option (aelf.identity) = "acs12";
option csharp_namespace = "AElf.Standards.ACS12";

service UserContract{

}

//Specified method fee for user contract.
message UserContractMethodFees {
// List of fees to be charged.
repeated UserContractMethodFee fees = 2;
// Optional based on the implementation of SetConfiguration method.
bool is_size_fee_free = 3;
}

message UserContractMethodFee {
// The token symbol of the method fee.
string symbol = 1;
// The amount of fees to be charged.
int64 basic_fee = 2;
}
51 changes: 51 additions & 0 deletions templates/ExpenseTrackerContract/test/ExpenseTracker.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>AElf.Contracts.ExpenseTracker</RootNamespace>
</PropertyGroup>

<PropertyGroup>
<NoWarn>0436;CS2002</NoWarn>
</PropertyGroup>
<PropertyGroup>
<ObjPath>$(MSBuildProjectDirectory)/$(BaseIntermediateOutputPath)$(Configuration)/$(TargetFramework)/</ObjPath>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AElf.Testing.TestBase" Version="1.0.0" />
<PackageReference Include="AElf.EconomicSystem" Version="1.5.0" />
<PackageReference Include="AElf.GovernmentSystem" Version="1.5.0" />
<PackageReference Include="coverlet.msbuild" Version="2.5.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="Shouldly" Version="3.0.2" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="AElf.ContractTestKit" Version="1.5.0" />
<PackageReference Include="AElf.Tools" Version="1.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<Protobuf Include="Protobuf/base/*.proto">
<ContractOutputOptions>nocontract</ContractOutputOptions>
</Protobuf>
<Protobuf Include="Protobuf/message/*.proto">
<ContractOutputOptions>nocontract</ContractOutputOptions>
</Protobuf>
<Protobuf Include="Protobuf/stub/*.proto">
<ContractOutputOptions>stub</ContractOutputOptions>
</Protobuf>
</ItemGroup>

<ItemGroup>
<Compile Include="$(ObjPath)Protobuf/**/*.cs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="../src/ExpenseTracker.csproj" />
</ItemGroup>

</Project>
27 changes: 27 additions & 0 deletions templates/ExpenseTrackerContract/test/ExpenseTrackerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using Shouldly;
using Xunit;

namespace AElf.Contracts.ExpenseTracker
{
// This class is unit test class, and it inherit TestBase. Write your unit test code inside it
public class ExpenseTrackerTests : TestBase
{
[Fact]
public async Task Update_ShouldUpdateMessageAndFireEvent()
{
// Arrange
var inputValue = "Hello, World!";
var input = new StringValue { Value = inputValue };

// Act
await ExpenseTrackerStub.Update.SendAsync(input);

// Assert
var updatedMessage = await ExpenseTrackerStub.Read.CallAsync(new Empty());
updatedMessage.Value.ShouldBe(inputValue);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
syntax = "proto3";

import "aelf/core.proto";

option csharp_namespace = "AElf.Contracts.ExpenseTracker";

message AuthorityInfo {
aelf.Address contract_address = 1;
aelf.Address owner_address = 2;
}
Loading