WEB3DEV

Cover image for Desmembrando o Contrato Inteligente Uniswap - Parte 2
Panegali
Panegali

Posted on • Atualizado em

Desmembrando o Contrato Inteligente Uniswap - Parte 2

Explicando sua funcionalidade através do agrupamento de linhas de código

99

Esta é a Parte 2 da Análise do Contrato Inteligente Uniswap. Na Parte 1, abordamos:

  • Como a Uniswap funciona em alto nível
  • Como o código Uniswap é organizado
  • Funcionalidades Uniswap
  • Contratos principais: Par (difícil): gerenciar os fundos, cunhar e queimar

Neste artigo, abordaremos o resto:

  • Contratos principais: Par (difícil): troca, tokens de propriedade da pool, taxa de protocolo e oráculo de preços
  • Contratos principais: Fábrica (fácil)
  • Contrato Periférico: Roteador (fácil)
  • Código totalmente anotado

Sumário

1 . Contratos Principais
..... . Par (difícil)
..... . Fábrica (fácil)

2 . Contrato Periférico
..... . Roteador (fácil)


Par

Troca

A função swap é usada pelos negociante para trocar tokens:

1

  • Primeiro, temos um monte de afirmações
  • Então, nas linhas 170 e 171, transferimos tokens (para o negociante) de forma otimista (sem ter certeza de que o negociante já transferiu os tokens correspondentes para o nosso saldo. Podemos transferir tokens com otimismo porque temos afirmações posteriormente na função para verificar se recebemos os tokens correspondentes (o contrato Periférico deve nos enviar os tokens antes de nos chamar para a troca). Se não tivermos, as assertivas falharão e o Solidity reverterá toda a função.
  • A linha 172 informará o receptor sobre a troca, se solicitado.
  • Então, nas linhas 176 e 177, verificamos quantos tokens recebemos. Afirmamos que recebemos uma quantia >0 para pelo menos um token na linha 178. Se essa afirmação falhar, toda a função será revertida e nada terá ocorrido.
  • Então, nas linhas 180 e 181, subtraímos a taxa de negociação (0,3%) do saldo, e na linha 182 verificamos se o valor de k (x*y=k) diminuiu após a negociação. O valor k nunca pode diminuir porque, caso contrário, a Uniswap perderia com a troca.
  • Por fim, atualizamos nossas reservas conhecidas com os novos saldos e emitimos um evento Swap.

Uma observação sobre taxas e recompensas

A Uniswap funciona cobrando uma pequena porcentagem (0,3%) dos negociantes em cada operação. Posteriormente (opcionalmente) leva algumas dessas taxas (1/6) para si e distribui o restante para os provedores de liquidez na proporção de quanto o provedor de liquidez contribuiu para a pool.

Onde essas taxas/recompensas são armazenadas? Elas são realmente armazenadas na própria pool.

Quando os negociantes pagam suas taxas, essas taxas são adicionadas na pool. Mais tarde, quando os provedores de liquidez adicionam ou retiram fundos, as recompensas do provedor de liquidez são calculadas usando fórmulas matemáticas complexas.

Esta é a elegância da Uniswap em jogo novamente - em vez de criar uma pool/armazenamento separado para as taxas/recompensas, eles apenas adicionam tudo à pool e depois usam fórmulas matemáticas inteligentes para deduzir quanto da pool é das taxas. E a Uniswap tem uma maneira eficiente de acompanhar absolutamente o mínimo necessário para derivar esses valores a qualquer momento no futuro.

Tokens de propriedade da pool

Quando os provedores de liquidez adicionam fundos à pool, eles recebem tokens de propriedade da pool. Depois de algum tempo, esses tokens de propriedade ganham valor devido às taxas dos negociantes. Quando os tokens são trocados de volta, os provedores de liquidez recebem mais do que depositaram.

Os tokens de propriedade da pool são implementados como um token padrão ERC20. Está implementado no contrato UniswapV2ERC20.sol da Uniswap (v2-core/contracts/UniswapV2ERC20.sol). É esta parte do nosso diagrama da Parte 1:

2

Eu já fiz um detalhamento do contrato ERC20 da Uniswap no meu artigo Desmembrando o Contrato Inteligente ERC20, então não vou me repetir.

O contrato Par obtém acesso à implementação do ERC20 estendendo-o:

3

Dessa forma, o contrato Pair obtém acesso às funções ERC20 _mint e _burn:

4

5

Taxa de protocolo

A Uniswap v2 introduziu uma taxa de protocolo comutável — uma taxa que pode ser ativada/desativada pela Uniswap, que vai para a Uniswap para manter o serviço. É igual a 1/6 das taxas pagas pelos negociantes. Vamos examinar como a taxa de protocolo é tratada no contrato Par.

A principal função da taxa de protocolo é _mintFee:

6

Esta função parece complicada, então vamos focar nestas linhas:

7

  • Primeiro pegamos o endereço feeTo do factory. factory é o contrato que criou este contrato Par.
  • Se estiver definido para algo diferente do endereço zero, isso significa que a taxa de protocolo está ativa. O endereço feeTo indicado no endereço para onde a taxa de protocolo deve ser enviada.
  • Se a taxa estiver ativa, cunhamos alguma liquidez no endereço feeTo. ( função _mint é a função do _mintERC20 )

O resto do código é para calcular liquidity. A liquidez aqui indica a quantidade de novos tokens de propriedade da pool que precisam ser cunhados no endereço feeTo. É assim que a Uniswap implementa as taxas de protocolo: ela apenas cunha novos tokens de propriedade da pool para si mesmo. Isto, de fato, dilui todos os outros na pool (os provedores de liquidez).

Na minha humilde opinião, _mintFeenão é o melhor nome para esta função porque tem um efeito colateral de cunhar nova liquidez. Um nome melhor seria _collectProtocolFee.

Como a taxa de protocolo é calculada

Uma maneira direta de implementar a taxa de protocolo seria receber 1/6 da taxa dos negociantes toda vez que houver uma troca de tokens. Mas como você provavelmente notou, a Uniswap não gosta do caminho mais fácil. Ela adora eficiência e economia de gás, mesmo que isso signifique que o código se torne 10x mais complexo.

A Uniswap não calcula taxas em todas as negociações porque isso incorreria em gás extra em todas as negociações de swap. Como há muitos e muitos negócios acontecendo todos os dias, isso representaria grandes quantidades de custo de gás. Em vez disso, a Uniswap calcula a taxa de protocolo apenas quando os fundos são depositados ou retirados da pool pelos provedores de liquidez. Este é um evento muito mais raro do que as negociações.

Portanto, a função _mintFee é chamada apenas a partir das funções mint e burn.

9

10

A taxa de protocolo é acumulada durante as negociações na pool para que a pool se torne uma mistura de tokens de troca, taxas de protocolo e recompensas para provedores de liquidez. Fórmulas matemáticas inteligentes nos permitem calcular quanto de cada constituinte existe.

A taxa de protocolo, em particular, é calculada usando uma fórmula complexa que você pode encontrar no whitepaper Uniswap V2:

11

O valor k aqui é o produto das reservas (k=x*y). É por isso que acompanhamos o valor kLast em todo o código: o valor kLastnos permite calcular a taxa total de protocolo acumulada (de cada negociação) até agora e coletar toda esta taxa de uma só vez nas funções mint ou burn.

Oráculo de preço

A Uniswap implementa um oráculo de preços que pode ser usado por outros contratos inteligentes no ecossistema Ethereum para consultar o preço dos tokens em relação uns aos outros.

Para implementar o oráculo de preços, a Uniswap utiliza apenas 3 variáveis: price0CumulativeLast, price1CumulativeLast, e blockTimestampLast.

12

O preço relativo pode ser calculado subtraindo os preços acumulados em 2 pontos no tempo e dividindo pelo tempo decorrido. Verifique a seção “Oráculo de preço” do whitepaper Uniswap para obter mais detalhes.

As variáveis ​​são atualizadas apenas uma vez por bloco aqui:

13

As linhas 75–77 calculam se esta é a primeira vez que o código é executado em um bloco específico.

Por que atualizamos os valores apenas uma vez por bloco? Porque é mais difícil alguém manipular os preços para ganhar alguma coisa. Consulte a seção “Oráculo de preços” do whitepaper Uniswap para obter mais detalhes sobre esses manipuladores de preços.

Diversos

14

Um evento de liquidez é quando os fundos são adicionados ou retirados pelos provedores de liquidez.

15

lock é para se proteger contra o abuso de reentrância. Essencialmente, este modificador de função impede que 2 partes diferentes deste contrato sejam executadas simultaneamente. Isso meio que faz o contrato ser executado com uma única thread.

Image description

skim e sync são necessários quando os saldos dos contratos ERC20 dos tokens de troca ficam fora de sincronia com as variáveis reserve ​​do contrato Par. Isso pode acontecer, por exemplo, quando alguém simplesmente transfere alguma Dogecoin para a conta do contrato Par sem motivo. Existem 2 soluções para manter as variáveis ​​de reserva sincronizadas com os saldos reais nos contratos ERC20:

  • skimpermite que alguém retire os fundos extras do contrato ERC20. Qualquer um pode chamar esta função!
  • syncatualiza as variáveis reserve ​​para corresponder aos saldos.

Uma nota sobre a dinâmica do mercado

Uniswap precifica os tokens de acordo com a proporção deles na pool. Quanto maior o desequilíbrio deles na pool, maior a diferença de preço (em favor do token mais raro).

Mas como a Uniswap garante que o preço relativo dos tokens na pool corresponda à taxa de mercado? Arbitragem. A Uniswap aproveita a arbitragem para garantir que os preços na pool acompanhem de perto os preços de mercado.

Arbitragem é quando um investidor inteligente vê uma discrepância entre a taxa de mercado e a taxa de câmbio Uniswap, ele a usará para obter lucro e, como resultado, aproximará a taxa Uniswap da taxa de mercado.

Por exemplo, se a Uniswap oferecesse um preço de Dogecoin para Shiba mais baixo em comparação com a taxa de mercado, um investidor inteligente trocaria sua Shiba por Dogecoin na Uniswap e venderia a Dogecoin a um preço mais alto no mercado. Ele terá lucro e, como resultado, aproximou a taxa Unsiwap da taxa de mercado porque diminuiu a oferta de Dogecoin e aumentou a oferta de Shiba na pool Uniswap (o preço Dogecoin para Shiba aumentará devido à forma como os tokens de preço Uniswap em relação uns aos outros).

Isto continuará até que a taxa Uniswap corresponda à taxa de mercado. Assim, a taxa Uniswap tende a acompanhar de perto a taxa de mercado e é por isso que pode ser usada como um oráculo de preços on-chain.

  • Como explicado no whitepaper Uniswap v2: O primeiro provedor de liquidez a ingressar em uma pool define a taxa de câmbio inicial depositando o que eles acreditam ser um valor equivalente de tokens ETH e ERC20. Se essa proporção estiver desativada, os negociantes de arbitragem equilibrarão os preços às custas do provedor de liquidez inicial.
  • E o whitepaper Uniswap v1 mencionou: Grandes negociações também causam derrapagem de preços, mas a arbitragem garantirá que o preço não se desvie muito do de outras corretoras.

Síntese

Isto é tudo para o contrato Par — o contrato mais complexo da Uniswap! Os outros 2 contratos são muito mais fáceis. Vamos resumir o que aprendemos.

O contrato Par é uma mistura de várias funcionalidades:

  • Gerenciando fundos
  • Adicionando/removendo liquidez
  • Trocando tokens
  • Gerenciamento de taxas/recompensas
  • Calculando a taxa de protocolo
  • Implementando um oráculo de preços

Aqui está o código totalmente anotado para o contrato Par, codificado por cores de acordo com a funcionalidade:

17

Fábrica

18

Aqui está um detalhamento do contrato Fábrica (v2-core/contracts/UniswapV2Fatory.sol):

19

Bastante simples em comparação com o contrato Par

Este contrato Fábrica é referenciado em todo o contrato Par:

20

21

Contrato Periférico

Roteador

22

O contrato Periférico é a API para a Uniswap. Você pode chamar os contratos Principais diretamente, mas isto é mais complexo (o periférico fornece funções de encapsulamento) e mais perigoso (você pode perder dinheiro se não for cuidadoso).

Os contratos principais têm verificações para garantir que não sejam fraudados. Mas eles não fazem verificações para mais ninguém. Estas verificações estão no periférico. Então, se você não quer perder dinheiro, use o contrato periférico para interagir com a Uniswap.

Vamos desmembrar o contrato Roteador, que é o único contrato periférico. Ele pode ser encontrado em v2-periphery/contracts/UniswapV2Router02.sol.

23

  • Este contrato tem várias funções semelhantes para adicionar liquidez, remover liquidez e trocar tokens. Diferentes variantes de funções são para diferentes preferências de negociação/liquidez.
  • Eu removi o corpo da maioria das funções porque elas são bem parecidas.
  • Do site Ethereum: UniswapV2Router01 tem problemas e não deve mais ser usado.

Isso é tudo para a Uniswap! Eu espero que isto tenha sido útil. Deixe-me saber nos comentários se você tiver alguma dúvida.

Estou planejando fazer mais detalhamentos de contratos inteligentes populares como Axie Infinity e BAYC, então me siga no Medium ou no Twitter para obter atualizações.

Você também pode conferir detalhamentos de outros contratos inteligentes e mais coisas para noobs do Solidity em solidnoob.com.

Gostaria de conectar-se? Siga-me no Twitter.


Artigo escrito por Nazar Ilamanov. A versão original pode ser encontrada aqui. Traduzido e adaptado por Marcelo Panegali.

Top comments (0)