Dicas para desenvolvimento de contratos: experiências aprendidas com o código do Uniswap
Recentemente, ao escrever um tutorial sobre uma exchange descentralizada, consultei a implementação do Uniswap V3 e aprendi vários pontos interessantes. Como um novato que está apenas começando a desenvolver contratos Defi, essas dicas foram muito inspiradoras para mim, e acredito que também serão úteis para outros amigos que desejam aprender a desenvolver contratos inteligentes.
Endereço de contrato previsível
Os endereços de contrato normalmente implantados parecem aleatórios, devido ao nonce associado. No entanto, em certos cenários, precisamos inferir o endereço do contrato através das informações da transação, como determinar permissões de transação ou obter o endereço do pool.
A Uniswap cria contratos usando o método CREATE2, adicionando o parâmetro salt. Assim, o endereço do contrato gerado é previsível, seguindo a lógica "novo endereço = hash('0xFF', endereço do criador, salt, initcode)".
Uso inteligente de funções de retorno
Em Solidity, os contratos podem chamar uns aos outros. Às vezes, o contrato A chama um método do contrato B, e o B, por sua vez, chama de volta um método do A, o que é útil em certos cenários.
Por exemplo, no fluxo de negociação do Uniswap, quando o método swap do contrato UniswapV3Pool é chamado, ele fará uma chamada de retorno swapCallback, passando a quantidade real de Token necessária. O chamador precisa transferir o Token necessário na chamada de retorno, garantindo a integridade e a segurança de toda a lógica da transação.
Usar exceções para transmitir informações, implementar estimativa de transação com try catch
No contrato Quoter da Uniswap, a execução do método swap do UniswapV3Pool é envolvida em um try catch. Isso é feito para simular a estimativa de tokens necessários para a transação, mas ao estimar, os tokens não são realmente trocados, então ocorrerá um erro.
Uniswap lança um erro especial na função de retorno de chamada de transação, e depois captura esse erro e analisa a informação. Embora essa abordagem possa parecer uma solução rápida, é bastante prática, pois não requer uma modificação específica do método swap para estimar a demanda.
Problemas de precisão no manuseio de grandes números
O código do Uniswap envolve muitos cálculos, como calcular a quantidade de tokens a serem trocados com base no preço atual e na liquidez. Para evitar a perda de precisão nas operações de divisão, o processo de cálculo frequentemente utiliza a operação "<< FixedPoint96.RESOLUTION", que equivale a multiplicar por 2^96.
Este método garante a precisão ao mesmo tempo que evita que as transações normais excedam (geralmente calculado com uint256). Embora teoricamente ainda possa haver perda de precisão na unidade mínima, isso já é aceitável.
Calcular lucros com o método Share
No Uniswap, é necessário registrar os ganhos de taxas dos provedores de liquidez (LP). Para evitar registrar as taxas para cada LP a cada transação (o que consumiria uma grande quantidade de Gas), o Uniswap adotou um método engenhoso.
Na estrutura Position, são definidos feeGrowthInside0LastX128 e feeGrowthInside1LastX128, que registram as taxas que cada posição deveria receber por unidade de liquidez na última retirada de taxa. Assim, apenas é necessário registrar a taxa total e a alocação por unidade de liquidez, e as taxas que podem ser retiradas pelos LPs são calculadas com base na liquidez detida.
O equilíbrio entre a obtenção de informações on-chain e off-chain
O armazenamento em blockchain é relativamente caro, e nem todas as informações precisam ser armazenadas na blockchain ou recuperadas dela. Muitos dos interfaces chamadas pelo 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, sincronizando periodicamente com a cadeia. Não é necessário chamar em tempo real a interface RPC dos serviços de cadeia ou nó para obter dados relevantes.
Alguns fornecedores de RPC de blockchain oferecem interfaces avançadas que permitem obter dados de forma mais rápida e barata. Essas interfaces geralmente melhoram o desempenho e a eficiência através de cache.
Divisão de contratos e utilização de contratos padrão
Um projeto pode conter vários contratos efetivamente implantados. Mesmo que apenas um contrato seja implantado, o código pode ser mantido através da divisão em vários contratos por meio de herança.
Por exemplo, o contrato NonfungiblePositionManager da Uniswap herda vários contratos. O contrato ERC721Permit utiliza diretamente a implementação padrão ERC721 da OpenZeppelin, facilitando a gestão de posições de forma NFT e aumentando a eficiência do desenvolvimento.
Conclusão
A prática é o melhor método de aprendizagem. Ao tentar implementar uma versão simples de uma exchange descentralizada, é possível entender mais profundamente a implementação do código do Uniswap e aprender mais sobre conceitos práticos em projetos. Espero que essas experiências possam ajudar amigos que estão interessados em desenvolver projetos de Web3 e Defi.
Esta página pode conter conteúdos de terceiros, que são fornecidos apenas para fins informativos (sem representações/garantias) e não devem ser considerados como uma aprovação dos seus pontos de vista pela Gate, nem como aconselhamento financeiro ou profissional. Consulte a Declaração de exoneração de responsabilidade para obter mais informações.
7 gostos
Recompensa
7
6
Partilhar
Comentar
0/400
StableNomad
· 15h atrás
estatisticamente falando, a uniswap ainda tem a base de código mais limpa... apenas dizendo
Ver originalResponder0
StablecoinAnxiety
· 15h atrás
Endereço pode prever isso, é muito crucial!
Ver originalResponder0
PumpStrategist
· 15h atrás
Tsc tsc, o DEX também está a brincar com as artimanhas da Máquina Oracle, a viabilidade para grandes fundos aumentou.
Dicas para desenvolvimento de contratos Uniswap: do Endereço previsível ao equilíbrio na cadeia e fora da cadeia.
Dicas para desenvolvimento de contratos: experiências aprendidas com o código do Uniswap
Recentemente, ao escrever um tutorial sobre uma exchange descentralizada, consultei a implementação do Uniswap V3 e aprendi vários pontos interessantes. Como um novato que está apenas começando a desenvolver contratos Defi, essas dicas foram muito inspiradoras para mim, e acredito que também serão úteis para outros amigos que desejam aprender a desenvolver contratos inteligentes.
Endereço de contrato previsível
Os endereços de contrato normalmente implantados parecem aleatórios, devido ao nonce associado. No entanto, em certos cenários, precisamos inferir o endereço do contrato através das informações da transação, como determinar permissões de transação ou obter o endereço do pool.
A Uniswap cria contratos usando o método CREATE2, adicionando o parâmetro salt. Assim, o endereço do contrato gerado é previsível, seguindo a lógica "novo endereço = hash('0xFF', endereço do criador, salt, initcode)".
Uso inteligente de funções de retorno
Em Solidity, os contratos podem chamar uns aos outros. Às vezes, o contrato A chama um método do contrato B, e o B, por sua vez, chama de volta um método do A, o que é útil em certos cenários.
Por exemplo, no fluxo de negociação do Uniswap, quando o método swap do contrato UniswapV3Pool é chamado, ele fará uma chamada de retorno swapCallback, passando a quantidade real de Token necessária. O chamador precisa transferir o Token necessário na chamada de retorno, garantindo a integridade e a segurança de toda a lógica da transação.
Usar exceções para transmitir informações, implementar estimativa de transação com try catch
No contrato Quoter da Uniswap, a execução do método swap do UniswapV3Pool é envolvida em um try catch. Isso é feito para simular a estimativa de tokens necessários para a transação, mas ao estimar, os tokens não são realmente trocados, então ocorrerá um erro.
Uniswap lança um erro especial na função de retorno de chamada de transação, e depois captura esse erro e analisa a informação. Embora essa abordagem possa parecer uma solução rápida, é bastante prática, pois não requer uma modificação específica do método swap para estimar a demanda.
Problemas de precisão no manuseio de grandes números
O código do Uniswap envolve muitos cálculos, como calcular a quantidade de tokens a serem trocados com base no preço atual e na liquidez. Para evitar a perda de precisão nas operações de divisão, o processo de cálculo frequentemente utiliza a operação "<< FixedPoint96.RESOLUTION", que equivale a multiplicar por 2^96.
Este método garante a precisão ao mesmo tempo que evita que as transações normais excedam (geralmente calculado com uint256). Embora teoricamente ainda possa haver perda de precisão na unidade mínima, isso já é aceitável.
Calcular lucros com o método Share
No Uniswap, é necessário registrar os ganhos de taxas dos provedores de liquidez (LP). Para evitar registrar as taxas para cada LP a cada transação (o que consumiria uma grande quantidade de Gas), o Uniswap adotou um método engenhoso.
Na estrutura Position, são definidos feeGrowthInside0LastX128 e feeGrowthInside1LastX128, que registram as taxas que cada posição deveria receber por unidade de liquidez na última retirada de taxa. Assim, apenas é necessário registrar a taxa total e a alocação por unidade de liquidez, e as taxas que podem ser retiradas pelos LPs são calculadas com base na liquidez detida.
O equilíbrio entre a obtenção de informações on-chain e off-chain
O armazenamento em blockchain é relativamente caro, e nem todas as informações precisam ser armazenadas na blockchain ou recuperadas dela. Muitos dos interfaces chamadas pelo 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, sincronizando periodicamente com a cadeia. Não é necessário chamar em tempo real a interface RPC dos serviços de cadeia ou nó para obter dados relevantes.
Alguns fornecedores de RPC de blockchain oferecem interfaces avançadas que permitem obter dados de forma mais rápida e barata. Essas interfaces geralmente melhoram o desempenho e a eficiência através de cache.
Divisão de contratos e utilização de contratos padrão
Um projeto pode conter vários contratos efetivamente implantados. Mesmo que apenas um contrato seja implantado, o código pode ser mantido através da divisão em vários contratos por meio de herança.
Por exemplo, o contrato NonfungiblePositionManager da Uniswap herda vários contratos. O contrato ERC721Permit utiliza diretamente a implementação padrão ERC721 da OpenZeppelin, facilitando a gestão de posições de forma NFT e aumentando a eficiência do desenvolvimento.
Conclusão
A prática é o melhor método de aprendizagem. Ao tentar implementar uma versão simples de uma exchange descentralizada, é possível entender mais profundamente a implementação do código do Uniswap e aprender mais sobre conceitos práticos em projetos. Espero que essas experiências possam ajudar amigos que estão interessados em desenvolver projetos de Web3 e Defi.