Dicas de desenvolvimento de contratos aprendidas com o código do Uniswap
Recentemente, ao escrever um tutorial de desenvolvimento de exchanges descentralizadas, consultei a implementação do código do Uniswap V3 e aprendi muitos pontos valiosos. Como um desenvolvedor que anteriormente só havia desenvolvido contratos NFT simples, esta tentativa de desenvolver contratos DeFi me trouxe muitas novas aprendizagens. Acredito que essas pequenas dicas serão muito úteis para novatos que desejam aprender sobre o desenvolvimento de contratos.
A seguir, vamos dar uma olhada nestas dicas de desenvolvimento úteis, algumas das quais podem até ser consideradas truques engenhosos.
Endereço de contrato previsível
Geralmente, o endereço obtido ao implantar um contrato parece aleatório, pois está relacionado ao nonce, tornando o endereço do contrato difícil de prever. Mas em algumas situações, precisamos inferir o endereço do contrato através de pares de negociação e informações relacionadas, como determinar permissões de negociação ou obter o endereço do pool, etc.
O Uniswap cria contratos usando o método CREATE2 ao adicionar o parâmetro salt, tornando o endereço do contrato criado previsível. A lógica de geração do endereço é: novo endereço = hash("0xFF", endereço do criador, salt, initcode).
Utilize bem as funções de retorno
Em Solidity, os contratos podem chamar uns aos outros. Em certos cenários, é útil que A chame o método de B e que B faça uma chamada de volta para A no método que foi chamado.
No Uniswap, ao chamar o método swap do contrato UniswapV3Pool para realizar uma transação, ele fará uma chamada de retorno (callback) swapCallback, que receberá o Token calculado necessário para a transação atual. O chamador precisa transferir o Token necessário para a transação para o UniswapV3Pool dentro do callback, em vez de dividir o método swap em duas partes para que o chamador o chame. Isso garante a segurança do método swap, assegurando que toda a lógica seja executada de forma completa, sem a necessidade de registros de variáveis complicados para garantir a segurança.
Usar exceções para transmitir informações, implementar a estimativa de transação com try catch
Em alguns contratos da Uniswap, o método swap do UniswapV3Pool é executado envolto em try catch. Isto é feito para simular o método swap a fim de estimar os Tokens necessários para a transação. Como não há troca real de Tokens durante a estimativa, um erro é gerado. A Uniswap lança um erro especial na função de callback da transação e, em seguida, captura esse erro para extrair as informações necessárias a partir da mensagem de erro.
Este método pode parecer um pouco astuto, mas é muito prático. Não é necessário adaptar o método swap para estimar a demanda de negociação, e a lógica é também mais simples.
Resolver problemas de precisão com grandes números
No código do Uniswap, há uma grande quantidade de lógica de cálculo, como calcular os tokens a serem trocados com base no preço atual e na liquidez. Para evitar a perda de precisão causada pela operação de divisão, usa-se frequentemente a operação << FixedPoint96.RESOLUTION durante o cálculo, que equivale a mover para a esquerda 96 bits, ou seja, multiplicar por 2^96. Após o deslocamento para a esquerda, a operação de divisão é realizada, garantindo precisão em transações normais sem estouro.
Embora teoricamente ainda haja perda de precisão, geralmente é apenas uma perda da unidade mínima, o que é aceitável.
Calcular lucros através do Share
No Uniswap, é necessário registar os rendimentos das taxas dos LPs (fornecedores de liquidez). É evidente que não se pode registar as taxas de cada LP em cada transacção, pois isso consumiria uma grande quantidade de Gas.
A solução da Uniswap é definir feeGrowthInside0LastX128 e feeGrowthInside1LastX128 na estrutura Position, que registra a comissão que cada liquidez deveria ter recebido na última retirada de taxas de cada posição.
Em resumo, basta registrar a taxa total de transação e a taxa de transação que deve ser alocada a cada liquidez. Quando os LPs retiram a taxa de transação, a taxa que pode ser retirada é calculada com base na liquidez mantida. Isso é semelhante a possuir ações de uma empresa; ao retirar os lucros das ações, é necessário apenas saber o lucro por ação histórico da empresa e o lucro na última retirada.
Nem todas as informações precisam ser obtidas da cadeia
O armazenamento em blockchain é relativamente caro, e nem todas as informações precisam ser armazenadas na blockchain ou obtidas a partir dela. Por exemplo, muitas das interfaces chamadas pelo site front-end do Uniswap são interfaces tradicionais da Web2.
A lista de pools de negociação, informações sobre pools de negociação, etc., podem ser armazenadas em um banco de dados comum, alguns podem precisar ser sincronizados periodicamente da cadeia, mas não é necessário chamar em tempo real a interface RPC fornecida pela cadeia ou serviços de nó para obter os dados relevantes.
Claro, as transações-chave devem ser feitas na cadeia.
Aprenda a dividir contratos, utilizando contratos padrão existentes
Um projeto pode conter vários contratos realmente implementados. Mesmo que haja apenas um contrato realmente implementado, podemos dividir o contrato em vários contratos para manutenção através de herança.
Por exemplo, alguns contratos no Uniswap herdam vários contratos. Na implementação, foi utilizado diretamente o contrato @openzeppelin/contracts/token/ERC721/ERC721.sol, o que facilita a gestão de posições através de NFTs e permite aproveitar contratos padrão existentes para aumentar a eficiência do desenvolvimento.
Resumo
Desenvolver por conta própria aprofunda mais a compreensão do que ler artigos. Tentar implementar um versão simplificada de uma exchange descentralizada permitirá que você compreenda melhor a implementação do código do Uniswap e também aprenderá mais pontos de conhecimento em projetos reais.
This page may contain third-party content, which is provided for information purposes only (not representations/warranties) and should not be considered as an endorsement of its views by Gate, nor as financial or professional advice. See Disclaimer for details.
7 Curtidas
Recompensa
7
4
Compartilhar
Comentário
0/400
ForumLurker
· 2h atrás
pro pode explicar melhor esta parte das técnicas
Ver originalResponder0
BearMarketGardener
· 23h atrás
Novato, comece com a alquimia.
Ver originalResponder0
MissedAirdropAgain
· 23h atrás
Já vamos abrir mais um? Acabamos de fazer o NFT e ainda não é suficiente.
Análise do código Uniswap V3: 7 dicas práticas para desenvolvimento de contratos
Dicas de desenvolvimento de contratos aprendidas com o código do Uniswap
Recentemente, ao escrever um tutorial de desenvolvimento de exchanges descentralizadas, consultei a implementação do código do Uniswap V3 e aprendi muitos pontos valiosos. Como um desenvolvedor que anteriormente só havia desenvolvido contratos NFT simples, esta tentativa de desenvolver contratos DeFi me trouxe muitas novas aprendizagens. Acredito que essas pequenas dicas serão muito úteis para novatos que desejam aprender sobre o desenvolvimento de contratos.
A seguir, vamos dar uma olhada nestas dicas de desenvolvimento úteis, algumas das quais podem até ser consideradas truques engenhosos.
Endereço de contrato previsível
Geralmente, o endereço obtido ao implantar um contrato parece aleatório, pois está relacionado ao nonce, tornando o endereço do contrato difícil de prever. Mas em algumas situações, precisamos inferir o endereço do contrato através de pares de negociação e informações relacionadas, como determinar permissões de negociação ou obter o endereço do pool, etc.
O Uniswap cria contratos usando o método CREATE2 ao adicionar o parâmetro salt, tornando o endereço do contrato criado previsível. A lógica de geração do endereço é: novo endereço = hash("0xFF", endereço do criador, salt, initcode).
Utilize bem as funções de retorno
Em Solidity, os contratos podem chamar uns aos outros. Em certos cenários, é útil que A chame o método de B e que B faça uma chamada de volta para A no método que foi chamado.
No Uniswap, ao chamar o método swap do contrato UniswapV3Pool para realizar uma transação, ele fará uma chamada de retorno (callback) swapCallback, que receberá o Token calculado necessário para a transação atual. O chamador precisa transferir o Token necessário para a transação para o UniswapV3Pool dentro do callback, em vez de dividir o método swap em duas partes para que o chamador o chame. Isso garante a segurança do método swap, assegurando que toda a lógica seja executada de forma completa, sem a necessidade de registros de variáveis complicados para garantir a segurança.
Usar exceções para transmitir informações, implementar a estimativa de transação com try catch
Em alguns contratos da Uniswap, o método swap do UniswapV3Pool é executado envolto em try catch. Isto é feito para simular o método swap a fim de estimar os Tokens necessários para a transação. Como não há troca real de Tokens durante a estimativa, um erro é gerado. A Uniswap lança um erro especial na função de callback da transação e, em seguida, captura esse erro para extrair as informações necessárias a partir da mensagem de erro.
Este método pode parecer um pouco astuto, mas é muito prático. Não é necessário adaptar o método swap para estimar a demanda de negociação, e a lógica é também mais simples.
Resolver problemas de precisão com grandes números
No código do Uniswap, há uma grande quantidade de lógica de cálculo, como calcular os tokens a serem trocados com base no preço atual e na liquidez. Para evitar a perda de precisão causada pela operação de divisão, usa-se frequentemente a operação << FixedPoint96.RESOLUTION durante o cálculo, que equivale a mover para a esquerda 96 bits, ou seja, multiplicar por 2^96. Após o deslocamento para a esquerda, a operação de divisão é realizada, garantindo precisão em transações normais sem estouro.
Embora teoricamente ainda haja perda de precisão, geralmente é apenas uma perda da unidade mínima, o que é aceitável.
Calcular lucros através do Share
No Uniswap, é necessário registar os rendimentos das taxas dos LPs (fornecedores de liquidez). É evidente que não se pode registar as taxas de cada LP em cada transacção, pois isso consumiria uma grande quantidade de Gas.
A solução da Uniswap é definir feeGrowthInside0LastX128 e feeGrowthInside1LastX128 na estrutura Position, que registra a comissão que cada liquidez deveria ter recebido na última retirada de taxas de cada posição.
Em resumo, basta registrar a taxa total de transação e a taxa de transação que deve ser alocada a cada liquidez. Quando os LPs retiram a taxa de transação, a taxa que pode ser retirada é calculada com base na liquidez mantida. Isso é semelhante a possuir ações de uma empresa; ao retirar os lucros das ações, é necessário apenas saber o lucro por ação histórico da empresa e o lucro na última retirada.
Nem todas as informações precisam ser obtidas da cadeia
O armazenamento em blockchain é relativamente caro, e nem todas as informações precisam ser armazenadas na blockchain ou obtidas a partir dela. Por exemplo, muitas das interfaces chamadas pelo site front-end do Uniswap são interfaces tradicionais da Web2.
A lista de pools de negociação, informações sobre pools de negociação, etc., podem ser armazenadas em um banco de dados comum, alguns podem precisar ser sincronizados periodicamente da cadeia, mas não é necessário chamar em tempo real a interface RPC fornecida pela cadeia ou serviços de nó para obter os dados relevantes.
Claro, as transações-chave devem ser feitas na cadeia.
Aprenda a dividir contratos, utilizando contratos padrão existentes
Um projeto pode conter vários contratos realmente implementados. Mesmo que haja apenas um contrato realmente implementado, podemos dividir o contrato em vários contratos para manutenção através de herança.
Por exemplo, alguns contratos no Uniswap herdam vários contratos. Na implementação, foi utilizado diretamente o contrato @openzeppelin/contracts/token/ERC721/ERC721.sol, o que facilita a gestão de posições através de NFTs e permite aproveitar contratos padrão existentes para aumentar a eficiência do desenvolvimento.
Resumo
Desenvolver por conta própria aprofunda mais a compreensão do que ler artigos. Tentar implementar um versão simplificada de uma exchange descentralizada permitirá que você compreenda melhor a implementação do código do Uniswap e também aprenderá mais pontos de conhecimento em projetos reais.