Desde o anúncio do UniswapV4, esta plataforma de swap passou por uma transformação significativa, evoluindo de uma simples plataforma de swap para um provedor de serviços de infraestrutura. Em particular, o recurso Hooks do V4 ganhou ampla atenção. Após uma pesquisa aprofundada, compilei alguns conteúdos para ajudar todos a entender melhor essa transformação e sua implementação.
O foco da inovação do UniswapV4 não é apenas melhorar a tecnologia AMM, mas também expandir o ecossistema. Especificamente, esta inovação inclui os seguintes recursos principais:
Nas seções seguintes, explicarei detalhadamente a importância desses recursos e seus princípios de implementação.
fonte: https://twitter.com/jermywkh/status/1670779830621851650
O UniswapV4 adota um método de manutenção de registros semelhante à Escrituração de Dupla Entrada para rastrear as alterações de saldo dos tokens correspondentes a cada operação. Este método de contabilidade por partidas dobradas exige o registro de cada transação em várias contas simultaneamente e a garantia de que o saldo dos ativos entre essas contas permaneça equilibrado. Por exemplo, suponha que um usuário troque 100 TokenA por 50 TokenB do pool. O registro no livro razão seria o seguinte:
No UniswapV4, esse método de manutenção de registros é usado principalmente para operações importantes e uma variável de armazenamento chamada lockState.currencyDelta[currency] é usado no código para registrar a quantidade de alterações no saldo do token. Se o valor deste delta for positivo, ele representa o aumento esperado na quantidade de tokens no pool, enquanto um valor negativo representa a diminuição esperada na quantidade de tokens. Alternativamente, se o valor for positivo, indica a quantidade de tokens em falta no pool (o valor esperado a ser recebido), enquanto um valor negativo indica o excesso de tokens no pool (o valor esperado para os usuários retirarem). A lista a seguir mostra os efeitos de várias operações no Token Delta:
Dentre essas operações, apenas “settle” e “take” envolvem a transferência efetiva de tokens, enquanto as demais operações são as únicas responsáveis pela atualização do valor do TokenDelta.
Aqui usamos um exemplo simples para ilustrar como atualizar o TokenDelta. Vamos supor que hoje trocamos 100 TokenA por 50 TokenB:
Quando toda a operação de câmbio é concluída, tanto TokenADelta quanto TokenBDelta são zerados. Isso significa que a operação foi totalmente balanceada, garantindo assim a consistência dos saldos das contas.
Anteriormente, foi mencionado que o UniswapV4 utiliza variáveis de armazenamento para registrar TokenDelta. Porém, dentro do contrato, a leitura e gravação em variáveis de armazenamento são bastante caras. Isso nos leva a outro EIP introduzido pelo Uniswap: EIP1153 - Transient Storage Opcodes.
O UniswapV4 planeja usar os opcodes TSTORE e TLOAD fornecidos pelo EIP1153 para atualizar o TokenDelta. Variáveis de armazenamento que adotam Opcodes de armazenamento transitório serão descartadas após o término da transação (semelhante às variáveis de memória), reduzindo assim as taxas de gás.
Foi confirmado que o EIP1153 será incluído na próxima atualização de Cancún, e o UniswapV4 também declarou que entrará em operação após a atualização de Cancún, conforme relatado aqui.
fonte: https://etherworld.co/2022/12/13/transient-storage-for-beginners/
UniswapV4 introduz um mecanismo de bloqueio, o que significa que antes de executar qualquer operação Pool, você deve primeiro chamar PoolManager.lock() para adquirir um bloqueio. Durante a execução de lock(), ele verifica se o valor de TokenDelta é 0, caso contrário será revertido. Depois que PoolManager.lock() for adquirido com sucesso, ele chama a função lockAcquired() de msg.sender. Dentro da função lockAcquired() são realizadas as operações relacionadas ao Pool, como swap e modificarPosition.
O processo é ilustrado abaixo. Quando um usuário precisa realizar uma operação de Token Swap, ele deve chamar um Contrato Inteligente com a função lockAcquired() (referida como Contrato de Retorno de Chamada). O contrato de retorno de chamada primeiro chama PoolManager.lock(), e então PoolManager chama a função lockAcquired() do contrato de retorno de chamada. Dentro da função lockAcquired(), é definida a lógica relacionada às operações do Pool, como swap, liquidação e take. Por fim, quando o lock() está prestes a terminar, o PoolManager verifica se o TokenDelta associado a esta operação foi zerado, garantindo que o saldo dos ativos no Pool permaneça intacto.
Contrato Singleton significa que UniswapV4 abandonou o modelo Factory-Pool anterior. Cada Pool não é mais um Contrato Inteligente independente, mas todos os Pools compartilham um único contrato singleton. Este design, aliado ao mecanismo Flash Accounting, requer apenas a atualização das variáveis de armazenamento necessárias, reduzindo ainda mais a complexidade e o custo das operações.
No exemplo abaixo, usando UniswapV3 como exemplo, a troca de ETH por DAI exigiria pelo menos quatro transferências de Token (operações de gravação de armazenamento). Isso inclui várias alterações registradas para tokens USDC, USDT e DAI. Porém, com as melhorias no UniswapV4, aliadas ao mecanismo Flash Accounting, é necessária apenas uma transferência de Token (mover o DAI do Pool para o usuário), reduzindo significativamente o número de operações e custos.
fonte: https://twitter.com/Uniswap/status/1671208668304486404
Na última atualização do UniswapV4, o recurso mais notável é a arquitetura Hooks. Esta atualização traz grande flexibilidade em termos de disponibilidade do Pool. Ganchos são ações adicionais que são acionadas através do Contrato de Ganchos ao realizar operações específicas no Pool. Essas ações são categorizadas em inicializar (criar pool), modificarPosition (adicionar/remover liquidez), trocar e doar. Cada categoria possui ações de pré e pós-execução.
Este design permite que os usuários executem lógica personalizada antes e depois de operações específicas, tornando-o mais flexível e expandindo a funcionalidade do UniswapV4.
fonte: https://github.com/Uniswap/v4-core/blob/main/whitepaper-v4-draft.pdf
A seguir, usaremos um exemplo de Ordem Limitada para explicar o processo real de operação de Hooks no UniswapV4. Antes de começarmos, vamos explicar brevemente o princípio de implementação de Ordens Limitadas no UniswapV4.
A implementação UniswapV4 da ordem de limite funciona adicionando liquidez a uma faixa de preço específica e, em seguida, executando a operação de remoção de liquidez se a liquidez nessa faixa for trocada.
Por exemplo, digamos que adicionamos liquidez na faixa de preço de 1900-2000 para ETH, e então o preço da ETH sobe de 1800 para 2100. Neste ponto, toda a liquidez ETH que adicionamos anteriormente na faixa de preço 1900-2000 foi trocada por USDC (assumindo no pool ETH-USDC). Ao remover a liquidez neste momento, podemos obter um efeito semelhante à execução de uma ordem de mercado ETH na faixa de preço atual de 1900-2000.
Este exemplo foi retirado do GitHub do UniswapV4. Neste exemplo, o contrato Limit Order Hook fornece dois ganchos, nomeadamente afterInitialize e afterSwap. O gancho afterInitialize é usado para registrar a faixa de preço (tick) ao criar um pool, a fim de determinar quais ordens de limite foram correspondidas após alguém trocar.
Quando o usuário precisa fazer um pedido, o contrato Hook executa a operação de adição de liquidez com base na faixa de preço e quantidade especificada pelo usuário. No contrato Hook para pedidos com limite, você pode ver a função place() . A lógica principal é chamar a função lockAcquiredPlace() após adquirir o bloqueio para executar a operação de adição de liquidez, o que equivale a colocar uma ordem limite.
fonte: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L246
Depois que o usuário concluir um Swap Token dentro deste Pool, o Pool invocará a função afterSwap() do contrato Hook. A principal lógica do afterSwap é remover a liquidez das ordens colocadas anteriormente que foram executadas entre a faixa de preço anterior e a faixa de preço atual. Esse comportamento equivale ao pedido sendo atendido.
fonte: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L192
Aqui está um fluxograma que ilustra o processo de execução de uma ordem com limite:
O texto acima é todo o processo de implementação da Ordem Limitada usando o mecanismo Hook.
Os ganchos têm vários pontos interessantes que acho que vale a pena compartilhar.
A decisão de realizar operações específicas antes/depois é determinada pelo 1 byte mais à esquerda do endereço do contrato Hook. 1 byte é igual a 8 bits, o que corresponde a 8 ações adicionais. O Pool verificará se o bit dessa ação é 1 para determinar se deve invocar a função de gancho correspondente do contrato de gancho. Isso também significa que o endereço do contrato Hook precisa ser elaborado de forma específica e não pode ser escolhido arbitrariamente como contrato Hook. Este projeto visa principalmente reduzir o consumo de gás e transferir o custo para implantação contratual para alcançar operações mais eficientes. (PS: Na prática, diferentes sais CREATE2 podem ser usados para calcular com força bruta endereços de contrato que atendam às condições)
Além de poder realizar operações adicionais antes e depois de cada ação, os Hooks também suportam a implementação de taxas dinâmicas. Ao criar um Pool, você pode especificar se deseja ativar taxas dinâmicas. Se as taxas dinâmicas estiverem habilitadas, a função getFee() do contrato Hook será chamada ao trocar tokens. O contrato Hook pode determinar o valor das taxas a serem cobradas com base no estado atual do Pool. Este design permite o cálculo flexível de taxas com base nas circunstâncias reais, aumentando a flexibilidade do sistema.
Cada Pool precisa determinar o contrato Hook durante sua criação e ele não pode ser alterado posteriormente (embora Pools diferentes possam compartilhar o mesmo contrato Hook). Isso ocorre principalmente porque os Hooks são considerados parte do PoolKey, e o PoolManager usa o PoolKey para identificar em qual Pool operar. Mesmo que os ativos sejam iguais, se o contrato Hook for diferente, será considerado um Pool diferente. Este design garante que o estado e as operações de diferentes Pools possam ser gerenciados de forma independente, garantindo a consistência dos Pools. No entanto, também aumenta a complexidade do roteamento à medida que o número de Pools aumenta (talvez o UniswapX tenha sido projetado para resolver esse problema).
O UniswapV4 enfatiza claramente a expansão de todo o ecossistema Uniswap, transformando-o em infraestrutura para permitir a construção de mais serviços com base nos pools Uniswap. Isto ajuda a aumentar a competitividade do Uniswap e reduz o risco de serviços alternativos. No entanto, resta saber se alcançará o sucesso esperado. Alguns destaques incluem a combinação de Flash Accounting e EIP1153, e acreditamos que mais serviços adotarão esses recursos no futuro, levando a vários cenários de aplicação. Este é o conceito central do UniswapV4 e esperamos que forneça uma compreensão mais profunda de como o UniswapV4 funciona. Se houver algum erro no artigo, sinta-se à vontade para apontá-lo. Também acolhemos discussões e comentários.
Por fim, gostaríamos de agradecer a Anton Cheng e Ping Chen por revisarem o artigo e fornecerem comentários valiosos!
Desde o anúncio do UniswapV4, esta plataforma de swap passou por uma transformação significativa, evoluindo de uma simples plataforma de swap para um provedor de serviços de infraestrutura. Em particular, o recurso Hooks do V4 ganhou ampla atenção. Após uma pesquisa aprofundada, compilei alguns conteúdos para ajudar todos a entender melhor essa transformação e sua implementação.
O foco da inovação do UniswapV4 não é apenas melhorar a tecnologia AMM, mas também expandir o ecossistema. Especificamente, esta inovação inclui os seguintes recursos principais:
Nas seções seguintes, explicarei detalhadamente a importância desses recursos e seus princípios de implementação.
fonte: https://twitter.com/jermywkh/status/1670779830621851650
O UniswapV4 adota um método de manutenção de registros semelhante à Escrituração de Dupla Entrada para rastrear as alterações de saldo dos tokens correspondentes a cada operação. Este método de contabilidade por partidas dobradas exige o registro de cada transação em várias contas simultaneamente e a garantia de que o saldo dos ativos entre essas contas permaneça equilibrado. Por exemplo, suponha que um usuário troque 100 TokenA por 50 TokenB do pool. O registro no livro razão seria o seguinte:
No UniswapV4, esse método de manutenção de registros é usado principalmente para operações importantes e uma variável de armazenamento chamada lockState.currencyDelta[currency] é usado no código para registrar a quantidade de alterações no saldo do token. Se o valor deste delta for positivo, ele representa o aumento esperado na quantidade de tokens no pool, enquanto um valor negativo representa a diminuição esperada na quantidade de tokens. Alternativamente, se o valor for positivo, indica a quantidade de tokens em falta no pool (o valor esperado a ser recebido), enquanto um valor negativo indica o excesso de tokens no pool (o valor esperado para os usuários retirarem). A lista a seguir mostra os efeitos de várias operações no Token Delta:
Dentre essas operações, apenas “settle” e “take” envolvem a transferência efetiva de tokens, enquanto as demais operações são as únicas responsáveis pela atualização do valor do TokenDelta.
Aqui usamos um exemplo simples para ilustrar como atualizar o TokenDelta. Vamos supor que hoje trocamos 100 TokenA por 50 TokenB:
Quando toda a operação de câmbio é concluída, tanto TokenADelta quanto TokenBDelta são zerados. Isso significa que a operação foi totalmente balanceada, garantindo assim a consistência dos saldos das contas.
Anteriormente, foi mencionado que o UniswapV4 utiliza variáveis de armazenamento para registrar TokenDelta. Porém, dentro do contrato, a leitura e gravação em variáveis de armazenamento são bastante caras. Isso nos leva a outro EIP introduzido pelo Uniswap: EIP1153 - Transient Storage Opcodes.
O UniswapV4 planeja usar os opcodes TSTORE e TLOAD fornecidos pelo EIP1153 para atualizar o TokenDelta. Variáveis de armazenamento que adotam Opcodes de armazenamento transitório serão descartadas após o término da transação (semelhante às variáveis de memória), reduzindo assim as taxas de gás.
Foi confirmado que o EIP1153 será incluído na próxima atualização de Cancún, e o UniswapV4 também declarou que entrará em operação após a atualização de Cancún, conforme relatado aqui.
fonte: https://etherworld.co/2022/12/13/transient-storage-for-beginners/
UniswapV4 introduz um mecanismo de bloqueio, o que significa que antes de executar qualquer operação Pool, você deve primeiro chamar PoolManager.lock() para adquirir um bloqueio. Durante a execução de lock(), ele verifica se o valor de TokenDelta é 0, caso contrário será revertido. Depois que PoolManager.lock() for adquirido com sucesso, ele chama a função lockAcquired() de msg.sender. Dentro da função lockAcquired() são realizadas as operações relacionadas ao Pool, como swap e modificarPosition.
O processo é ilustrado abaixo. Quando um usuário precisa realizar uma operação de Token Swap, ele deve chamar um Contrato Inteligente com a função lockAcquired() (referida como Contrato de Retorno de Chamada). O contrato de retorno de chamada primeiro chama PoolManager.lock(), e então PoolManager chama a função lockAcquired() do contrato de retorno de chamada. Dentro da função lockAcquired(), é definida a lógica relacionada às operações do Pool, como swap, liquidação e take. Por fim, quando o lock() está prestes a terminar, o PoolManager verifica se o TokenDelta associado a esta operação foi zerado, garantindo que o saldo dos ativos no Pool permaneça intacto.
Contrato Singleton significa que UniswapV4 abandonou o modelo Factory-Pool anterior. Cada Pool não é mais um Contrato Inteligente independente, mas todos os Pools compartilham um único contrato singleton. Este design, aliado ao mecanismo Flash Accounting, requer apenas a atualização das variáveis de armazenamento necessárias, reduzindo ainda mais a complexidade e o custo das operações.
No exemplo abaixo, usando UniswapV3 como exemplo, a troca de ETH por DAI exigiria pelo menos quatro transferências de Token (operações de gravação de armazenamento). Isso inclui várias alterações registradas para tokens USDC, USDT e DAI. Porém, com as melhorias no UniswapV4, aliadas ao mecanismo Flash Accounting, é necessária apenas uma transferência de Token (mover o DAI do Pool para o usuário), reduzindo significativamente o número de operações e custos.
fonte: https://twitter.com/Uniswap/status/1671208668304486404
Na última atualização do UniswapV4, o recurso mais notável é a arquitetura Hooks. Esta atualização traz grande flexibilidade em termos de disponibilidade do Pool. Ganchos são ações adicionais que são acionadas através do Contrato de Ganchos ao realizar operações específicas no Pool. Essas ações são categorizadas em inicializar (criar pool), modificarPosition (adicionar/remover liquidez), trocar e doar. Cada categoria possui ações de pré e pós-execução.
Este design permite que os usuários executem lógica personalizada antes e depois de operações específicas, tornando-o mais flexível e expandindo a funcionalidade do UniswapV4.
fonte: https://github.com/Uniswap/v4-core/blob/main/whitepaper-v4-draft.pdf
A seguir, usaremos um exemplo de Ordem Limitada para explicar o processo real de operação de Hooks no UniswapV4. Antes de começarmos, vamos explicar brevemente o princípio de implementação de Ordens Limitadas no UniswapV4.
A implementação UniswapV4 da ordem de limite funciona adicionando liquidez a uma faixa de preço específica e, em seguida, executando a operação de remoção de liquidez se a liquidez nessa faixa for trocada.
Por exemplo, digamos que adicionamos liquidez na faixa de preço de 1900-2000 para ETH, e então o preço da ETH sobe de 1800 para 2100. Neste ponto, toda a liquidez ETH que adicionamos anteriormente na faixa de preço 1900-2000 foi trocada por USDC (assumindo no pool ETH-USDC). Ao remover a liquidez neste momento, podemos obter um efeito semelhante à execução de uma ordem de mercado ETH na faixa de preço atual de 1900-2000.
Este exemplo foi retirado do GitHub do UniswapV4. Neste exemplo, o contrato Limit Order Hook fornece dois ganchos, nomeadamente afterInitialize e afterSwap. O gancho afterInitialize é usado para registrar a faixa de preço (tick) ao criar um pool, a fim de determinar quais ordens de limite foram correspondidas após alguém trocar.
Quando o usuário precisa fazer um pedido, o contrato Hook executa a operação de adição de liquidez com base na faixa de preço e quantidade especificada pelo usuário. No contrato Hook para pedidos com limite, você pode ver a função place() . A lógica principal é chamar a função lockAcquiredPlace() após adquirir o bloqueio para executar a operação de adição de liquidez, o que equivale a colocar uma ordem limite.
fonte: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L246
Depois que o usuário concluir um Swap Token dentro deste Pool, o Pool invocará a função afterSwap() do contrato Hook. A principal lógica do afterSwap é remover a liquidez das ordens colocadas anteriormente que foram executadas entre a faixa de preço anterior e a faixa de preço atual. Esse comportamento equivale ao pedido sendo atendido.
fonte: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L192
Aqui está um fluxograma que ilustra o processo de execução de uma ordem com limite:
O texto acima é todo o processo de implementação da Ordem Limitada usando o mecanismo Hook.
Os ganchos têm vários pontos interessantes que acho que vale a pena compartilhar.
A decisão de realizar operações específicas antes/depois é determinada pelo 1 byte mais à esquerda do endereço do contrato Hook. 1 byte é igual a 8 bits, o que corresponde a 8 ações adicionais. O Pool verificará se o bit dessa ação é 1 para determinar se deve invocar a função de gancho correspondente do contrato de gancho. Isso também significa que o endereço do contrato Hook precisa ser elaborado de forma específica e não pode ser escolhido arbitrariamente como contrato Hook. Este projeto visa principalmente reduzir o consumo de gás e transferir o custo para implantação contratual para alcançar operações mais eficientes. (PS: Na prática, diferentes sais CREATE2 podem ser usados para calcular com força bruta endereços de contrato que atendam às condições)
Além de poder realizar operações adicionais antes e depois de cada ação, os Hooks também suportam a implementação de taxas dinâmicas. Ao criar um Pool, você pode especificar se deseja ativar taxas dinâmicas. Se as taxas dinâmicas estiverem habilitadas, a função getFee() do contrato Hook será chamada ao trocar tokens. O contrato Hook pode determinar o valor das taxas a serem cobradas com base no estado atual do Pool. Este design permite o cálculo flexível de taxas com base nas circunstâncias reais, aumentando a flexibilidade do sistema.
Cada Pool precisa determinar o contrato Hook durante sua criação e ele não pode ser alterado posteriormente (embora Pools diferentes possam compartilhar o mesmo contrato Hook). Isso ocorre principalmente porque os Hooks são considerados parte do PoolKey, e o PoolManager usa o PoolKey para identificar em qual Pool operar. Mesmo que os ativos sejam iguais, se o contrato Hook for diferente, será considerado um Pool diferente. Este design garante que o estado e as operações de diferentes Pools possam ser gerenciados de forma independente, garantindo a consistência dos Pools. No entanto, também aumenta a complexidade do roteamento à medida que o número de Pools aumenta (talvez o UniswapX tenha sido projetado para resolver esse problema).
O UniswapV4 enfatiza claramente a expansão de todo o ecossistema Uniswap, transformando-o em infraestrutura para permitir a construção de mais serviços com base nos pools Uniswap. Isto ajuda a aumentar a competitividade do Uniswap e reduz o risco de serviços alternativos. No entanto, resta saber se alcançará o sucesso esperado. Alguns destaques incluem a combinação de Flash Accounting e EIP1153, e acreditamos que mais serviços adotarão esses recursos no futuro, levando a vários cenários de aplicação. Este é o conceito central do UniswapV4 e esperamos que forneça uma compreensão mais profunda de como o UniswapV4 funciona. Se houver algum erro no artigo, sinta-se à vontade para apontá-lo. Também acolhemos discussões e comentários.
Por fim, gostaríamos de agradecer a Anton Cheng e Ping Chen por revisarem o artigo e fornecerem comentários valiosos!