Como criar uma StableCoin Fiat em Solidity

Cripto

Como criar uma StableCoin Fiat em Solidity

Luiz Duarte
Escrito por Luiz Duarte em 15/08/2023
Junte-se a mais de 34 mil devs

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

Neste tutorial você vai aprender como você pode codificar uma stablecoin fiat usando Solidity, a linguagem número 1 para smart contracts no mundo.

Como pré-requisitos para conseguir acompanhar tudo é importante que você já tenha tido a experiência de desenvolver smart contracts com Solidity, em especial seguindo o padrão ERC-20 para novos tokens, o que você pode aprender neste tutorial. Também é importante que você já tenha lido meu outro artigo sobre o assunto: Introdução técnica à stablecoins, pois aspectos muito importantes do que vamos fazer aqui são melhor explicados no mesmo.

Usarei neste tutorial a ferramenta Remix, que é online e gratuita, mas sinta-se livre para usar toolkits profissionais como Truffle e HardHat.

Vamos lá!

Como programar uma stablecoin lastreada em Fiat?

A parte mais complexa de se criar uma stablecoin lastreada em moeda fiat não é a programação, mas sim a burocracia com legislação, manter e auditar o lastro, transparência/reports, etc como expliquei no artigo anterior. Mas digamos que você já tenha resolvido essa parte ou não esteja preocupado com ela no momento, o que é necessário para programar uma stablecoin com colateral/lastro?

Stablecoins fiat, via de regra, são wrapped tokens ERC-20 do tipo Collateral Backed, que empacotam uma moeda fiduciária de um país que está guardada em uma conta bancária. Assim, o primeiro passo é criar um token ERC-20 que vai ser pareado com a moeda fiat, como no exemplo abaixo, onde usei a biblioteca de contratos da OpenZeppelin pra simplificar meu trabalho e deixá-lo bem profissional.

Além do padrão ERC-20 normal, incluí nos imports a extensão ERC20Burnable, que vai permitir suporte a burn, a extensão Pausable que vai permitir suporte a pausar a emissão de tokens (necessário caso seja exigido pelo governo do país da fiat) e a extensão Ownable, para controle de acesso de algumas funções estratégicas (afinal, temos de controlar expansão e contração monetária). As funções apresentadas no contrato acima foram geradas pelo builder de contrato OpenZeppelin, e vamos customizá-las agora.

O primeiro item que vamos ajustar é o mint, que deve ser chamado somente pelo owner do contrato (onlyOwner), que o fará somente quando um novo depósito da moeda fiat for identificado na conta bancária do emissor (essa parte de pagamento fiat foge do escopo deste tutorial, mas você poderia fazê-lo usando gateways de pagamento tradicionais como PIX, boleto, PayPal, etc). Adicionalmente, ele não poderá fazê-lo se o contrato estiver pausado (uma exigência ocasional de órgãos reguladores dos países, como aconteceu com a Binance em 2023 que foi impedida de mintar novos BUSD durante investigação da SEC).

E de forma análoga, teremos a função de burn, que será chamada somente pelo owner (onlyOwner), que o fará quando um portador de nossa stablecoin decidir resgatar a quantia equivalente na moeda fiat. Ou seja, se o usuário solicitar o resgate de 10 BRL (por exemplo, se a stablecoin for lastreada em BRL), devemos queimar 10 tokens da nossa stablecoin e entregar ao usuário 10 BRL na conta bancária dele. Esse resgate pode usar os gateways de pagamento normais como PIX e outros e foge do escopo deste tutorial. Para a stablecoin, o burn abaixo já resolve.

Note que estas funções de mint e de burn não possuem validações aparentes, mas elas ocorrem, só que internamente, nas suas contrapartes privadas (_mint e _burn). Além disso, repare que não condicionei o burn ser impedido de ser chamado nos casos em que o contrato esteja pausado. Isso porque em caso de restrição governamental, os clientes não serão impedidos de fazer seus saques, apenas a empresa não poderá emitir novos tokens.

Curso Node.js e MongoDB

Como cobrar taxas com stablecoins?

Note que, dependendo do seu modelo de negócio, pode ser interessante dividir a responsabilidade em dois contratos: um sendo o token/stablecoin em si, e outro focado no business, como por exemplo a cobrança de taxas. A cobrança de taxas é um modelo recorrente em stablecoins, a exemplo da Pax Gold (PAXG), que cobra 0.2% na emissão de tokens lastreados em outro.

Neste caso, podemos começar modificando o contrato da stablecoin anterior para que ela receba a informação de quem é o contrato que vai fazer o papel de exchange (corretora), além do owner em si.

Temos alguns pontos interessantes para abordar aqui. O primeiro deles é a função setExchange que será usada pelo owner para definir qual o endereço do contrato que poderá chamar as funções administrativas (além do owner em si).

Depois, criei um function modifier novo que permite verificar se o msg.sender é o owner (usando função exposta pelo contrato Ownable.sol) ou a exchange definida anteriormente. Repare que poderíamos definir isso no constructor do token, mas isso restringiria nossas opções de ordem do deploy e isso ser um problema como verá mais adiante.

Antes de avançar é interessante também criarmos uma interface que extenda o padrão ERC-20 e inclua as funções de mint e de burn, que precisarão ser chamadas pelo nosso contrato de exchange mais tarde. Abaixo sugestão de interface:

A adoção do uso desta interface (que irá deixar seu código da exchange mais profissional e flexível), requer que você mude o modificador de acesso das funções mint e burn de public para external no contrato da stablecoin, bem como ajuste a declaração do contrato para extender a interface, como abaixo:

Curso Beholder
Curso Beholder

Contrato de Exchange

Agora podemos criar um contrato MyExchange.sol que vai ser a corretora responsável por receber os estímulos de depósito e saque (oriundos do seu gateway fiat) e que vai, além de chamar o contrato do token, cobrar as taxas que você determinar. Vamos começar declarando os imports que vamos precisar, que são a extensão Ownable da OpenZeppelin e a interface da nossa stablecoin.

Na sequência, vamos definir as variáveis de estado e o constructor necessários.

A primeira das variáveis é o quanto vamos cobrar de taxa, mas como não temos ponto flutuante (casas decimais) em Solidity na data que escrevo este tutorial, vamos emular isso em uma escala diferente, sempre considerando uma divisão por 100. Ou seja, se eu coloquei 20 no fee e dividir esse valor por 100, chego em 0.2%, que é a taxa inicial sugerida, mas que você pode ajustar conforme quiser.

A segunda variável é o contrato da nossa stablecoin, que estou usando a interface para tipá-lo o que permitirá invocar suas funções mais tarde sem conhecermos detalhes de implementação do mesmo. Na sequência, o constructor do contrato recebe o endereço da stablecoin e o associa à exchange já no deploy. Opcionalmente você pode criar uma função depois que permita alterar este endereço, mas via de regra não há necessidade.

Atenção apenas à ordem do deploy quando o fizer:

  1. deploy da stablecoin
  2. deploy da exchange, passando o endereço da stablecoin;
  3. chamada da função setExchange da stablecoin, passando o endereço da exchange;

Somente seguindo essas instruções é que essa implementação que fizemos irá funcionar. Você pode aprender mais sobre deploy com Remix neste tutorial.

Mas voltando ao que interessa, vamos implementar agora as funções da exchange:

As funções setFee e withdraw (saque) dispensam grandes explicações, já que são bem objetivas. Atenção apenas ao fato de que o saque em si, na moeda fiat, acontecerá através do gateway bancário que escolher e que foge do escopo deste tutorial. Ao contrato da exchange cabe somente o burn dos tokens que foram sacados.

Agora a função de depósito tem uma implementação que talvez lhe escape o detalhe à primeira vista que é o desconto da taxa. Como não temos uso de casas decimais aqui, mas queremos deduzir a taxa, vamos elevar a quantia depositada em 10.000 e depois dividir por 10.000, mas descontando o fee o que causará a redução percentual esperada (recomendo que teste na calculadora para entender realmente a lógica). Esse truque de subir a escala do número para não precisar de casas decimais é muito comum em contratos solidity que precisem lidar com percentuais.

Reforço também que a função de depósito será chamada pelo owner assim que o gateway de pagamento fiat confirmar o depósito equivalente. Ambas funções podem ser automatizadas através de um backend próprio que as chame usando a chave privada da carteira do owner. Esse conhecimento de chamar o smart contract via backend é ensinado neste outro tutorial, usando Node.js.

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

Falo também sobre paridade de stablecoins no vídeo abaixo.

E com isso finalizamos mais este tutorial.

Até a próxima!

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 *