WEB3DEV

Dione Bastos
Dione Bastos

Posted on

Criando um to do list com solidity

Esse artigo foi escrito por Dione Bastos.

É muito comum criarmos para nosso portifólio um projeto de to do list, que é uma pequena lista de afazeres onde você pode criar, apagar e editar alguma tarefa. Entretanto também é muito comum utilizar alguma linguagem da web2 parar isso, como por exemplo, o Javascript.

Nesse tutorial irei lhe explicar como criar um to do list utilizando contratos inteligentes, e iremos utilizar o solidity para isso. Lembrando que não apagaremos nenhuma tarefa, para manter a magia da imutabilidade 😉.

Se você ainda não conhece o solidity, vou lhe dar uma breve introdução, porém encontram-se no site excelentes artigos utilizando a linguagem.

O solidity é uma linguagem de programação de alto nível para Smart Contracts, mais especificamente voltados a rede Ethereum, ele também é compilado, já que a EVM reconhece apenas bytecodes. Para utilizarmos ele, recomendo usar o Remix IDE, nele poderemos escrever contratos em solidity com um ambiente simples e de fácil implantação.

A primeira coisa a fazer é criar um arquivo no remix que chamaremos de TodoList.sol. Basta clicar com o botão direito na pasta de contracts e depois criar um arquivo novo.

Image description

Iremos construir tudo passo a passo, então comece com a estrutura básica do contrato:


// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;

contract TodoList {

}
Enter fullscreen mode Exit fullscreen mode

A primeira linha refere-se a licença que nosso sistema tem, no caso como é um algoritmo de teste, deixei como UNLICENSED (sem licença). Logo em seguida precisamos informar a versão do compilador pragma que será utilizado para compilar o solidity para bytecode.

Agora adicione isso:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;

contract TodoList {
    struct Todo {
        string message;
        bool done;
    }

    Todo[] public todos;

    function add() public {}

    function edit() public {}

    function getTodo() public view {}
}
Enter fullscreen mode Exit fullscreen mode

Note que adicionamos um struct que exigirá que nossa lista siga uma tipagem pré-definida. Também inicializamos um array que servirá para adicionar nossa lista de tarefas.

struct Todo {
  string message;
  bool done;
}

Todo[] public todos;
Enter fullscreen mode Exit fullscreen mode

Depois criaremos a base para as funções:

function add() public {}

function edit() public {}

function getTodo() public view {}
Enter fullscreen mode Exit fullscreen mode

A primeira função add servirá para adicionar algo escrito por um usuário externo, por isso é do tipo public. A segunda tem função de editar o conteúdo da lista de tarefas e ela também é do tipo public. Por fim precisamos criar uma função que retornará o que foi adicionado na lista de tarefas, para isso precisamos utilizar uma função do tipo view, que apenas retorna os dados.

Agora que temos nossa estrutura básica iremos informar os parâmetros das funções e sua lógica, começaremos com a função add:

function add(string calldata _message) public  {
   todos.push(Todo({
      message: _message,
      done: false
   }));
}
Enter fullscreen mode Exit fullscreen mode

Ela irá receber um parâmetro, que será a descrição da nossa tarefa. Na função precisamos popular o array todos, para isso usamos um método conhecido por push, que serve para adicionar um elemento dentro do array. Iremos adicionar o valor: message e setar o done como false, pois ainda não temos nenhuma tarefa.

function edit(uint _index, string calldata _message) public {
  Todo storage todo = todos[_index];
  todo.message = _message;
}
Enter fullscreen mode Exit fullscreen mode

Na função edit iremos receber dois parâmetros, um _index e o _message, o primeiro será o identificador da nossa tarefa e o segundo a tarefa em si. Irei utilizar o storage para o index, ele precisa ser persistente, ao contrário do

Antes de ir mais a fundo no exemplo, note que utilizamos três tipos de armazenamento, irei dar uma breve descrição de cada:

  • Memory - É um tipo de armazenamento em cache, no solidity um dado salvo em memória só existe enquanto aquela função é utilizada. Ela pode ser declarada como parâmetro e também pode ser usada na lógica interna de uma função. Ela também é do tipo mutável, quer dizer que seu valor pode ser alterado enquanto a função estiver sendo utilizada.

  • Calldata - Ela é bem semelhante ao memory. A diferença é que ela é do tipo imutável (não pode ser alterada) e é utilizada apenas como parâmetro de uma função externa (não pode ser usada na lógica interna). Ambas memory e calldata são excluídas quando o objetivo da função é concluído.

  • Storage - Já a storage tem o mesmo proposito das anteriores. O que muda é que ela é uma memória persistente (é armazenada na blockchain) e mutável (pode ser alterada).

Para informações mais detalhadas, acesse esse vídeo onde o Yan Luiz explica cada detalhe sobre os tipos de armazenamento com Solidity.

A próxima função é o getTodo, que irá retornar para nós a tarefa escolhida:

function getTodo(uint _index) public view returns (string memory, bool) {
     Todo memory todo = todos[_index];
     return (todo.message, todo.done);
}
Enter fullscreen mode Exit fullscreen mode

Note que essa função é do tipo view, então somente me retorna dados da blockchain.

Nessa função preciso informar o id da minha tarefa como parâmetro, de retorno eu recebo a mensagem e o status da tarefa:

return (todo.message, todo.done);
Enter fullscreen mode Exit fullscreen mode

Além das 3 funções acima, adicionei uma nova que servirá de toggle de status da nossa tarefa:

function toggleDone(uint _index) public {
   Todo storage todo = todos[_index];
   todo.done = !todo.done;
}
Enter fullscreen mode Exit fullscreen mode

Ela apenas identifica a tarefa correta e troca o valor de falso para true ou true para falso, na nossa variável done:

todo.done = !todo.done;
Enter fullscreen mode Exit fullscreen mode

Na integra seu código estará assim:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;

contract TodoList {
    struct Todo {
     string message;
     bool done;
    }

 Todo[] public todos;

 function add(string calldata _message) public  {
    todos.push(Todo({
      message: _message,
      done: false
    }));
 }

 function edit(uint _index, string calldata _message) public {
    Todo storage todo = todos[_index];
    todo.message = _message;
 }

 function getTodo(uint _index) public  view returns (string memory, bool) {
    Todo memory todo = todos[_index];
    return (todo.message, todo.done);
 }

 function toggleDone(uint _index) public {
    Todo storage todo = todos[_index];
    todo.done = !todo.done;
 }

}
Enter fullscreen mode Exit fullscreen mode

Agora iremos compilar nosso código e testar as funções, para isso utilize a versão compatível a que você informou no código. Se o símbolo do compilador estiver verde é porque seu código está pronto para o deploy:

Image description

O próximo passo é efetuar o deploy do seu contrato, para isso clique em Deploy & run transactions, depois verifique o arquivo correto e clique em Deploy:

Image description

Vamos criar uma tarefa:

Image description

Note que a função foi executada com sucesso:

Image description

Para obter a tarefa, basta chamar a função getTodo, lembre-se de passar no parâmetro o index, que é o valor referente ao id da tarefa, como a tarefa foi a primeira a ser criada e ela funciona utilizando vetores, bastar passar como parâmetro o primeiro índice do vetor, que no caso é 0(zero):

Image description

Para editar a tarefa também é muito simples, para isso iremos utilizar a função edit, passando como parâmtro o id (index do vetor) e a descriçao da tarefa (message):

Image description

Agora que criamos e editamos a tarefa ainda nos resta definir a tarefa como concluída ou não, para isso utilizo a função de toggle que irá apenas inverter o valor de false da minha variável done para true:

Image description

Que demais, nossa lista de tarefas está funcionando perfeitamente 🤩.

Lembre-se que um to do list em blockchain pode não ser tão interessante, às vezes algumas aplicações não necessitam utilizar a tecnologia do blockchain, mas para efeitos de informação agora você sabe o quão divertido pode ser os smart contracts.

Latest comments (0)