Neste artigo, forneceremos uma visão geral da negociação (trading) de arbitragem e explicaremos como você pode usar os utilitários MemPool BlockVision para criar seu próprio bot de arbitragem. Ao integrar os nossos serviços, você pode reduzir significativamente os custos técnicos associados a este tipo de negociação. Também discutiremos os benefícios de usar um bot de arbitragem e como ele pode ajudá-lo a aproveitar as ineficiências do mercado e maximizar seus lucros.
O que é negociação de arbitragem?
A negociação de arbitragem é uma estratégia que envolve aproveitar as diferenças de preços em diferentes mercados ou bolsas para o mesmo ativo. Ao comprar um ativo onde o preço é relativamente baixo e vendê-lo em um mercado onde o preço é mais alto, os negociantes (traders) podem lucrar com a diferença de preços. Esse tipo de negociação é frequentemente usado para explorar ineficiências nos mercados financeiros e pode ser realizado utilizando vários instrumentos financeiros, como ações, títulos, moedas e derivativos. Embora possa ser uma estratégia complexa e arriscada, também oferece oportunidades para os negociantes obterem lucros rápidos. No mundo das criptomoedas, a concorrência também é acirrada, tornando importante que os negociantes usem ferramentas como bots de arbitragem para ganhar vantagem no mercado.
Prática — Integrando a coleção de ferramentas MemPool BlockVision em seu bot de arbitragem
Por quê — Para monitorar o MemPool e obter oportunidades de arbitragem um passo à frente
Para aqueles envolvidos na negociação de arbitragem on-chain, a velocidade com que podem procurar oportunidades de arbitragem é um fator crucial para seu sucesso. No mundo das criptomoedas, todas as transações devem ser enviadas para o MemPool e empacotadas pelos mineradores antes de serem adicionadas à blockchain. Ao monitorar as transações que ainda não estão na cadeia no MemPool, podemos encontrar oportunidades de arbitragem mais rapidamente do que outros negociantes de arbitragem que apenas buscam oportunidades com base em transações que já estão na blockchain. Isso nos permite concluir a busca por oportunidades de arbitragem um passo à frente da concorrência e potencialmente fazer negociações mais lucrativas.
Por exemplo, suponha que nosso objetivo de arbitragem seja aproveitar as diferenças de preço entre pares de tokens na DEX CFAMM. Se estivermos ouvindo o mempool e virmos uma transação para o par de tokens em que estamos interessados, e isso causar uma flutuação de preço significativa, podemos usar a fórmula de negociação simples x * y = k
para calcular o preço mais recente do token com base no número de transaçõese as reservas do pool correspondente. Se descobrirmos um spread (é a diferença entre o preço da compra e o preço da venda de uma transação financeira) lucrativo após nosso cálculo, encontramos com sucesso uma oportunidade de arbitragem por meio do MemPool antes que a transação seja adicionada à blockchain. Isso nos permite agir rapidamente e potencialmente lucrar com a diferença de preço antes que outros negociantes tenham a chance de fazê-lo.
Monitorar o MemPool
Para integrar o MemPool em bots de arbitragem, primeiro precisamos integrar o serviço de escuta MemPool BlockVision em nosso software. Suponha que os pools que precisamos ouvir sejam pares de negociação ETH-BTC na Uniswap e Sushiswap. Em seguida, podemos escrever o seguinte código para monitorar o par de negociação em duas corretoras diferentes.
Os endereços na cadeia são:
UniswapV2 WETH-WBTC: 0xbb2b8038a1640196fbe3e38816f3e67cba72d940
Sushiswap WETH-WBTC: 0xCEfF51756c56CeFFCA006cD410B03FFC46dd3a58
O MemPool pode conter transações que não são relevantes para sua estratégia de arbitragem, como transações para diferentes pares de tokens ou transações que usam um método diferente (methodsId: 0x022c0d9f
). No passado, os negociantes de arbitragem tinham que escrever seus próprios programas para filtrar essas transações desnecessárias, mas com o serviço de monitoramento MemPool BlockVision, você pode facilmente filtrar as transações por endereço e um ou mais IDs de método em um só lugar. Isso torna mais fácil e eficiente encontrar as oportunidades de arbitragem que você esteja procurando sem ter que filtrar transações irrelevantes.
#!/usr/bin/env node
var WebSocketClient = require('websocket').client;
var client = new WebSocketClient();
client.on('connectFailed', function(error) {
console.log('Connect Error: ' + error.toString());
});
client.on('connect', function(connection) {
console.log('WebSocket Client Connected');
connection.on('error', function(error) {
console.log("Connection Error: " + error.toString());
});
connection.on('close', function() {
console.log('echo-protocol Connection Closed');
});
connection.on('message', function(message) {
if (message.type === 'utf8') {
console.log("Received: '" + message.utf8Data + "'");
}
});
function bvPendingTransaction() {
if (connection.connected){
// subscrever transações relacionadas com o par de token
e o método de troca.
var payload = '{"jsonrpc":"2.0","id": 2, "method": "eth_subscribe", "params": ["bvPendingTransactions", {"toAddress": ["0xbb2b8038a1640196fbe3e38816f3e67cba72d940", "0xCEfF51756c56CeFFCA006cD410B03FFC46dd3a58"], "methodsId": "0x022c0d9f"}]}';
connection.sendUTF(payload.toString());
}
}
bvPendingTransaction()
});
client.connect('wss://eth-mainnet.blockvision.org/v1/<api-key>');
Depois de estabelecer uma assinatura com sucesso, você poderá ver transações como as seguintes em seu terminal. Ao analisar os dados de entrada, você pode determinar as ações que a transação executará. Por exemplo, se você estiver procurando por transações que envolvam um par de tokens específico na DEX CFAMM, você pode usar os dados de entrada para filtrar as transações que não sejam relevantes para sua estratégia de arbitragem. Isso permite que você se concentre nas transações com potencial para fornecer oportunidades lucrativas de arbitragem.
{
"blockHash": "",
"blockNumber": "",
"from": "0x1d57184a354d58d8a0809b8a692e7a246b475c59",
"gas": "0x6ab56",
"gasPrice": "0x15426df2e",
"maxPriorityFeePerGas": "0x4d5ae996",
"maxFeePerGas": "0x161cd80e0",
"hash": "0x3faa1d4ce54732d78b18c06769fa08ed0d546354499fbe88a673ae961b1fa9c0",
"input": "0x022c0d9f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001bfc44ca3d497100000000000000000000000000a88157429f300dc5e796151ba91cd53b8e64e913000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c302810079003ffedcddd268511acc44ae67845bdd56c8417fa4018100600075bff91af9878f5ec3fede9b52d51159afc2430a01810047005777d92f208679db4b9778590fa3cab3ac9e21680181002e0088e6a0c2ddd26feeb64f039a2c41296fcb3f56400100c02aaa39b223fe8d0a0e5c4f27ead9083c756cc201c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29b19f7f92e60c1fe20d6080ec390c7aa6bb72811000000000000000000000000000000000000000000000000000815d5ce5445e70000000000000000000000000000000000000000000000000000000000",
"nonce": "0x63",
"to": "0xbb2b8038a1640196fbe3e38816f3e67cba72d940",
"transactionIndex": "",
"value": "0x0",
"type": "0x2",
"chainId": "0x1",
"v": "0x1",
"r": "0xf15fcfa63e8cf08ff2211231e87db4f89f28a1000ebd6060d8d064de31ff5c14",
"s": "0x37d38f7b93ae5f7a31363be559c94872cbfcd16840aeb5f972fef974653c4d6c"
}
O código de análise é o seguinte:
if (txHash['params']['result'] != undefined) {
result = txHash['params']['result'];
input = result['input'];
const iface = new ethers.utils.Interface(['function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external'])
decodedData = iface.decodeFunctionData('swap', input);
}
// 解析结果如下
[
BigNumber { _hex: '0x00', _isBigNumber: true },
BigNumber { _hex: '0x1bfc44ca3d497100', _isBigNumber: true },
'0xA88157429f300dc5E796151BA91CD53B8e64e913',
'0x02810079003ffedcddd268511acc44ae67845bdd56c8417fa4018100600075bff91af9878f5ec3fede9b52d51159afc2430a01810047005777d92f208679db4b9778590fa3cab3ac9e21680181002e0088e6a0c2ddd26feeb64f039a2c41296fcb3f56400100c02aaa39b223fe8d0a0e5c4f27ead9083c756cc201c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29b19f7f92e60c1fe20d6080ec390c7aa6bb72811000000000000000000000000000000000000000000000000000815d5ce5445e7',
amount0Out: BigNumber { _hex: '0x00', _isBigNumber: true },
amount1Out: BigNumber { _hex: '0x1bfc44ca3d497100', _isBigNumber: true },
to: '0xA88157429f300dc5E796151BA91CD53B8e64e913',
data: '0x02810079003ffedcddd268511acc44ae67845bdd56c8417fa4018100600075bff91af9878f5ec3fede9b52d51159afc2430a01810047005777d92f208679db4b9778590fa3cab3ac9e21680181002e0088e6a0c2ddd26feeb64f039a2c41296fcb3f56400100c02aaa39b223fe8d0a0e5c4f27ead9083c756cc201c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29b19f7f92e60c1fe20d6080ec390c7aa6bb72811000000000000000000000000000000000000000000000000000815d5ce5445e7'
]
Por meio da análise, podemos obter o amount0Out
e amount1Out
dessa transação e, em seguida, calcular o preço do último par de transações, se a transação for bem sucedida, por meio da seguinte fórmula:
Se uma negociação causa uma grande oscilação de preço em um dos pools, dizemos que temos alguma confiança de que identificamos uma oportunidade de arbitragem.
Escreva o contrato básico de arbitragem
O objetivo deste artigo é explicar como o uso do conjunto de ferramentas BlockVision pode reduzir o custo técnico da negociação de arbitragem, em vez de fornecer um guia completo para a implementação de contratos de arbitragem. Observe que a implementação do contrato fornecida neste artigo é apenas para fins ilustrativos e pode não ter valor de produção no mundo real. Cabe aos operadores de arbitragem individuais explorar e desenvolver suas próprias estratégias de arbitragem. Ao usar as ferramentas e serviços fornecidos pela BlockVision, os negociantes podem se concentrar em encontrar oportunidades lucrativas e executar negociações, em vez de gastar tempo e recursos na implementação técnica.
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
pragma abicoder v2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "hardhat/console.sol";
import "./interfaces/IUniswapV2Pair.sol";
import "./libraries/Decimal.sol";
contract arbitrageDemo {
struct arbitrageParams {
address pool1;
address pool2;
address inputToken;
uint256 amountIn1;
uint256 amountIn2;
}
function arbitrageWithinDex(params arbitrageParams) external {
// Certifique-se de que o caminho de arbitragem segue uma direção
require(amountIn1 == 0 || amountIn2 == 0, "montanteInx ambos não são iguais a zero");
// Certifique-se de que os endereços do pool de destino de arbitragem sejam inconsistentes
require(params.pool0 != params.pool1, "mesmo par de tokens");
// Aquisição de reservas de pools
(uint256 pool0Reserve0, uint256 pool0Reserve1, ) = IUniswapV2Pair(params.pool0).getReserves();
(uint256 pool1Reserve1, uint256 pool1Reserve1, ) = IUniswapV2Pair(params.pool1).getReserves();
// Arbitragem do pool1 para o pool2
if (params.amountIn1 != 0) {
IUniswapV2Pair pair = IUniswapV2Pair(params.pool0);
{
(uint256 reserve0, uint256 reserve1, ) = pair.getReserves();
(uint256 reserveInput, uint256 reserveOutput) = params.inputToken == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
amountInput = IERC20(params.inputToken).balanceOf(address(pair)).sub(reserveInput);
amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput);
}
(uint256 amount0Out, uint256 amount1Out) = input == token0 ? (uint256(0), amountOutput) : (amountOutput, uint256(0));
pair.swap(amount0Out, amount1Out, msg.sender, new bytes(0));
}
// Arbitragem do pool2 para o pool1
if (params.amountIn2 != 0) {
IUniswapV2Pair pair = IUniswapV2Pair(params.pool1);
{
(uint256 reserve0, uint256 reserve1, ) = pair.getReserves();
(uint256 reserveInput, uint256 reserveOutput) = params.inputToken == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
amountInput = IERC20(params.inputToken).balanceOf(address(pair)).sub(reserveInput);
amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput);
}
(uint256 amount0Out, uint256 amount1Out) = input == token0 ? (uint256(0), amountOutput) : (amountOutput, uint256(0));
pair.swap(amount0Out, amount1Out, msg.sender, new bytes(0));
}
}
}
Implante o contrato no Goerli para testar on-chain e obter o endereço do contrato:
0xba849911c809f6c922bc4767328a01db30c331e5
Agora que tudo está configurado, podemos usar os contratos de arbitragem implantados neste capítulo para simular um pacote de flashbots e iniciar uma negociação de arbitragem usando o conjunto de ferramentas BlockVision. No próximo capítulo, veremos as etapas de uso do conjunto de ferramentas para enviar um pacote e executar a negociação, para que você possa ver como é fácil integrar a negociação de arbitragem em seu próprio bot usando os serviços da BlockVision.
Iniciar uma negociação de arbitragem
Depois de encontrar uma oportunidade de arbitragem, você pode usar o contrato de arbitragem que implantou na cadeia para iniciar a negociação. Neste capítulo, mostraremos como construir transações de arbitragem usando as ferramentas fornecidas pela BlockVision e como é fácil enviar transações usando a coleção de ferramentas BlockVision-Flashbots. Com essas ferramentas, você não precisa mais incorrer nos custos técnicos associados ao uso de flashbots, tornando-se uma maneira conveniente e econômica de executar negociações de arbitragem.
No capítulo anterior, escrevemos uma demonstração breve de contrato de arbitragem e obtivemos seu endereço de contrato 0xba849911c809f6c922bc4767328a01db30c331e5
. Antes de empacotar a transação e enviá-la para BlockVision-Flashbots, precisamos primeiro construir a transação de arbitragem. Bem, vamos construir esta transação primeiro. Por favor, veja o seguinte código:
const ethers = require('ethers');
const fetch = require('node-fetch');
const dotenv = require('dot-env');
dotenv.config();
async function main() {
let abi = [
"struct arbitrageParams {address pool1;address pool2;address inputToken;uint256 amountIn1;uint256 amountIn2;}",
"function arbitrageWithinDex(params arbitrageParams)",
];
const contract = new ethers.Contract("CONTRACT_ADDRESS", abi, Wallet);
const params = [
"0xbb2b8038a1640196fbe3e38816f3e67cba72d940",
"0xCEfF51756c56CeFFCA006cD410B03FFC46dd3a58",
"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
1000000000000000000,
0,
];
const action = 'arbitrageWithinDex';
const unsignedTx = await contract.populateTransaction[action](...params);
let transaction = {
to: '<contract-address>',
value: ethers.utils.parseEther('1'),
gasLimit: '21000',
maxPriorityFeePerGas: ethers.utils.parseUnits('5', 'gwei'),
maxFeePerGas: ethers.utils.parseUnits('20', 'gwei'),
nonce: 1,
type: 2,
chainId: 3
};
let rawTransaction = await wallet.signTransaction(transaction).then(ethers.utils.serializeTransaction(transaction));
console.log('Raw txhash string ' + rawTransaction);
// postar para bv eth_sendBundle api
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
var raw = JSON.stringify({
"jsonrpc": "2.0",
"method": "eth_sendBundle",
"params": {
"txsHex": [unsignedTx],
"blockNumber": 0
},
"id": 1
});
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch("https://api.blockvision.org/v1/<api-key>", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
main();
Se o envio for bem sucedido, a interface retornará o bundle hash
alocado pelo relé dos Flashbots. Por meio do valor do hash, combinado com a API eth_getBundleStat
, o estado do pacote enviado pode ser rastreado continuamente. O resultado de retorno deve ser o seguinte:
{
"jsonrpc" : "2.0" ,
"id" : 1 ,
"resultado" : {
"isSimulated" : true ,
"isSentToMiners" : false ,
"isHighPriority" : false ,
"simulatedAt" : "2022-10-27T00:05 :01.436Z" ,
"submittedAt" : "2022-10-27T00:05:31.436Z" ,
"sentToMinersAt" : "0001-01-01T00:00:00Z"
}
}
Neste artigo, mostramos como usar a ferramenta MemPool BlockVision para integrar negociação de arbitragem em seu bot. Seguindo as etapas descritas neste artigo, você pode acessar facilmente o MemPool e encontrar oportunidades de arbitragem em tempo real, permitindo que você aproveite as ineficiências do mercado e maximize seus lucros. Esperamos que este artigo tenha sido útil e obrigado pela leitura.
Artigo produzido pela Blockvision e traduzido por Marcelo Panegali.
Top comments (0)