Autor: Sun
As transações on-chain incluem transferências simples de uma única transação, interações de contratos DeFi, interações de vários contratos DeFi, arbitragem de empréstimo relâmpago, propostas de governança, transações cross-chain, etc. Nesta seção, vamos começar com um aquecimento, começando com algo simples. Vou explicar quais informações do explorador de blockchain Etherscan geralmente são relevantes para nós e, em seguida, usaremos a ferramenta de análise de transações Phalcon para analisar essas transações, desde transferências simples, swaps na UniSWAP, adição de liquidez no Curve 3pool, propostas de governança no Compound e diferenças nas chamadas de empréstimo relâmpago.
- Primeiro, você precisa instalar o Foundry no ambiente. Consulte as instruções para saber como instalar.
- O teste principal será feito com o Forge test. Se você estiver usando o Foundry pela primeira vez, consulte o Foundry book, Foundry @EthCC e WTF Solidity - Foundry
- Cada blockchain tem seu próprio explorador de blockchain. Nesta seção, usaremos a rede principal Ethereum como exemplo e faremos a análise através do Etherscan.
- Geralmente, os campos que eu gostaria de ver incluem:
- Transaction Action: Como as transferências de tokens ERC-20 podem ser complicadas em transações complexas e de difícil leitura, podemos usar a Transaction Action para ver as ações-chave, mas nem todas as transações têm esse campo.
- From: O endereço da carteira de origem que executou a transação (msg.sender)
- Interacted With (To): O contrato com o qual houve interação
- ERC-20 Tokens Transferred: O processo de transferência de tokens
- Input Data: Os dados de entrada originais da transação, que mostram qual função foi chamada e quais valores foram passados
- Se você ainda não sabe quais ferramentas comumente usadas, pode revisar a primeira aula sobre ferramentas de análise de transações
A partir do exemplo acima, podemos interpretar da seguinte forma:
From: Endereço da carteira de origem que enviou a transação
Interacted With (To): Contrato Tether USD (USDT)
ERC-20 Tokens Transferred: Transferência de 651,13 USDT da carteira do usuário A para a carteira do usuário B
Input Data: Chamada da função transfer
Podemos usar o phalcon para ver que há apenas uma chamada Call USDT.transfer
no fluxo de chamadas. É importante observar o valor. Como a EVM não suporta operações com números de ponto flutuante, a precisão é usada para representar os valores. Cada token tem sua própria precisão, e é importante prestar atenção ao tamanho da precisão. O padrão ERC-20 tem uma precisão de 18, mas há exceções, como o USDT, que tem uma precisão de 6. Portanto, o valor passado é 651130000. Se a precisão não for tratada corretamente, podem ocorrer problemas. Você pode verificar a precisão consultando o contrato do token no Etherscan.
A partir do exemplo acima, podemos interpretar da seguinte forma:
Transaction Action: É óbvio que o usuário está fazendo um swap na Uniswap, trocando 12.716 USDT por 7.118 UNDEAD.
From: Endereço da carteira de origem que enviou a transação
Interacted With (To): Neste exemplo, é um contrato MEV Bot que chama o contrato Uniswap
ERC-20 Tokens Transferred: O processo de troca de tokens
Podemos usar o phalcon para ver que o MEV Bot chama o contrato do par de negociação Uniswap V2 USDT/UNDEAD e chama a função swap para trocar os tokens.
Usamos o Foundry para simular a operação de trocar 1 BTC por DAI na Uniswap. Consulte o código de exemplo e execute o seguinte comando:
forge test --contracts ./src/test/Uniswapv2.sol -vvvv
Como mostrado na imagem abaixo, usamos a função Uniswap_v2_router.swapExactTokensForTokens para trocar 1 BTC por 16.788 DAI.
A partir do exemplo acima, podemos interpretar da seguinte forma:
Adicionando liquidez no Curve 3pool
From: Endereço da carteira de origem que enviou a transação
Interacted With (To): Pool DAI/USDC/USDT do Curve.fi
ERC-20 Tokens Transferred: O usuário A depositou 3.524.968,44 USDT no Curve 3pool e o Curve emitiu 3.447.897,54 tokens 3Crv para o usuário A.
Podemos usar o phalcon para ver que foram executadas três etapas: 1. add_liquidity 2. transferFrom 3. mint
A partir do exemplo acima, podemos interpretar da seguinte forma: O usuário enviou uma proposta para o contrato de governança do Compound e você pode ver o conteúdo da proposta clicando em "Decode Input Data" no Etherscan.
Podemos usar o phalcon para ver que a proposta foi enviada chamando a função propose e obteve o número da proposta 44.
Aqui, usamos o Foundry para simular como usar um flashswap na Uniswap. Consulte a introdução oficial ao Flash swap e o código de exemplo.
forge test --contracts ./src/test/Uniswapv2_flashswap.sol -vv
Neste exemplo, usamos um flashswap na Uniswap para emprestar 100 WETH e depois devolvê-lo à Uniswap. Observe que uma taxa de 0,3% deve ser paga ao devolver.
A partir do fluxo de chamadas abaixo, podemos ver que a função swap é chamada para fazer o flashswap e, em seguida, a função de retorno uniswapV2Call é usada para devolver o empréstimo.
Vamos diferenciar brevemente a diferença entre Flashloan e Flashswap. Ambos permitem emprestar tokens sem a necessidade de garantia e devolvê-los na mesma transação, caso contrário, a transação falhará. No caso de um flashloan, se você emprestar token0 usando token1, precisará devolver token0. No caso de um flashswap, se você emprestar token0, poderá devolver token0 ou token1. É mais flexível.
Para mais operações básicas de DeFi, consulte DeFiLabs
Os cheatcodes do Foundry são essenciais para análise on-chain. Aqui, vou apresentar algumas funções comumente usadas. Para mais informações, consulte a Referência de Cheatcodes
- createSelectFork: Especifica qual rede e altura do bloco devem ser copiadas para o teste. Observe que o RPC de cada blockchain deve ser definido no arquivo foundry.toml
- deal: Define o saldo da carteira de teste
- Define o saldo de ETH
deal(address(this), 3 ether);
- Define o saldo de tokens
deal(address(USDC), address(this), 1 * 1e18);
- Define o saldo de ETH
- prank: Simula a identidade de uma carteira específica. Somente a próxima chamada será afetada. O próximo msg.sender será o endereço da carteira especificada. Por exemplo, simular uma transferência usando uma carteira de baleia.
- startPrank: Simula a identidade de uma carteira específica. Até que
stopPrank()
seja executado, todos os msg.sender serão o endereço da carteira especificada. - label: Rotula um endereço de carteira para facilitar a leitura durante a depuração com o Foundry
- roll: Ajusta a altura do bloco
- warp: Ajusta o block.timestamp
Obrigado por assistir, estamos prontos para a próxima aula.