Как заменить байты в данных транзакции для изменения суммы swap
При разработке софта для обмена монет часто возникает задача модификации параметров транзакции, в частности - суммы обмена. Если вы декодировали данные двух транзакций с разными объёмами и увидели набор байтов, то для понимания, какие именно байты отвечают за сумму, нужно провести сравнительный анализ. В этой статье разберём, как определить нужные байты и безопасно их заменить.
Анализ данных транзакции: поиск различий
Первым шагом является декодирование входных данных (input data) каждой транзакции с помощью блокчейн-эксплорера (например, TheSuperscan) или библиотеки web3. После декодирования вы увидите структуру, состоящую из сигнатуры функции (первые 4 байта) и аргументов. Для стандартных функций swap (например, в Uniswap V2) аргументы включают:
- amountIn - количество входящих токенов (uint256, 32 байта);
- amountOutMin - минимальное количество исходящих токенов (uint256);
- path - массив адресов токенов (динамический);
- to - адрес получателя;
- deadline - временная метка.
Сравните байты двух транзакций: отличаться будут поля amountIn и amountOutMin, так как суммы разные. Также могут отличаться deadline (если транзакции созданы в разное время) и path (если менялся маршрут). Все остальные байты должны быть идентичными (если адреса и получатель те же).
Как определить позицию байтов суммы
Входные данные транзакции - это шестнадцатеричная строка без префикса 0x. Сигнатура функции занимает первые 4 байта (8 символов). Далее следуют аргументы, каждый из которых выравнивается по 32 байта (64 символа). Для статических аргументов (uint256, address) позиция фиксирована. Например:
- Байты 4-35 (с 5-го по 68-й символ hex-строки) -
amountIn; - Байты 36-67 (69-132 символ) -
amountOutMin; - Далее - динамические данные (path).
Если ваши транзакции имеют одинаковую сигнатуру и порядок аргументов, то различия в первых 68 символах (после сигнатуры) будут указывать на разные суммы. Заменив эти байты на нужное значение (в hex-формате с обратным порядком байтов для uint256), вы измените сумму swap.
Практический пример замены байтов
Допустим, у вас есть hex-строка данных первой транзакции: 0x38ed1739...00000000000000000000000000000000000000000000000000000000000f4240... (где 0x38ed1739 - сигнатура функции swapExactTokensForTokens). Замените байты с 5-го по 68-й символ на новое значение суммы в hex. Например, для суммы 1000 USDC (10^18 * 1000 = 10^21 = 0x3635c9adc5dea00000) подставьте 0000000000000000000000000000000000000000000000003635c9adc5dea00000. После замены соберите новую hex-строку и подпишите транзакцию.
Важные предостережения
Изменение суммы swap без учёта slippage (проскальзывания) может привести к неудачной транзакции (revert). Убедитесь, что новое значение amountOutMin соответствует ожидаемому курсу обмена. Также проверяйте, что вы не затронули байты, отвечающие за адреса или временную метку, иначе транзакция будет отправлена на другой адрес или истечёт. Для тестирования используйте тестнет (Ropsten, Goerli) и симуляторы вроде Tenderly.
Инструменты для анализа и замены байтов
Используйте библиотеки web3.js или ethers.js для декодирования и кодирования данных. Вручную заменять байты можно через любой hex-редактор, но удобнее написать скрипт на Python или JavaScript, который автоматически парсит и модифицирует input data. Пример на JavaScript с ethers.js:
const iface = new ethers.utils.Interface(['function swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline)']);
const decoded = iface.parseTransaction({data: txData});
// измените decoded.args.amountIn на новое значение
const newData = iface.encodeFunctionData('swapExactTokensForTokens', [newAmountIn, decoded.args.amountOutMin, decoded.args.path, decoded.args.to, decoded.args.deadline]);Этот подход гарантирует, что вы не повредите структуру данных.