Взаимодействие с HyperCore
Прекомпайлы чтения
EVM тестнета предоставляет прекомпайлы чтения, позволяющие запрашивать информацию HyperCore. Адреса прекомпайлов начинаются с 0x0000000000000000000000000000000000000800 и содержат методы для запроса такой информации, как позиции по перпам, спот-балансы, капитал хранилищ, делегирования стейкинга, цены оракулов и номер L1-блока.
Значения гарантированно соответствуют последнему состоянию HyperCore на момент построения EVM-блока.
Ниже приложен файл Solidity L1Read.sol, описывающий прекомпайлы чтения. Например, этот вызов запрашивает третью цену оракула перпа в тестнете:
cast call 0x0000000000000000000000000000000000000807 0x0000000000000000000000000000000000000000000000000000000000000003 --rpc-url https://rpc.hyperliquid-testnet.xyz/evm
Для преобразования в числа с плавающей точкой разделите возвращённую цену на 10^(6 - szDecimals) для перпов и 10^(8 - base asset szDecimals) для спота.
Прекомпайлы, вызванные с недопустимыми входными данными, например несуществующим активом или адресом хранилища, вернут ошибку и израсходуют весь газ, переданный во фрейм вызова прекомпайла. Стоимость газа прекомпайлов составляет 2000 + 65 * (input_len + output_len).
Контракт CoreWriter
По адресу 0x3333333333333333333333333333333333333333 доступен системный контракт для отправки транзакций из HyperEVM в HyperCore. Он сжигает \~25,000 газа перед эмиссией лога, который HyperCore обрабатывает как действие. На практике расход газа для базового вызова составит \~47000. Ниже приложен файл Solidity CoreWriter.sol для системного контракта записи.
Детали кодирования действий
- Байт 1: версия кодирования
- Сейчас поддерживается только версия
1, но это открывает путь к будущим обновлениям с сохранением обратной совместимости. - Байты 2–4: ID действия
- Эти три байта, декодированные как беззнаковое целое big-endian, представляют уникальный идентификатор действия.
- Остальные байты: кодирование действия
- Остальные байты составляют специфические для действия данные. Это всегда сырая ABI-кодировка последовательности типов Solidity
Чтобы исключить возможное преимущество по задержке от использования HyperEVM в обход L1-мемпула, ордерные действия и переводы в хранилища, отправленные из CoreWriter, задерживаются ончейн на несколько секунд. Это не оказывает заметного влияния на UX, поскольку конечному пользователю в любом случае нужно дождаться хотя бы одного подтверждения маленького блока. Эти ончейн-задержанные действия появляются в L1-обозревателе дважды: сначала как постановка в очередь, затем как исполнение HyperCore.
| ID действия | Действие | Поля | Тип Solidity | Примечания |
|---|---|---|---|---|
| 1 | Лимитный ордер | (asset, isBuy, limitPx, sz, reduceOnly, encodedTif, cloid) | (uint32, bool, uint64, uint64, bool, uint8, uint128) | Кодировка Tif: 1 для Alo , 2 для Gtc , 3 для Ioc . Кодировка cloid: 0 означает отсутствие cloid, иначе число используется как cloid. limitPx и sz следует отправлять как 10^8 * человекочитаемое значение |
| 2 | Перевод в хранилище | (vault, isDeposit, usd) | (address, bool, uint64) | |
| 3 | Делегирование токена | (validator, wei, isUndelegate) | (address, uint64, bool) | |
| 4 | Пополнение стейкинга | wei | uint64 | |
| 5 | Вывод из стейкинга | wei | uint64 | |
| 6 | Отправка спот | (destination, token, wei) | (address, uint64, uint64) | |
| 7 | Перевод класса USD | (ntl, toPerp) | (uint64, bool) | |
| 8 | Финализация EVM-контракта | (token, encodedFinalizeEvmContractVariant, createNonce) | (uint64, uint8, uint64) | encodedFinalizeEvmContractVariant: 1 для Create, 2 для FirstStorageSlot , 3 для CustomStorageSlot . Для варианта Create используется входной аргумент createNonce. |
| 9 | Добавление API-кошелька | (адрес API-кошелька, имя API-кошелька) | (address, string) | Если имя API-кошелька пустое, он становится основным API-кошельком / агентом |
| 10 | Отмена ордера по oid | (asset, oid) | (uint32, uint64) | |
| 11 | Отмена ордера по cloid | (asset, cloid) | (uint32, uint128) | |
| 12 | Одобрение комиссии билдера | (maxFeeRate, адрес билдера) | (uint64, address) | maxFeeRate задаётся в decibps. Чтобы одобрить комиссию билдера 0.01%, maxFreeRate должен быть 10. |
| 13 | Отправка актива | (destination, subAccount, source_dex, destination_dex, token, wei) | (address, address, uint32, uint32, uint64, uint64) | Если subAccount не нулевой адрес, перевод выполняется с subAccount. Для спота укажите uint32::MAX в source_dex или destination_dex. |
| 15 | Операция borrow-lend | (encodedOperation, token, wei) | (uint8, uint64, uint64) | encodedOperation: 0 для Supply, 1 для Withdraw . Если wei равен 0, операция применяется максимально, например вывод всего баланса из резерва. |
| 16 | Установка абстракции | (user, abstraction) | (address, uint8) | abstraction: 1 для disabled, 2 для unifiedAccount , 3 для portfolioMargin . user может быть мастер-пользователем или суб-аккаунтом. |
| 17 | Операция с исходом | (encodedOperation, question, outcome, wei) | (uint8, uint32, uint32, uint64) | encodedOperation: |
Ниже приведён пример контракта, который отправляет действие от имени адреса самого контракта в HyperCore; он также демонстрирует один из способов построения закодированного действия в Solidity.
contract CoreWriterCaller {
function sendUsdClassTransfer(uint64 ntl, bool toPerp) external {
bytes memory encodedAction = abi.encode(ntl, toPerp);
bytes memory data = new bytes(4 + encodedAction.length);
data[0] = 0x01;
data[1] = 0x00;
data[2] = 0x00;
data[3] = 0x07;
for (uint256 i = 0; i < encodedAction.length; i++) {
data[4 + i] = encodedAction[i];
}
CoreWriter(0x3333333333333333333333333333333333333333).sendRawAction(data);
}
}
\ Счастливой разработки. Любые отзывы приветствуются.
{% file src="/files/4dRObNCsfvnrcSVeJXgc" %}
{% file src="/files/Nsv6L7FugL44GNDvyDq2" %}