Tutorial de Smart Contract CRUD em Solidity com Remix

Web3 e Blockchain

Tutorial de Smart Contract CRUD em Solidity com Remix

Luiz Duarte
Escrito por Luiz Duarte em 31/07/2025
Junte-se a mais de 34 mil devs

Entre para minha lista e receba conteúdos exclusivos e com prioridade

Todas as vezes que comecei a aprender uma nova linguagem de programação, logo depois de escrever o primeiro Olá Mundo, eu inicio um projeto de CRUD. CRUD é uma abreviação para Create, Retrieve, Update e Delete, ou seja, as 4 operações elementares em um sistema de cadastro. E com Solidity não foi diferente, ajudando a descobrir diversas coisas fundamentais desta tecnologia. Neste tutorial de hoje eu vou lhe ensinar como criar um smart contract de CRUD de livros com Solidity e a ferramenta Remix.

Este não deve ser o seu primeiro contato com Solidity ou com Remix, para isso recomendo que tenha feito este tutorial antes.

Se preferir, pode conferir o mesmo conteúdo deste tutorial neste vídeo abaixo.

Vamos lá!

#1 – Criando o Smart Contract

Nosso CRUD vai ser com a temática de livros, como se estivéssemos criando um smart contract global para todos os livros do mundo, algo como um ISBN (International Standard Book Number, o “CPF” dos livros) descentralizado.

Como o Remix aberto, crie um novo arquivo de smart contract  com o nome de BookDatabase.sol e coloque nele a seguinte estrutura inicial, que define a licença do código, a versão do Solidity que usaremos e o nome do contrato.

Repare que estou usando a versão 0.8.30 ou superior, você deve usar a versão mais recente que possuir disponível no seu Remix (você verifica isso na aba Compiler, depois de salvar o arquiv0).

A primeira coisa que quero lhe ensinar a respeito de um CRUD em Solidity é que você deve pensar primeiro na estrutura ou esquema dos dados que vamos precisar. Isso varia enormemente de acordo com o domínio da aplicação que estamos implementando, mas no caso de livros, podemos ter algo como:

  • id: o identificador único do livro;
  • title: o título da obra;
  • year: o ano de publicação;
  • author: o autor do livro;
  • country: o código ISO do país (2 letras);

Você pode criar outros campos conforme quiser, mas podemos seguir com estes neste primeiro momento. Em um contrato Solidity, definimos estruturas de dados através da criação de structs, seja dentro ou fora do contrato. Uma struct segue o seguinte padrão:

Ou seja, temos o nome da estrutura, seu escopo e, dentro dele, cada um dos campos do esquema. Cada livro que criarmos no sistema deverá respeitar todos os campos presentes na struct, ela representa tudo que deve ter em cada livro, entende? Experimente criar os demais campos por conta própria, antes de ver a resposta abaixo.

Claro que não existe uma única resposta possível, mas explico abaixo o porquê de cada decisão:

  • uint256 no id pois ele é um numérico positivo que pode crescer indefinidamente, esse é o maior número que podemos ter no Solidity;
  • string no title e author pois não sabemos o tamanho que ele pode ter;
  • uint16 no year porque permite até o número 65.535, o que é mais do que o suficiente para representar um ano;
  • bytes2 no país pois ele pode ter apenas 2 letras (ISO). Sempre que tiver string de tamanho fixo até 32 bytes (caracteres) e quiser economizar em taxas, use bytes para isso;

Para armazenar todos os livros, podemos usar arrays ou mappings. Essas são estruturas de dados bem comuns em diversas linguagens de programação, embora o nome possa variar levemente. Ambas permitem adicionar elementos, mas a diferença fundamental entre elas é:

  • arrays: use sempre que precisar fazer listagens/enumerações mais facilmente e de preferência com quantidade máxima/limitada;
  • mappings: use sempre que precisar pesquisar por chave/id, sem retrição de quantidade, mas sem possibilidade de enumeração;

No nosso caso vamos criar um mapping de Book, como abaixo, e uma variável auxiliar para ser a contador do id incremental. Optei por usar um mapping, que é como se fosse um array associativo ou dicionário de objetos, mas o termo mais correto seria que um mapping é um hashmap, ou seja: dado um índice definido por você (um id único) ele aponta (map = mapeia) para onde está armazenada uma informação. Esse tipo de estrutura é muito eficiente para busca e inserção.

Repare como disse que o id (uint256) aponta para objeto Book, que é o tipo da struct que definimos antes. Além disso coloquei que nosso mapping books é público, ou seja, pode ser lido por qualquer um na blockchain. Como em Solidity as variáveis de estado são salvas por padrão no storage, basta a declaração acima dentro do escopo do contrato para ter onde salvar os livros definitivamente.

Com isso nosso projeto está pronto para implementarmos as funções do CRUD!

#2 – Cadastrando Livros

A primeira operação do CRUD que vamos fazer é o cadastro. Podemos criar a função pública que adiciona um novo livros com um novo id único, como abaixo.

Como o nosso struct Book não é um tipo primitivo, devemos usar o modificador memory na declaração do parâmetro dele. Isso quer dizer que por parâmetro devemos receber um objeto Book, gerar um id para ele (usando a variável auxiliar), associar este novo id ao novo livro e salvá-lo em nosso mapping com o id sendo a chave e o newBook sendo o valor.

Para testar esta nossa função Solidity nós devemos salvar o arquivo, compilar ele (aba Compile) e então fazer o deploy dele na VM de teste do Remix (Remix VM, na aba Deploy). Não esqueça de selecionar no compilador a mesma versão que especificou no topo do seu contrato.

Após o deploy, você poderá testar o contrato pela interface do Remix, que vai exibir um botão para pesquisar um livro por id (books) e outro para cadastrar um novo livro, mas aqui tem alguns macetes que vou te explicar.

Repare que no input do addBook tem o termo “tuple” (tupla, em Inglês). Isso nada mais é do que um array com os valores de um livro, na exata ordem em que foram definidos na sua struct e separados por vírgula. Os números, as strings e os…bytes? Como passar bytes neste campo? Esta é uma dúvida bem comum entre programadores Solidity iniciantes.

O primeiro passo é você pegar a string que deseja converter para bytes e passar ela em um conversor de hexadecimal, como esse. A string “BR” (sem aspas), vai ser transformada em dois números, 42 e 52, certo? Agora basta montar uma palavra iniciada em 0x e juntar os valores hexadecimais obtidos e voilá, temos o equivalente de um bytes2 em hexadecimal, como na tupla abaixo:

Nesta tupla, estou cadastrando um id 0 (ele vai ser gerado automaticamente), título livro1, autor luiz, ano 2025 e o país BR em hexadecimal. Como dica adicional, recomendo sempre que monte a tupla fora do Remix (no notepad por exemplo) e só cole nele, vai passar menos raiva com aquele campo minúsculo.

Com isso, temos o cadastro de livros finalizado!

#3 – Retornando um Livro

Depois de cadastrar o livro, você pode verificá-lo usando o botão books e informando o id 1. Você receberá como retorno uma tupla com os valores do livro em questão, ou com os valores default para os campos caso pesquise um id que não existe ainda.

Mas de onde saiu esse botão books se não criamos uma função para ler um livro?

O Solidity cria automaticamente pra gente uma função de leitura (view) com o mesmo nome de cada uma das variáveis de estado public que você tiver no contrato. Mais especificamente no caso de arrays e mappings, a função que ele cria espera por parâmetro o index (array) ou key (mapping) e retorna especificamente o valor filtrado, já que retornar todos os elementos poderia significar um problema de performance.

No entanto, caso queira explicitamente criar uma função de retorno de um livro, pode fazê-la como abaixo.

Essa função Solidity é bem simples pois ela espera o id por parâmetro e usa ele como chave no mapping para retornar o Book. Apenas atenção ao fato dela ser view (somente leitura) e que retorna um Book memory, já que não preciso salvar o retorno no storage, ele pode ser em memória.

Com isso finalizamos o R do CRUD!

Curso Web3 para Iniciantes

#4 – Atualizando um Livro

Agora vamos para o U de Update em nosso CRUD. Aqui temos uma complicação que a função de edit vai sempre receber um objeto Book mas nem sempre iremos querer alterar todos os dados de um livro. Sendo assim, devemos criar uma lógica para comparar campo a campo e alterar somente aqueles que mudaram de fato.

Até aí tudo bem, exceto pelo fato de que alguns campos são string. Campos string são um problema em linguagens como C e Solidity pois elas não são tipos primitivos e são armazenadas em memória de um jeito que dificulta a sua comparação direta com o operador “==”. Abaixo proponho uma função simples para comparação de strings que atende bem.

Dadas duas strings, a e b, recebidas em memory, nós convertemos elas para bytes (tipo nativo no Solidity) e comparamos o tamanho das palavras. Se forem de igual comprimento, também geramos um hash com eles, usando a função keccak256 (este é um algoritmo de hashing nativo do Solidity). Se os hashes de ambas forem iguais, quer dizer que são exatamente a mesma palavra. Outra opção é você fazer um for e comparar byte a byte das palavras, mas o hashing atende perfeitamente bem.

Agora que temos a nossa função de comparação de bytes retornando um booleano quando duas palavras forem iguais, podemos criar a nossa função de edição que compara campo a campo para alterar somente aqueles que foram informados e que mudaram em relação aos valores já armazenados.

Primeiro eu faço o carregamento do livro antigo (oldBook) para a memória, a fim de conseguir manipulá-lo mais facilmente. Aí então eu testo, campo a campo, quais devem ser alterados, verificando sempre se ele foi passado no newBook e se mudou em relação ao valor antigo.

Para campos numéricos como o year, basta ver se são maiores que 0 e diferentes do valor antigo.

Para campos bytes como o country, podemos verificar o comprimento e se são diferentes, diretamente, assim como fizemos com os números.

Agora para campos string, devemos primeiro verificar se foram passados (string vazia tem comprimento 0, logo a comparação vai dar false) e por fim a comparação dos valores antigos com os novos. No final de tudo, a atribuição por cima do registro antigo usando o mesmo id no mapping.

Salve, compile, faça um novo deploy. No novo deploy, faça o mesmo cadastro que fizemos antes e depois faça uma edição. Você vai reparar que na edição temos dois parâmetros: primeiro deve passar o id do livro a ser editado, e depois a tupla (array) com os parâmetros que deseja passar, sendo que deve passar TODOS os parâmetros da struct, assim como fazemos no cadastro, mas pode passar valores default nos campos que não deseja alterar que eles serão ignorados por nossa função. Exemplo abaixo, onde quero alterar apenas o país (última posição da tupla) do livro de id 1 (primeiro parâmetro) para “US” (código 0x5553 em hexa):

Depois de testar a função editBook, use o botão books para testar se o livro foi realmente alterado conforme esperado.

E com isso finalizamos o U do CRUD!

#5 – Excluindo um Livro

Agora vamos para a quarta e última operação do CRUD: o D de Delete. Essa função fica bem simples, como abaixo:

A keyword delete não excluir realmente um elemento do mapping, mas na verdade adiciona os valores default a cada um dos campos do elemento em questão.  Não existe uma exclusão real em mappings Solidity.

Quer aprender como fazer deploy deste Smart Contract na Blockchain? Leia este tutorial.

Agora se estiver buscando aprender a criar algo mais complexo, recomendo este tutorial com o toolkit HardHat.

E se quiser aprender a reduzir o consumo de gás nos seus smart contracts, este é o artigo certo.

Até mais!

 

 

TAGS:

Olá, tudo bem?

O que você achou deste conteúdo? Conte nos comentários.

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *