Contratos Inteligentes: o guia do mochileiro dos protocolos

Lucas Vieira
Block3 Research
Published in
21 min readMay 13, 2022

Para falar de protocolos de contratos inteligentes (os famosos Smart Contracts) precisamos falar sobre Ethereum, que é uma plataforma descentralizada que usa tecnologia em Blockchain onde é possível subir programas (pedaços de código executáveis, que é o que são os contratos inteligentes) e armazenar dados. Para fazer isso funcionar, a Ethereum faz uso de um único computador chamado EVM (Ethereum Virtual Machine) em que todos da rede concordam com seu atual estado. Todo nó que participa da rede Ethereum (pense em nó como um computador qualquer) guarda uma cópia do estado da EVM. E todos os participantes da rede podem fazer requests para a EVM para performar qualquer tipo de computação arbitrária. Essas requisições são chamadas de transactions e elas causam uma mudança de estado na EVM, que é propagada por todos os nós (cópias do estado da EVM) da rede.

Qualquer desenvolvedor pode criar um contrato inteligente, fazer o deploy e torná-lo público na rede (usando a Blockchain como sua camada de dados) para construir múltiplos tipos de aplicativos e serviços. Contratos inteligentes podem ser escritos usando linguagens de programação (sendo Solidity a mais usada) específicas que compilam um código binário (instruções de baixo nível) o qual humanos não entendem, mas computadores sim e com baixo esforço. Além disso, qualquer usuário da rede poderá fazer chamadas para o contrato e executar seu código.

Para facilitar esse uso em ambos os lados (tanto dos desenvolvedores quanto dos usuários) a comunidade adotou uma série de protocolos e padrões. Protocolos são vastamente usados em todo tipo de tecnologia (e em várias outras áreas), nos ajudando a manter projetos (e todo tipo de conhecimento) integráveis a todo tipo de implementação, seguindo boas práticas e com tempo de desenvolvimento menor. Normalmente eles são introduzidos através de EIPs (Ethereum Improvement Proposals) que são discutidos pelos membros da comunidade através de um processo de padronização. Existem 3 tipos de EIPs:

  • Standards Track EIP que descrevem qualquer mudança que afete quase ou todas as implementações na rede Ethereum. Eles podem ser divididos em categorias que tem melhorias relacionadas (Core, Networking, Interface e ERC).
  • Meta EIP que descrevem processos secundários a rede Ethereum ou a mudança em algum desses processos.
  • Informational EIP que descrevem algum problema de design na rede ou fornecem guias gerais para a comunidade Ethereum.

Nesse post iremos focar nos ERCs (Ethereum Requests for Comment), uma Standard Track EIP, que se refere a protocolos e convenções a nível de aplicação. Muitos ERCs são amplamente usados no ecossistema Ethereum como o ERC-20, ERC-721, ERC-777 e ERC-1155. A seguir nós vamos dar uma visão geral, discutir as diferenças e a maneira de usar esses e outros úteis protocolos. Aqui tem uma lista atualizada com todas as propostas de protocolos ERC. Para usar os protocolos nós podemos tanto escrever o código das funções, eventos e variáveis por conta própria, seguindo os nomes e convenções definidos pela comunidade ou usar alguma das famosas bibliotecas já implementadas como a do OpenZeppelin, Dappsys ou HQ20.

Nota: Um ponto importante para se ter em mente é que apesar do uso de protocolos e padrões ser extremamente útil para a comunidade, algumas regras não estão cravadas em pedra. O desenvolvedor do contrato pode e deve definir outras funções ou até sobrescrever funções existentes para lidar com funcionalidades específicas e atender os critérios de seu produto. A parte importante é saber quais regras são necessárias para se beneficiar corretamente da compatibilidade com outros serviços. Se essas regras forem satisfeitas, está tudo certo!

ERC-20

ERC-20 é o Token Standard. Mas o que é um token? É uma representação digital de praticamente qualquer coisa na rede. Pode ser um bilhete de loteria, um ativo financeiro, uma moeda fiduciária, habilidades do personagem de um jogo e mais infinitas possibilidades. Esse protocolo nos auxilia a construir aplicações que são compatíveis com outros produtos e serviços que também usam tokens e tecnologia blockchain. Nesse caso nós estamos lidando com os chamados Fungible Tokens, que são tokens que são exatamente iguais uns aos outros (em tipo e valor). Por exemplo, se eu tiver 1 token e você tiver 1 token, nós dois temos exatamente a mesma coisa. Por exemplo, ETH e BTC são fungible tokens. Entre as funcionalidades desse protocolos temos:

  • Transferir tokens de uma conta para outra.
  • Retornar o saldo de uma conta.
  • Retornar a quantidade total de tokens disponíveis na rede.
  • Aprovar quando uma quantidade de tokens de sua conta puder ser gasto por uma outra conta.
ERC-20 Interface

As 3 primeiras funções são auto explicativas, a primeira para transferir _value tokens de sua conta para o endereço _to (que pode ser uma outra carteira ou até um contrato inteligente). A duas seguintes são funções do tipo view, ou seja, funções de leitura que apenas retornam o valor de algum parâmetro (não fazem alterações no estado da blockchain) no caso o saldo de uma conta e o total de tokens disponíveis na rede. As restantes fazem parte do fluxo de permissão a contas terceiras. A função approve permite que o endereço da variável _spender faça quantas retiradas quiser da sua conta até o valor total contido na variável _value. A função allowance retorna o total que o endereço _spender pode retirar da conta do endereço _owner. E a função transferFrom por sua vez é quem permite o endereço terceiro a fazer retiradas da conta _from para a _to.

Esse protocolo abriu portas para a criação de muitos tokens e temos alguns exemplos famosos de tokens que foram construidos seguindo o protocolo ERC-20 como o BAT (contrato), BNB (contrato), LINK (contrato), USDT (contrato) e a lista continua…

A implementação do protocolo feita pelo OpenZeppelin pode ser encontrada aqui.

ERC-777

ERC-777 é também um protocolo de Fungible Tokens e foi criado para trazer melhorias ao protocolo ERC-20 existente. Ele nos oferece algumas funcionalidades mais avançadas para lidarmos com os tokens. É possível definir operadores para enviar tokens em nome de outro endereço (carteira ou contrato) e o envio de gatilhos (hooks) para notificar ou fazer alguma ação após o envio e/ou recebimento de tokens, dando aos donos mais controle sobre seus tokens. Entre as vantagens do uso desse protocolos temos:

  • Podemos passar um atributo data quando transferimos tokens, similar ao Ether.
  • Tanto contratos quanto endereços de carteiras normais podem controlar e rejeitar qual token eles enviam ou recebem através do registro de hooks.
  • Os gatilhos nos permitem enviar tokens para um contrato e notificar numa única transação, diferentemente do protocolo ERC-20 que precisava de uma dupla chamada das funções approve e transferFrom.
  • O dono pode autorizar e revogar quais operadores podem enviar tokens em seu nome.
  • Toda transação contém campos do tipo byte data e operatorData que podem ser usados livremente para que o dono e o operador, respectivamente, possam fazer o envio de dados ao endereço destino.

Esse protocolo é compatível com versões anteriores, ou seja, podemos interagir com contratos que usam o protocolo ERC-777 da mesma maneira que interagimos com contratos que usam o protocolo ERC-20. Por razões de compatibilidade, quando interagimos com algum contrato ERC-777 todas as quantidades e saldos devem ser inteiros positivos, podemos usar o tipo uint256. Além disso, para exibição dos valores armazenados internamente, eles devem ser sempre divididos por 10¹⁸ . Por exemplo, se um contrato retorna um saldo de 500.000.000.000.000.000 para uma conta, a interface deve exibir 0,5 tokens como saldo da conta. Isso segue o mesmo comportamento do wei e Ether, em que 1 Ether = 10¹⁸ wei. Essa implementação pode seguir o mesmo padrão da função opcional decimals do protocolo ERC-20 retornando 18 quando chamada.

Além disso, um contrato que adota o protocolo ERC-777 precisa que implementar as funções de leitura opcionais da interface de metadados do ERC-20 name e symbol e as obrigatórias totalSupply e balanceOf. Mas também uma nova função de leitura precisa ser adotada, a granularity. Essa função retorna a menor parte não divisível de um token. Ou, em outras palavras, a menor quantidade de tokens que podem ser mintados, transferidos ou destruídos a qualquer momento.

Nós devemos seguir as seguintes regras a respeito da granularidade:

  • Ela precisa ser setada no momento de criação do contrato.
  • Ela não pode ser alterada, nunca.
  • Ela precisa ser maior ou igual a 1.
  • Todos os saldos precisam ser um múltiplo da granularidade.
  • Qualquer quantidade de tokens mintados, transferidos ou destruídos precisa ser um múltiplo da granularidade.
  • Qualquer operação que resulte em um saldo que não é um múltiplo da granularidade precisa ser revertida.

Como comentamos anteriormente, um operador é um endereço que pode transferir e destruir tokens atrelados a outro endereço. A seguir temos o formato e nomenclatura propostos para as funções atreladas a essa funcionalidade.

Para autorizar e revogar as permissões de um operador temos as funções authorizeOperator e revokeOperator. E temos as funções de leitura isOperatorFor que retorna um boolean dizendo se aquele endereço é um operador de outro e temos a função defaultOperators que nos diz se um endereço é ou não um operador pré-definido. Mas o que é um operador pré-definido? São operadores que estão implicitamente autorizados a operar por qualquer endereço. Mas para tê-los é preciso seguir algumas regras:

  • Precisam ser definidos na criação do contrato.
  • Precisam ser invariantes, o contrato não pode adicioná-los ou remove-los, nunca.
  • O dono dos tokens deve poder revogar a permissão do operador.
  • O dono dos tokens deve poder re-autorizar uma permissão previamente revogada a um operador.

Nota: Os donos dos tokens podem ter múltiplos operadores simultaneamente.

Para lidar com a transferência de tokens, as funções implementadas devem ter o seguinte formato:

E as seguintes regras devem ser respeitadas:

  • Qualquer operador autorizado pode transferir tokens para qualquer endereço (exceto 0x0).
  • O saldo do dono dos tokens deve reduzir do valor amount.
  • O saldo do endereço que recebe os tokens deve incrementar do valor amount.
  • O saldo do dono dos tokens deve ser igual ou maior ao valor amount.

Minting é o ato de emitir novos tokens. Esse protocolo não oferece nenhuma função específica para fazer o mint. Isso porque essa lógica normalmente é bem específica em relação a cada token e poderia gerar uma limitação ao uso e adoção do protocolo. Mas seguintes regras precisam ser seguidas em relação ao mint:

  • O total de tokens da rede retornado pela função totalSupply deve ser incrementado do número de tokens mintados.
  • O saldo do endereço que receber o mint deve ser incrementado do número de tokens mintados.

Burning é o ato de destruir tokens existentes. Esse protocolo define funções para que o dono dos tokens e os operadores possam detruir os tokens. As mesmas regras do mint devem ser seguidas com a diferença de que agora temos uma redução do saldo e do total de tokens.

Nós comentamos no início que este protocolo dispunha de funcionalidades relacionadas ao uso de gatilhos. Mas como isso funciona? Temos a definição de duas funções tokensToSend e tokensReceived das interfaces ERC777TokensSender e ERC777TokensRecipient, respectivamente.

Essas funções devem ser definidas do lado dos endereços (contratos ou contas regulares) que quiserem ser notificados quando houver créditos ou débitos de seus endereços. Mas como o meu contrato ERC-777 vai saber se esses endereços dos tokens que estão sendo incrementados/decrementados possuem essas funções implementadas? Para isso é usada a função setInterfaceImplementer de um outro protocolo, o ERC-1820. Esse protocolo define um registro universal onde qualquer endereço (contrato ou conta regular) possa registrar qual interface ele suporta e qual contrato é responsável por essa implementação.

Dessa forma é obrigatório que qualquer contrato ERC-777 se registre usando a função setInterfaceImplementer assim como os endereços que desejarem usar os gatilhos para serem notificados. Algumas regras acerca do uso dos gatilhos:

  • O gatilho tokensToSend deve ser chamado sempre que houver uma transferência ou destruição de tokens e deve ser chamado antes que o estado seja atualizado, ou seja, antes que o saldo seja decrementado.
  • O gatilho tokensReceived deve ser chamado sempre que houver uma transferência ou mint de tokens e deve ser chamado depois que o estado for atualizado, ou seja, depois que o saldo for incrementado.

Entre os exemplos de serviços implementados usando o protocolo ERC-777 temos pNetwork (contrato) e Superfluid (contrato).

A implementação de referência do protocolo pode ser encontrada aqui. E a implementação do OpenZeppelin aqui.

ERC-721

ERC-721 é o protocolo de Non-Fungible Tokens (NFTs). Como discutimos anteriormente, um token é uma representação digital de praticamente qualquer ativo na rede. Mas diferentemente de um fungible token, o NFT é usado para identificar algo ou alguém de maneira única. Então, se no caso do fungible token quando eu e você tivessemos 1 token teríamos a mesma coisa, no non-fungible se eu e você tivéssemos 1 token teremos coisas diferentes com diferentes tipos e valores, mesmo que tenham vindo do mesmo contrato inteligente.

Esse tipo de token é usado para representar itens colecionáveis, chaves de acesso, artes digitais, assinaturas, programas de fidelidade, assentos numerados para shows e muito mais! NFTs podem representar propriedade digital sobre ativos tanto digitais quanto físicos (propriedades imobiliárias, por exemplo). NFTs são distinguíveis e você deve mapear os proprietários de cada token separadamente.

Como nos protocolos anteriores temos funcionalidades para fazer a transferência de tokens de uma conta para outra,

para aprovar que uma quantidade de tokens de uma conta possa ser transferida para outra por uma terceira

Nota: a diferença entre approve e setApprovalForAll é que na primeira você garante permissão que um endereço seja o operador de um dos seus NFTs e a segunda para todos. A mesma lógica se aplica para as funções de leitura relacionadas. Retornando quem pode operar por um NFT específico e se algum endereço pode operar por todos.

e para retornar o saldo de tokens de uma conta, com a novidade de uma função para retornar qual conta é dona de um token específico.

Existem outras interfaces do protocolo ERC-721 que o uso é opcional mas que, na prática, são extremamente importantes caso você queira criar um contrato de NFT para produção. A primeira é a interface de metadados ERC721Metadata, que pode ser integrada através da implementação de 3 funções de leitura:

Precisamos dar uma atenção a última função, tokenURI. Essa função recebe um _tokenId como parâmetro e retorna uma string, que é a URI (Uniform Resource Identifier, aquilo que escrevemos na caixa de texto de um navegador para acessar algo dentro de um site. https://medium.com/ é uma URL e https://medium.com/@lucasdvieira é uma URI) relacionada a aquele token específico. Nessa URI são armazenados os metadados do token que normalmente tem o seguinte formato:

Nota: normalmente esses JSONs dos metadados e as imagens relacionadas a eles são armazenados no IPFS (InterPlanetary File System), que é um sistema de arquivos descentralizado que armazena dados usando tecnologia Blockchain. A maioria dos projetos de NFT usam esse sistema para armazenar o grosso dos dados do projeto já que armazená-los diretamente numa Blockchain como a rede Ethereum seria absurdamente caro (até o dia que esse post esta sendo escrito). Assim, o IPFS surge como uma mão na roda para solucionar esse problema, sem ter a necessidade de armazenar essa informação de uma maneira centralizada, como por exemplo usando serviços como o AWS S3. Observe que a imagem tem uma URI apontando para um Pinata Gateway. Que é um gateway dedicado (só seu serviço vai usar) para armazenar os dados. Por experiência própria posso dizer que é muito útil para projetos em produção, fazer o retorno dos seus dados ser muito mais rápido e confiável.

Os metadados são úteis para que serviços terceiros (como Marketplaces de NFTs) possam entender e ler o conteúdo dos seus NFTs sem precisar de nenhuma integração específica. Então, se você seguir esse padrão, todos os marketplaces vão ser capazes de exibir e interagir com seus tokens. Aqui você pode encontrar a documentação do padrão para os metadados fornecida pelo OpenSea.

Outra importante (mas também opcional) interface é a de numeração ERC721Enumerable, que permite que o contrato e os donos publiquem sua lista completa de NFTs e os tornem detectáveis.

Tem algumas bibliotecas famosas como a do OpenZeppelin ERC721Enumerable mas eu recomendo fortemente que você não a use para evitar ter custos exorbitantes de gas no seu contrato. Você pode encontrar mais detalhes sobre isso nesse post incrível feito pelo Chance Strickland. Então arregace suas mangas e vá codificar essa lógica você mesmo! Você pode usar o OpenZeppelin Counters Utility ou ler esse ourtro post para ajudar nesse processo.

Nota: você pode notar que a emissão (minting) e destruição (burning) de tokens não estão incluídas nessa especificação. Então cabe a você implementá-las! O minting é uma funcionalidade extremamente importante para a maioria dos projetos de NFT, construa ela com carinho. E lembre-se: quanto mais eficiente ela for, menos gás os usuários vão precisar gastar. Tornando seu projeto mais atrativo. Você também pode incluir outras funcionalidades como pausa e resumo do contrato, listas de acesso (whitelist) e bloqueio ao mint, saque dos fundos do contrato, pré -venda/venda pública e por ai vai!

Tem muitos projetos por ai que foram construídos usando o protocolo ERC-721, entre eles: CryptoKitties (contrato), Decentraland (contrato),CryptoPunks (contrato), Ejin Coin (contrato) e a lista é enorme.

ERC-1155

ERC-1155 é o protocolo dos Multi-Tokens. Com essa interface os contratos podem representar fungible, non-fungible ou ambos tipos de token. Então o ERC-1155 pode executar as funções tanto do ERC-20 quanto do ERC-721. E o melhor de tudo, melhorando a funcionalidade em ambos os tipos, o tornando mais eficiente, com custos de gás mais baixos e corrigindo alguns erros dos protocolos anteriores. Entre a melhoria nas funcionalidades temos a possibilidade de trabalhar com batches, como a possibilidade de transferir múltiplos tokens simultaneamente, economizando custos nas transações.

Ainda temos uma função para tranferência de um único token para manter compatibilidade com os protocolos anteriores, mas também temos a opção de usar a função em batches. A diferença é que no formato de batches recebemos arrays nos parâmetro _ids e _values. Então vamos supor que temos _ids=[2, 4, 7] e _values=[20, 30, 40], o que acontece é que tranferimos 20 tokens de id 2, 30 tokens de id 4 e 40 tokens de id 7 de um endereço para o outro. Da mesma maneira, temos duas funções para retornar o saldo de token de um ou múltiplos endereços.

As aprovações nesse protocolo seguem um comportamento diferente. É tudo ou nada. Ou um terceiro endereço tem a permissão para operar todos os NFTs ou não tem nenhuma permissão. É feito assim para manter a simplicidade.

Para habilitar o uso de metadados no protocolo ERC-1155, é preciso implementar a função uri.

Nota: o arquivo contido na URI retornada pela função precisa seguir o formato do ERC-1155 Metadata URI JSON Schema.

O protocolo por si só não tem uma função de mint pré-definida. É preciso que você a implemente de acordo com a lógica necessária para o seu produto. Como comentado, você pode usar esse protocolo para ter tokens fungíveis, não fungíveis ou ambos simultaneamente. E as funções de mint são o caminho para permitir isso, dessa maneira você passa além do id do token a ser mintado como também um amount para setar quantos tokens daquele id vão ser criados. Se esse valor for 1, esse token será único e consequentemente um NFT. Você pode conferir como essa e outras funções do protocolo foram implementadas pelo OpenZeppelin nesse link. Recomendo muito este post do Jeffrey Scholz mostrando uma maneira super eficiente de fazer mints e transferências com o protocolo ERC-1155.

Entre os casos reais que implementam o ERC-1155 nós temos o Adidas Token (contrato), Sandbox (contrato), Town Star (contrato), Ragnarok (contrato) e muitos outros.

Esses 4 protocolos descritos acima são sem dúvida os mais amplamente usados pela comunidade. Mas além deles também temos outros importantes e úteis protocolos que auxiliam muitos desenvolvedores, usuários e a própria comunidade a seguir padrões, boas práticas e a construir projetos cada vez mais integráveis.

ERC-137

ERC-137 é o protocolo do Ethereum Name Service (ENS). Ele descreve uma proposto de protocolo e formato de ABI (Application Binary Interface) que nos fornece nomes que humanos conseguem ler para serviços e endereços de recursos. Isso não só nos dá uma maneira prática de compartilhar sua carteira e seu contrato mas também permite que esses nomes sejam atualizados sempre que o recurso relacionado precisar realizar alguma mudança. Isso faz com que um endereço como 0x802ED31AC2B279C70f4d2f66eE23E3f470c8768b possa ser acessado usando algo como cool.wallet. O sistema ENS é dividido em três partes principais:

  • ENS Registry
  • Resolvers
  • Registrars

O ENS Registry é um único contrato inteligente que nos fornece um mapeamento de qualquer nome registrado ao endereço responsável e permite que o dono desse nome configure o endereço relacionado a ele e crie subdomínios, que normalmente estão relacionados a um endereço diferente ao do domínio principal. Os Resolvers são responsáveis por performar buscas pelo endereço correlacionado a um nome. E por fim, todo dono de um nó do ENS é um Registrar, que é responsável por alocar nomes de domínio aos usuários do sistema.

Os nomes de domínio consistem de uma série de rótulos separados por pontos. Esses rótulos podem ser de qualquer tamanho, mas por questão de compatibilidade com DNS antigos, é recomendado que sejam limitados a 64 caracteres. E o nome completo do domínio a 255. Também é recomendado que não comecem ou terminem com hífen e não comecem com dígitos.

ERC-4626

ERC-4626 é o protocolo de Tokenized Vaults. Esse protocolo nos define padrões para a implementação de tokenized vaults (cofres de tokens) que podem representar shares de um token ERC-20, nos provendo funcionalidades para depositar tokens, sacar tokens e ler saldos. Os protocolos DeFi surgiram com o conceito de "yield farming" e evoluíram para "yield aggregators", "vaults" e "lending markets". Mas esses conceitos sofriam de uma falta de padronização o que levava a detalhes de implementação diversos, fazendo a integração com os serviços muito difícil e sucetível a erros. Esse protocolo busca solucionar esse problema, o que pode potencialmente dar combustível para a nova onda de DeFi, como podemos ver nesse post do Sujith Somraaj.

Os contratos que implementarem token vaults com o ERC-4626 precisam também implementar o ERC-20 para representar as ações dos ativos do cofre e o opcional de metadados desse mesmo protocolo para ter acesso as funções name e symbol. O cofre pode ser não transferível, nesse cenário ele pode reverter as chamadas para as funções transfer e transferFrom. Vamos definir abaixo suas principais definições:

  • Asset: o token gerenciado pelo cofre (como BNB para o PancakeSwap).
  • Share: o token do cofre (como CAKE para o PancakeSwap).
  • Fee: quantidade de assets ou shares cobradas ao usuário pelo cofre.
  • Slippage: diferença entre o preço exibido da share e a realidade econômica no depósito e retirada de fundos do cofre, que não são contabilizadas pelas taxas.

Nota: esse protocolo foi desenvolvido para ser otimizado para integrações, promovendo funcionalidades completas porém com a mínima interface possível. Detalhes como contabilidade e alocação de tokens depositados não são, intencionalmente, especificadas aqui. Inspecione a implementação do serviço antes de usá-lo!

ERC-1363

ERC-1363 é o protocolo do Payable Token. Esse protocolo nos fornece uma maneira de executar um código após um ERC-20 transfer ou approval. Anteriormente, para executar uma ação depois de você ter recebido ou enviado tokens com sucesso, você precisaria de um listener (uma função que escuta a um evento) e outra transação, pagando o dobro de gás. Esse tipo de lógica pode ser útil em vários cenários:

  • Token Crowdsale
  • Venda de serviços por tokens
  • Pagamento de faturas
  • Planos de assinatura

ERC-165

ERC-165 é o protocolo de Interface Detection. É um protocolo extremamente importante porque ele contém a lógica para integrar corretamente contratos escritos em diferentes protocolos mas que podem operar o mesmo papel como ERC-721 e ERC-1155. Ele contém métodos para publicar e detectar quais interfaces um contrato inteligente implementa. Isso é feito através da padronização dos seguintes pontos:

  • Como as interfaces são definidas
  • Como um contrato pode publicar as interfaces que ele implementa
  • Como detectar se um contrato implementa o ERC-165
  • Como detectar se um contrato implementa qualquer interface

ERC-2981

ERC-2981 é o protocolo de NFT Royalty. Esse protocolo contém funcionalidades para retornar a informação relacionada ao pagamento de royalties de NFTs para habilitar suporte universal para esse pagamento em todos os marketplaces de NTF e participantes do ecossistema. Então ele permite que contratos que implementem o ERC-721 e ERC-1155 a configurem o percentual de royalty a ser pago em cada venda secundária do NFT para o criador ou para seus proprietários legais. Marketplaces e outros serviços podem consultar essa informação através da seguinte função:

ERC-3156

ERC-3156 é o protocolo de Flash Loan. O flash loan (ou "empréstimo rápido") é uma transação em que um contrato lender empresta ativos a um outro contrato borrower com a condição que esses ativos sejam retornados com uma taxa adicional em uma única transação. O protocolo implementa uma interface em que os lenders possam aceitar requisições de flash loans e para que os borrowers possam tomar controle temporário dessa transação. Assim os contratos podem emprestar uma quantidade de ativos sem precisar de um collateral. Um collateral é uma garantia para operações de crédito ou empréstimo para que duas partes possam efetuar uma transação com segurança. No caso de tokens, são usados os próprios tokens como collateral para garantir segurança numa transação de empréstimo de outros tokens.

Então os flash loans nos permitem fazer esse empréstimo sem a necessidade de um collateral, contanto que os ativos sejam retornados com uma taxa adicional na mesma transação. As implementações podem e devem seguir diferentes abordagens de alto nível na forma como eles implementam sua lógica usando esse protocolo, entre elas:

  • Diferentes abordagens de pagamento no fim da transação. Em alguns casos o ativo e as taxas são retiradas automaticamente de quem recebe o empréstimo. Em outras cabe a quem recebe o empréstimo manualmente fazer esse retorno.
  • Alguns provedores fornecem a possibilidade de fazer o pagamento do empréstimo com um token diferente do que foi emprestado, o que pode reduzir complexidade geral no processo e incorrer menores custos com gás.

Quem faz o empréstimo no flash loan deve implementar a interface IERC3156FlashLender.

A função maxFlashLoan deve retornar o empréstimo máximo para um token. Se o token não for suportado deve retornar 0 ao invés de reverter a transação. A flashFee deve retornar a taxa cobrada no empréstimo de uma quantidade de um certo token. Se o token não for suportado a função deve reverter a transação. A função flashLoan que de fato executa a transação do empréstimo e, para isso funcionar corretamente, deve seguir algumas regras:

  • Deve incluir um callback para a função onFlashLoan no contrato IERC3156FlashBorrower de quem pega o empréstimo.
  • Deve transferir o valor amount de tokens para o endereço receiver antes do callback.
  • Deve incluir o msg.sender (endereço que chamou a função) como initiator do onFlashLoan.
  • Não pode modificar os parâmetros token, amount e data e deve passá-los para o onFlashLoan.
  • Deve incluir um argumento fee no onFlashLoan com a taxa a se pagar que, por sua vez, deve ser fee == flashFee(token, amount).
  • Depois do callback, a função precisa pegar amount + fee de token do endereço receiver ou reverter caso não tenha tido sucesso. Se for bem sucedido, a função deve retornar true.

Quem recebe os flash loans deve implementar a interface IERC3156FlashBorrower.

Para que a transação não seja revertida, como comentado anteriormente, o endereço receiver deve aprovar que amount + fee de token sejam retirados pelo msg.sender até o fim do onFlashLoan.

A implementação de referência do ERC-3156 pode ser encontrada aqui.

Além desses, temos outros protocolos interessantes como o ERC-1167 (Minimal Proxy Contract) que nos dá a possibilidade de clonar a funcionalidade de um contrato com o mínimo de efeitos colaterais e com baixo custo de deploy desses proxies duplicados. O ERC-3448 (MetaProxy) que também nos permite atuar em casos de uso em que é necessário fazer uma cópia das funcionalidades de um contrato mas com diferentes parâmetros e num endereço diferente. O ERC-1820 (Pseudo-introspection Registry Contract) que define um registro universal onde qualquer endereço (contrato ou conta regular) possa registrar qual interface ele suporta e qual o contrato responsável por sua implementação. Bem similar ao ERC-165 que comentamos anteriormente e é inclusive compatível com ele. E por fim o ERC-3668 (CCIP Read: secure offchain data retrieval) que nos permite um padrão para o retorno de dados que estão offchain, ou seja, fora da Blockchain. E permite que contratos possam usar esses dados para executar qualquer validação necessária com eles. Comentem se quiserem um post mais detalhado de algum desses protocolos ou qualquer outro :)

Os padrões e protocolos foram criados pela comunidade para facilitar a vida de todos que participam dela. Para que a construção de produtos e serviços seja fácil de integrar e conversem entre si. Não significa que essas regras sejam os "10 mandamentos". As comunidades, o ecossistema e toda tecnologia estão em constante evolução. Regras foram feitas para serem quebradas e melhoradas. Seja livre pra construir soluções que mais se adequem ao seu caso, mas lembre-se: tudo tem um tradeoff. A magia do OpenSource é que temos a possibilidade de várias cabeças pensarem em conjunto para chegar a soluções eficientes que ajudem a todos. E todos podem e devem contribuir!

Espero que esse post tenha sido útil para você: desbravador do universo dos contratos inteligentes. Se você achou legal, compartilha com seus amigos. Me ajuda muito!

Estou pensando em lançar um post "hands on" com projetos práticos usando cada um desses protocolos. Se você acha que vai ser legal, me dá um alô aqui nos comentários, no meu linkedin ou em qualquer lugar que conseguir me encontrar.

Críticas e sugestões também são muito bem-vindas! Um abraço das galáxias a todos :)

--

--

Lucas Vieira
Block3 Research

Hi! I'm a brazilian software engineer who love to learn and build new things. My goal here is to share I little about that on the way :) https://bushi.solutions