Skip to content

Commit

Permalink
feat: Added todo-app example in playground and created aelf-studio vs… (
Browse files Browse the repository at this point in the history
#287)

* feat: Added todo-app example in playground and created aelf-studio vs-code extention documentation

* fix: Updated aelf-studio documentation

* feat: added gas fees step in playground example

* fix: Reviewed and updated aelf-Studio tutorial

* fix: updated images and steps integration according PR review

---------

Co-authored-by: vasmohi <[email protected]>
  • Loading branch information
RutvikGhaskataEalf and vasmohi authored Oct 17, 2024
1 parent c9cf527 commit 2d8dccf
Show file tree
Hide file tree
Showing 38 changed files with 436 additions and 1 deletion.
263 changes: 262 additions & 1 deletion docs/tools/aelf-playground/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,266 @@ Once all the changes are done in the above files and all other required files (w
![Add a New File](/img/playground-22.png)


### Conclusion
## 4. Example

Now it's time to creat a Todo-dApp using playground.

### Setup Todo Smart Contract Project

- Open [aelf Playground](https://playground.aelf.com) in your browser.

- Select the **`Hello World`** Template.

![playground-example-img-1](/img/playground-example-img-1.png)

- Enter the **"todo-dapp"** Name of a new workspace and Press the **Submit** button.

![playground-example-img-2](/img/playground-example-img-2.png)

- You will be redirect to workspace page with specific folders like **`src`** and **`test`**.

![playground-example-img-3](/img/playground-example-img-3.png)

- Rename the proto file name `hello_world_contract.proto` inside folder `src/Protobuf/contract/` to `todo_app.proto`

![playground-example-img-4](/img/playground-example-img-4.png)
![playground-example-img-5](/img/playground-example-img-5.png)

### Prepare the Todo Functions

The implementation of `todo_app.proto` file inside folder `src/Protobuf/contract/` is as follows:

```csharp title="todo_app.proto"
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.ToDo";
service ToDo {
// The name of the state class the smart contract is going to use to access blockchain state
option (aelf.csharp_state) = "AElf.Contracts.ToDo.ToDoState";
option (aelf.base) = "Protobuf/reference/acs12.proto";
rpc Initialize (google.protobuf.Empty) returns (google.protobuf.Empty) {
}
rpc CreateTask (TaskInput) returns (google.protobuf.StringValue) {
}
rpc UpdateTask (TaskUpdateInput) returns (google.protobuf.Empty) {
}
rpc DeleteTask (google.protobuf.StringValue) returns (google.protobuf.Empty) {
}
rpc ListTasks (google.protobuf.StringValue) returns (TaskList) {
option (aelf.is_view) = true;
}
rpc GetTask (google.protobuf.StringValue) returns (Task) {
option (aelf.is_view) = true;
}
rpc GetInitialStatus (google.protobuf.Empty) returns (google.protobuf.BoolValue) {
option (aelf.is_view) = true;
}
}
// A message to represent a task
message Task {
string task_id = 1;
string name = 2;
string description = 3;
string category = 4;
string status = 5;
string owner = 6;
int64 created_at = 7;
int64 updated_at = 8;
}
// Input for creating a task
message TaskInput {
string name = 1;
string description = 2;
string category = 3;
}
// Input for updating a task
message TaskUpdateInput {
string task_id = 1;
string name = 2;
string description = 3;
string category = 4;
string status = 5;
}
// List of tasks
message TaskList {
repeated Task tasks = 1;
}
```

- `rpc` methods define the callable functions within the contract, allowing external systems to interact with the contract's logic.
- `message` represent the structured data exchanged between the contract and external systems.

#### Define Contract States

The implementation of the ToDo app state inside file `src/todo-dappState.cs` is as follows:

```csharp title="src/todo-dappState.cs"
using AElf.Sdk.CSharp.State;
using AElf.Types;

namespace AElf.Contracts.ToDo
{
public class ToDoState : ContractState
{
public BoolState Initialized { get; set; }
public SingletonState<Address> Owner { get; set; }
public MappedState<string, Task> Tasks { get; set; } // Mapping of task ID to Task
public MappedState<string, bool> TaskExistence { get; set; } // Mapping to track task existence
public StringState TaskIds { get; set; } // Concatenated string of task IDs
public Int32State TaskCounter { get; set; } // Counter for generating unique IDs
}
}
```

- The `State.cs` file in an aelf blockchain smart contract holds the variables that store the contract's data, making sure this data is saved and accessible whenever the contract needs it.

#### Implement ToDo Smart Contract

The implementation of the ToDo App smart contract inside file `src/todo-dapp.cs` is as follows:

```csharp title="src/todo-dapp.cs"
using Google.Protobuf.WellKnownTypes;
using System.Collections.Generic;
namespace AElf.Contracts.ToDo
{
public class ToDo : ToDoContainer.ToDoBase
{
public override Empty Initialize(Empty input)
{
if (State.Initialized.Value)
{
return new Empty();
}
State.Initialized.Value = true;
State.Owner.Value = Context.Sender;
State.TaskIds.Value = "";
State.TaskCounter.Value = 0;
return new Empty();
}
public override StringValue CreateTask(TaskInput input)
{
if (!State.Initialized.Value)
{
return new StringValue { Value = "Contract not initialized." };
}
var taskId = (State.TaskCounter.Value + 1).ToString();
State.TaskCounter.Value++;
var timestamp = Context.CurrentBlockTime.Seconds;
// Create task dictionary entry directly in ToDo class
State.Tasks[taskId] = new Task
{
TaskId = taskId,
Name = input.Name,
Description = input.Description,
Category = input.Category,
Status = "pending",
CreatedAt = timestamp,
UpdatedAt = timestamp,
Owner = Context.Sender.ToString().Trim('"'),
};
State.TaskExistence[taskId] = true;
// Append task ID to the list of IDs
var existingTaskIds = State.TaskIds.Value;
existingTaskIds += string.IsNullOrEmpty(existingTaskIds) ? taskId : $",{taskId}";
State.TaskIds.Value = existingTaskIds;
return new StringValue { Value = taskId };
}
public override Empty UpdateTask(TaskUpdateInput input)
{
var task = State.Tasks[input.TaskId];
if (task == null)
{
return new Empty(); // Handle case if task doesn't exist
}
task.Name = input.Name ?? task.Name;
task.Description = input.Description ?? task.Description;
task.Category = input.Category ?? task.Category;
task.Status = input.Status ?? task.Status;
task.UpdatedAt = Context.CurrentBlockTime.Seconds;
State.Tasks[input.TaskId] = task;
return new Empty();
}
public override Empty DeleteTask(StringValue input)
{
State.Tasks.Remove(input.Value);
State.TaskExistence.Remove(input.Value);
// Remove task ID from the list of IDs
var existingTaskIds = State.TaskIds.Value.Split(',');
var newTaskIds = new List<string>(existingTaskIds.Length);
foreach (var taskId in existingTaskIds)
{
if (taskId != input.Value)
{
newTaskIds.Add(taskId);
}
}
State.TaskIds.Value = string.Join(",", newTaskIds);
return new Empty();
}
public override TaskList ListTasks(StringValue input)
{
var owner = input.Value; // Get the owner value from the input
var taskList = new TaskList();
var taskIds = State.TaskIds.Value.Split(',');
foreach (var taskId in taskIds)
{
var task = State.Tasks[taskId];
if (task != null && task.Owner == owner) // Filter tasks by owner
{
taskList.Tasks.Add(task);
}
}
return taskList;
}
public override Task GetTask(StringValue input)
{
var task = State.Tasks[input.Value];
if (task == null)
{
return new Task { TaskId = input.Value, Name = "Task not found." };
}
return task;
}
public override BoolValue GetInitialStatus(Empty input)
{
return new BoolValue { Value = State.Initialized.Value };
}
}
}
```

### Save Gas Fee

- Click on Save Gas Fee Button and It will suggest to make changes if contract need to be optimised otherwise it shows result like below.

![gas-fees-example-playground](/img/gas-fees-example-playground.png)


### Building Smart Contract

- Click on Build Icon for generate the build.

![playground-example-img-6](/img/playground-example-img-6.png)

- Once Build create successfully, You will get **Build successful** message in terminal.

![playground-example-img-7](/img/playground-example-img-7.png)

### Deploy Smart Contract

- Click on Deploy Icon for deploy the smart contract.

![playground-example-img-8](/img/playground-example-img-8.png)

- Once your smart contract deploy successfully, You will get **Contract Address** in terminal.

![playground-example-img-9](/img/playground-example-img-9.png)

🎉 Congratulations, We got the contract address after successful deployment of todo-dapp smart contract using playground.

## Conclusion
The aelf Playground offers a seamless and accessible platform for developers to build, test, and deploy smart contracts without the need for any local setup. With built-in features like AI audit, gas fee optimization, and GitHub integration, it simplifies the entire smart contract development process. Whether you're writing new code or modifying existing templates, the aelf Playground provides all the essential tools in one place, making it an ideal sandbox for both beginners and experienced developers.
Loading

0 comments on commit 2d8dccf

Please sign in to comment.