A arbitragem triangular serve como uma estratégia na negociação de câmbio de criptomoedas, aproveitando variações nas taxas de câmbio dentro de um único mercado ou em vários mercados. Este método compreende três negociações sequenciais: trocar uma criptomoeda inicial por uma segunda, a segunda por uma terceira e, por fim, a terceira criptomoeda de volta para a inicial, todas com o objetivo de gerar lucro. Assim, o termo 'triangular' encapsula o seu processo de três etapas.
Imagem gerada por IA
Na DEX, as oportunidades de arbitragem triangular são geralmente causadas por diferenças de liquidez em vários pools. Elas costumam ser de curta duração, durando apenas alguns segundos ou até menos, pois a exchange ajusta rapidamente quaisquer discrepâncias de preços. Como resultado, algoritmos de negociação automatizados equipados para executar rapidamente negociações são empregados para capitalizar sobre essas diferenças passageiras. Para ajudar a entender o conceito, aqui está um exemplo:
A transação triangular acima começa a partir de 01 - comprando 1 wBTC com $60.000 USDC, seguido por 02 - comprando 16 WETH com 1 wBTC e termina com 03 - vendendo 16 WETH por $66.000 USDC. No final da jornada, teríamos obtido $6.000 USDC como lucro.
Existem dois estilos de trocas multi-hop disponíveis no Uniswap v3: Entrada Exata e Saída Exata. Como os nomes sugerem, o primeiro espera um token com a quantidade exata como entrada da troca e, no final, um token com quantidade será produzido às taxas de câmbio; o último espera uma quantidade exata especificada como saída, apenas a quantidade suficiente de token como entrada pode satisfazer a troca nas taxas de câmbio.
Com a natureza comercial da arbitragem triangular, gostaríamos de pegar um token com a quantidade exata como entrada, trocá-lo por outra cripto e depois trocar novamente pelo token original para obter lucro, como desejamos.
constante de endereço SWAP_ROUTER_02 = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45;
endereço constante WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
endereço constante USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
endereço constante DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
contrato MultiHopSwap { usando SafeERC20 para IERC20;ISwapRouter02 privado constante ROUTER = ISwapRouter02(SWAP_ROUTER_02);uint256 privado constante MAX_INT = 115792089237316195423570985008687907853269984665640564039457584007913129639935;função swapExactInputMultiHop(uint256 amountIn) externo { IERC20(USDC).safeApprove(address(ROUTER), MAX_INT); IERC20(WETH).safeApprove(address(ROUTER), MAX_INT); IERC20(DAI).safeApprove(address(ROUTER), MAX_INT); bytes memory path = abi.encodePacked(USDC, uint24(3000), WETH, uint24(3000), DAI, uint24(3000), USDC); ISwapRouter02.ExactInputParams memory params = ISwapRouter02.ExactInputParams({ path: path, recipient: address(this), amountIn: amountIn, amountOutMinimum: 1 }); ROUTER.exactInput(params); }}
Os routers desempenham um papel crucial na facilitação da prestação de liquidez. Uma vez que são stateless e não têm saldos de tokens, os routers podem ser substituídos com segurança. Por esta razão, os routers têm números de lançamento, começando em 01. Na nossa implementação, usamos o Router02 em 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45na rede principal.
SafeERC20 é uma camada de proteção criada em torno das transações ERC20, garantindo interações seguras com tokens ERC20 dentro do nosso contrato. Ao contrário das funções ERC20 regulares, o SafeERC20 melhora a segurança verificando os valores booleanos de retorno das operações ERC20. Se alguma operação falhar, a transação é revertida, minimizando os riscos. Além disso, o SafeERC20 acomoda tokens ERC20 não padrão que não possuem valores booleanos de retorno, proporcionando flexibilidade e robustez na gestão de tokens. Ao aprovar a quantidade máxima, permitimos que o Router02 transfira tokens em nosso nome. Sem fazer isso, você esperaria ver uma mensagem de erro STF em que STF significa que a execução é revertida pela asserção require na função TransferHelper.safeTransferFrom.
A seguir, vamos analisar como é definido um caminho triangular:
bytes memory path = abi.encodePacked(USDC, uint24(3000),
WETH, uint24(3000), DAI, uint24(3000), USDC) ;
Através de abi.encodePacked, o Solidity compacta de forma apertada múltiplos valores sem adicionar qualquer preenchimento. Concatena os dados binários brutos de cada parâmetro. Não é difícil de perceber que os parâmetros sequencializaram as trocas com taxas entre os pares de criptomoedas. O caminho começa no USDC e termina no USDC esperando um lucro. Depois é envolvido por ExactInputParams com outros parâmetros obrigatórios e alimentado no roteador para trocas multi-hop.
Usamos a mesma técnica porforking mainnet com impersonation. Uma vez que 10 USDC são verificados como creditados no contrato, as trocas multi-hop podem ser acionadas da seguinte forma:
it("realiza troca de várias etapas", async () => {balance = await swap.tokenBalance(USDC);console.log(`Saldo atual de USDC = ${balance}`);console.log(`Trocar ${initialFundingHuman} USDC`);const tx = await swap.swapExactInputMultiHop(ethers.parseUnits(initialFundingHuman, DECIMALS));receipt = await tx.wait();balance = await swap.tokenBalance(USDC);console.log(`Saldo atual de USDC = ${balance}`);expect(balance).not.equal(0);});
O resultado do teste deve parecer-se com abaixo:
Saldo USDC da baleia: 170961218210457n
Impersonation Started.
Impersonação concluída.
Saldo atual de USDC = 100000000
Trocar 100 USDC
Saldo atual de USDC = 91677417
Depois de passar pelos obstáculos, perdemos dinheiro — Obviamente, o caminho com taxas à vista não estava a nosso favor, mas você tem uma ideia de como a arbitragem triangular deve ser feita usando trocas de várias etapas na Uniswap v3.
Não disse eua fonte de financiamento mais poderosa no ecossistema DeFi é Flash empréstimo? Não precisará de muita criatividade da sua parte para construir uma estratégia de negociação de arbitragem triangular financiada por empréstimo Flash usando tanto o empréstimo Flash quanto as trocas multihop que eu ensinei. Uma lógica combinada pode ser explicada pelo diagrama de sequência atualizado conforme abaixo:
Diagrama de sequência para arbitragem triangular financiada por empréstimo flash na Uniswap v3 (Ignoradas algumas operações para simplicidade)
Confira meu código-fonte para empréstimo instantâneo e trocas Multihop implementadas na Uniswap v3 — https://medium.com/cryptocurrency-scripts/flash-loan-on-uniswap-v3-84bca2bfe255, digira o diagrama de sequência e faça o seu próprio trabalho para concluir os contratos inteligentes combinados.
A primeira coisa que queremos olhar é o caminho que é composto pela sequência das 3 negociações: Para ser lucrativo, eles devem ser os 3 pares certos de criptomoedas com as taxas certas. Para encontrar toda essa correção, você precisa desenvolver um programa que permuta pares negociáveis no padrão de arbitragem triangular e simula as trocas para verificar a lucratividade. A recuperação de taxas da blockchain pode ser lenta e irá ainda mais desacelerar o processo se houver muitos caminhos esperando para serem verificados quanto à lucratividade. Você pode querer reduzir a lista de caminhos triangulares calculando Lucro e Perda com base nos preços de superfície fornecidos pelos pontos finais de preços do GraphQL de uma DEX, se houver.aqui vem Uniswap v3’s) , pois as APIs do GraphQL são muito mais rápidas do que a blockchain para fornecer dados de cotação. Uma vez que os caminhos são selecionados, execute-os com cotações obtidas da cadeia para um cálculo mais preciso do lucro e perda.
Impulsionar o seu investimento com empréstimo relâmpagopode estender ainda mais o lucro — emprestar tokens a baixo juro e investi-los com uma estratégia lucrativa será sempre uma boa ideia. Teoricamente, desde que o lucro bruto seja suficiente para cobrir a taxa de empréstimo Flash e as taxas de troca, a estratégia de arbitragem triangular será considerada lucrativa. Um truque crítico para proteger o seu lucro e mitigar o risco geral de negociação é ter uma lógica no seu contrato de negociação para falhar a transação de empréstimo Flash se a verificação de lucratividade bruta falhar, pois quando a transação falha, todas as operações serão revertidas e você não precisa suportar a perda e até mesmo as taxas da transação. Esta peça de lógica funcionará como um guarda-redes abrangente para evitar escorregamentos ou movimentos na taxa de câmbio que não nos favoreçam.
Dito isto, independentemente do sucesso ou fracasso da transação, as taxas de gás são algo de que nunca se pode escapar e podem ser a principal causa de perda de dinheiro na arbitragem triangular. Avalie sempre as taxas de gás para a transação da sua estratégia e leve isso em consideração no cálculo da rentabilidade líquida. Por favor, consulte os casos de teste de estimativa de taxas de gás no meu código-fonte.
A arbitragem triangular serve como uma estratégia na negociação de câmbio de criptomoedas, aproveitando variações nas taxas de câmbio dentro de um único mercado ou em vários mercados. Este método compreende três negociações sequenciais: trocar uma criptomoeda inicial por uma segunda, a segunda por uma terceira e, por fim, a terceira criptomoeda de volta para a inicial, todas com o objetivo de gerar lucro. Assim, o termo 'triangular' encapsula o seu processo de três etapas.
Imagem gerada por IA
Na DEX, as oportunidades de arbitragem triangular são geralmente causadas por diferenças de liquidez em vários pools. Elas costumam ser de curta duração, durando apenas alguns segundos ou até menos, pois a exchange ajusta rapidamente quaisquer discrepâncias de preços. Como resultado, algoritmos de negociação automatizados equipados para executar rapidamente negociações são empregados para capitalizar sobre essas diferenças passageiras. Para ajudar a entender o conceito, aqui está um exemplo:
A transação triangular acima começa a partir de 01 - comprando 1 wBTC com $60.000 USDC, seguido por 02 - comprando 16 WETH com 1 wBTC e termina com 03 - vendendo 16 WETH por $66.000 USDC. No final da jornada, teríamos obtido $6.000 USDC como lucro.
Existem dois estilos de trocas multi-hop disponíveis no Uniswap v3: Entrada Exata e Saída Exata. Como os nomes sugerem, o primeiro espera um token com a quantidade exata como entrada da troca e, no final, um token com quantidade será produzido às taxas de câmbio; o último espera uma quantidade exata especificada como saída, apenas a quantidade suficiente de token como entrada pode satisfazer a troca nas taxas de câmbio.
Com a natureza comercial da arbitragem triangular, gostaríamos de pegar um token com a quantidade exata como entrada, trocá-lo por outra cripto e depois trocar novamente pelo token original para obter lucro, como desejamos.
constante de endereço SWAP_ROUTER_02 = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45;
endereço constante WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
endereço constante USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
endereço constante DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
contrato MultiHopSwap { usando SafeERC20 para IERC20;ISwapRouter02 privado constante ROUTER = ISwapRouter02(SWAP_ROUTER_02);uint256 privado constante MAX_INT = 115792089237316195423570985008687907853269984665640564039457584007913129639935;função swapExactInputMultiHop(uint256 amountIn) externo { IERC20(USDC).safeApprove(address(ROUTER), MAX_INT); IERC20(WETH).safeApprove(address(ROUTER), MAX_INT); IERC20(DAI).safeApprove(address(ROUTER), MAX_INT); bytes memory path = abi.encodePacked(USDC, uint24(3000), WETH, uint24(3000), DAI, uint24(3000), USDC); ISwapRouter02.ExactInputParams memory params = ISwapRouter02.ExactInputParams({ path: path, recipient: address(this), amountIn: amountIn, amountOutMinimum: 1 }); ROUTER.exactInput(params); }}
Os routers desempenham um papel crucial na facilitação da prestação de liquidez. Uma vez que são stateless e não têm saldos de tokens, os routers podem ser substituídos com segurança. Por esta razão, os routers têm números de lançamento, começando em 01. Na nossa implementação, usamos o Router02 em 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45na rede principal.
SafeERC20 é uma camada de proteção criada em torno das transações ERC20, garantindo interações seguras com tokens ERC20 dentro do nosso contrato. Ao contrário das funções ERC20 regulares, o SafeERC20 melhora a segurança verificando os valores booleanos de retorno das operações ERC20. Se alguma operação falhar, a transação é revertida, minimizando os riscos. Além disso, o SafeERC20 acomoda tokens ERC20 não padrão que não possuem valores booleanos de retorno, proporcionando flexibilidade e robustez na gestão de tokens. Ao aprovar a quantidade máxima, permitimos que o Router02 transfira tokens em nosso nome. Sem fazer isso, você esperaria ver uma mensagem de erro STF em que STF significa que a execução é revertida pela asserção require na função TransferHelper.safeTransferFrom.
A seguir, vamos analisar como é definido um caminho triangular:
bytes memory path = abi.encodePacked(USDC, uint24(3000),
WETH, uint24(3000), DAI, uint24(3000), USDC) ;
Através de abi.encodePacked, o Solidity compacta de forma apertada múltiplos valores sem adicionar qualquer preenchimento. Concatena os dados binários brutos de cada parâmetro. Não é difícil de perceber que os parâmetros sequencializaram as trocas com taxas entre os pares de criptomoedas. O caminho começa no USDC e termina no USDC esperando um lucro. Depois é envolvido por ExactInputParams com outros parâmetros obrigatórios e alimentado no roteador para trocas multi-hop.
Usamos a mesma técnica porforking mainnet com impersonation. Uma vez que 10 USDC são verificados como creditados no contrato, as trocas multi-hop podem ser acionadas da seguinte forma:
it("realiza troca de várias etapas", async () => {balance = await swap.tokenBalance(USDC);console.log(`Saldo atual de USDC = ${balance}`);console.log(`Trocar ${initialFundingHuman} USDC`);const tx = await swap.swapExactInputMultiHop(ethers.parseUnits(initialFundingHuman, DECIMALS));receipt = await tx.wait();balance = await swap.tokenBalance(USDC);console.log(`Saldo atual de USDC = ${balance}`);expect(balance).not.equal(0);});
O resultado do teste deve parecer-se com abaixo:
Saldo USDC da baleia: 170961218210457n
Impersonation Started.
Impersonação concluída.
Saldo atual de USDC = 100000000
Trocar 100 USDC
Saldo atual de USDC = 91677417
Depois de passar pelos obstáculos, perdemos dinheiro — Obviamente, o caminho com taxas à vista não estava a nosso favor, mas você tem uma ideia de como a arbitragem triangular deve ser feita usando trocas de várias etapas na Uniswap v3.
Não disse eua fonte de financiamento mais poderosa no ecossistema DeFi é Flash empréstimo? Não precisará de muita criatividade da sua parte para construir uma estratégia de negociação de arbitragem triangular financiada por empréstimo Flash usando tanto o empréstimo Flash quanto as trocas multihop que eu ensinei. Uma lógica combinada pode ser explicada pelo diagrama de sequência atualizado conforme abaixo:
Diagrama de sequência para arbitragem triangular financiada por empréstimo flash na Uniswap v3 (Ignoradas algumas operações para simplicidade)
Confira meu código-fonte para empréstimo instantâneo e trocas Multihop implementadas na Uniswap v3 — https://medium.com/cryptocurrency-scripts/flash-loan-on-uniswap-v3-84bca2bfe255, digira o diagrama de sequência e faça o seu próprio trabalho para concluir os contratos inteligentes combinados.
A primeira coisa que queremos olhar é o caminho que é composto pela sequência das 3 negociações: Para ser lucrativo, eles devem ser os 3 pares certos de criptomoedas com as taxas certas. Para encontrar toda essa correção, você precisa desenvolver um programa que permuta pares negociáveis no padrão de arbitragem triangular e simula as trocas para verificar a lucratividade. A recuperação de taxas da blockchain pode ser lenta e irá ainda mais desacelerar o processo se houver muitos caminhos esperando para serem verificados quanto à lucratividade. Você pode querer reduzir a lista de caminhos triangulares calculando Lucro e Perda com base nos preços de superfície fornecidos pelos pontos finais de preços do GraphQL de uma DEX, se houver.aqui vem Uniswap v3’s) , pois as APIs do GraphQL são muito mais rápidas do que a blockchain para fornecer dados de cotação. Uma vez que os caminhos são selecionados, execute-os com cotações obtidas da cadeia para um cálculo mais preciso do lucro e perda.
Impulsionar o seu investimento com empréstimo relâmpagopode estender ainda mais o lucro — emprestar tokens a baixo juro e investi-los com uma estratégia lucrativa será sempre uma boa ideia. Teoricamente, desde que o lucro bruto seja suficiente para cobrir a taxa de empréstimo Flash e as taxas de troca, a estratégia de arbitragem triangular será considerada lucrativa. Um truque crítico para proteger o seu lucro e mitigar o risco geral de negociação é ter uma lógica no seu contrato de negociação para falhar a transação de empréstimo Flash se a verificação de lucratividade bruta falhar, pois quando a transação falha, todas as operações serão revertidas e você não precisa suportar a perda e até mesmo as taxas da transação. Esta peça de lógica funcionará como um guarda-redes abrangente para evitar escorregamentos ou movimentos na taxa de câmbio que não nos favoreçam.
Dito isto, independentemente do sucesso ou fracasso da transação, as taxas de gás são algo de que nunca se pode escapar e podem ser a principal causa de perda de dinheiro na arbitragem triangular. Avalie sempre as taxas de gás para a transação da sua estratégia e leve isso em consideração no cálculo da rentabilidade líquida. Por favor, consulte os casos de teste de estimativa de taxas de gás no meu código-fonte.