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.
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 {
}
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 {}
}
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;
Depois criaremos a base para as funções:
function add() public {}
function edit() public {}
function getTodo() public view {}
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
}));
}
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;
}
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). Ambasmemory
ecalldata
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);
}
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);
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;
}
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;
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;
}
}
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:
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
:
Vamos criar uma tarefa:
Note que a função foi executada com sucesso:
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):
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):
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:
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)