Торговый бот можно практически полностью написать на TypeScript.
Для простого приложения этого может быть достаточно: Стратегия ↓ TypeScript ↓ Маршрутизатор ↓ Цепочка Robinhood.
Но по мере усложнения системы появляется еще один инженерный уровень, который стоит тщательно разработать: уровень исполнения Solidity.
Пользовательский смарт-контракт может обеспечить границу цепочки для авторизованного выполнения, обработки токенов, адаптеров протоколов, проверки и генерации событий.
Приложение над ним по-прежнему может обрабатывать: стратегию рыночных данных, оркестрацию кошелька, мониторинг, сверку.
Это дает нам полную архитектуру: торговая стратегия ↓ механизм риска ↓ бэкэнд TypeScript ↓ Solidity Executor ↓ EVM ↓ цепочка Robinhood Chain Robinhood полностью совместима с EVM.
В текущей документации говорится, что контракты Solidity и Vyper могут быть развернуты с использованием стандартных инструментов Ethereum, включая Foundry и Hardhat.
Основная сеть Robinhood Chain в настоящее время использует идентификатор цепи 4663.
В этой статье основное внимание уделяется тому, как я буду создавать слой Solidity для торговой системы.
Зачем помещать часть торговой системы в цепочку?
Не каждому торговому боту нужен индивидуальный контракт.
Для некоторых систем вполне разумно использовать TypeScript ↓ Existing Protocol Contract.
Пользовательский слой Solidity становится более интересным, когда приложению требуется явная граница выполнения.
Например: TypeScript ↓ Торговое намерение ↓ Исполнитель Solidity ↓ Протокол Контракт Solidity может обеспечивать соблюдение таких правил, как: авторизованный исполнитель, разрешенные активы, разрешенные маршрутизаторы, максимальная сумма сделки, минимальный срок вывода, состояние паузы.
Между тем, уровень приложений обрабатывает: стратегию открытия рынка, ценообразование, оценку риска, управление кошельком, мониторинг транзакций.
Таким образом, контракт не является торговой стратегией.
Это уровень обеспечения соблюдения и исполнения в цепочке.
Архитектура.
Реализация, ориентированная на производство, может быть разделена на: ТОРГОВОЕ ПРИЛОЖЕНИЕ | +--------------+--------------+ | | Стратегический риск-движок | | +--------------+--------------+ | Торговое намерение | Серверная часть TypeScript | Исполнитель Solidity | Адаптер протокола | ЭВМ | Цепочка Robinhood После транзакции: Цепочка Robinhood ↓ События/Поступления ↓ Монитор транзакций ↓ Согласование ↓ Состояние позиции.
Это создает полный круговой обход.
Начните с ограниченного исполнителя.
Я бы не стал разрабатывать контракт, который принимает произвольные данные вызова от ненадежного вызывающего объекта.
Лучшей отправной точкой является ограниченный исполнитель.
Например: // SPDX-License-Identifier: MIT pragma Solidity ^0.8.24; интерфейс IERC20 { функция TransferFrom (адрес от, адрес, сумма uint256) внешний возврат (bool); } интерфейс IRouter { функция swap (адрес tokenIn, адрес tokenOut, uint256 sumIn, uint256 minAmountOut, адрес получателя) внешние возвраты (uint256 sumOut); } контракт TradingExecutor {адрес публичного неизменяемого владельца; сопоставление (адрес => bool) общественного разрешенногоRouter; сопоставление (адрес => bool) public AllowToken; bool public приостановлен; ошибка Неавторизованный(); ошибка Пауза(); ошибка RouterNotAllowed(); ошибка TokenNotAllowed(); ошибка InvalidAmount(); ошибка SlippageExceeded(); событие RouterUpdated (маршрутизатор с индексированным адресом, допускается логическое значение); событие TokenUpdated (токен с индексированным адресом, допускается логическое значение); событие Paused (значение bool); событие TradeExecuted (индексированный в байтах32 идентификатор операции, индексированный адрес маршрутизатора, индексированный адрес tokenIn, адрес tokenOut, uint256 sumIn, uint256 sumOut ); модификатор onlyOwner() { if (msg.sender != владелец) revert Unauthorized(); _; } Конструктор (адрес InitialOwner) {владелец = InitialOwner; } Функция setRouter (адрес маршрутизатора, логическое значение разрешено) внешний onlyOwner { разрешеноRouter [маршрутизатор] = разрешено; излучать RouterUpdated (маршрутизатор, разрешено); } Функция setToken (токен адреса, логическое значение разрешено) внешний onlyOwner {allowToken [токен] = разрешено; излучать TokenUpdated (токен, разрешено); } Функция setPaused (значение bool) external onlyOwner {paused = value; испустить паузу (значение); } функция ExecuteTrade (bytes32 идентификатор операции, адрес маршрутизатора, входной адрес токена, выходной адрес токена, uint256 sumIn, uint256 minAmountOut, адрес получателя) ext