Подпись запросов Ed25519 для Jupiter DEX на Python: Гайд

Подпись запросов Ed25519 для Jupiter DEX на Python: Гайд Python & API
Пошаговое руководство по реализации криптографической подписи Ed25519 для API децентрализованной биржи Jupiter (Solana) на Python с использованием solders.
Суть: Для безопасного взаимодействия с API децентрализованной биржи Jupiter в сети Solana (например, для выставления лимитных ордеров) требуется подтверждение владения приватным ключом. Это реализуется через криптографическую подпись Ed25519 произвольного сообщения или транзакции. В этой статье мы разберем, как реализовать этот процесс на Python с использованием современных библиотек solders и base58.

Исходный код

При проектировании высокочастотных торговых систем, таких как Реализация Grid Bot для Bybit на Python: Гайд Quant-разработчика, безопасность и скорость авторизации запросов играют решающую роль. В экосистеме Solana и DEX Jupiter для этого используется криптографическая подпись Ed25519. Ниже представлен готовый к продакшену класс для генерации подписей и отправки авторизованных запросов к API Jupiter.

import time
import json
import httpx
import base58
from solders.keypair import Keypair

class JupiterSigner:
    def __init__(self, private_key_b58: str):
        # Инициализируем ключевую пару Solana из Base58 строки
        self.keypair = Keypair.from_base58_string(private_key_b58)
        self.public_key_str = str(self.keypair.pubkey())

    def sign_payload(self, payload: dict) -> dict:
        """
        Формирует подпись Ed25519 для переданного словаря данных.
        Добавляет временную метку для предотвращения Replay-атак.
        """
        timestamp = int(time.time())
        
        # Создаем копию payload и добавляем обязательные метаданные
        auth_payload = {
            **payload,
            "timestamp": timestamp,
            "pubkey": self.public_key_str
        }
        
        # Сериализуем с сортировкой ключей для детерминированности JSON
        serialized_message = json.dumps(auth_payload, sort_keys=True, separators=(",", ":"))
        message_bytes = serialized_message.encode("utf-8")
        
        # Подписываем байты сообщения с помощью Ed25519
        signature = self.keypair.sign_message(message_bytes)
        signature_b58 = base58.b58encode(bytes(signature)).decode("utf-8")
        
        return {
            "payload": auth_payload,
            "signature": signature_b58
        }

    async def send_authenticated_request(self, url: str, payload: dict) -> dict:
        """
        Отправляет асинхронный POST-запрос с подписью в заголовках.
        """
        signed_data = self.sign_payload(payload)
        
        headers = {
            "Content-Type": "application/json",
            "X-Signature": signed_data["signature"],
            "X-Timestamp": str(signed_data["payload"]["timestamp"]),
            "X-PublicKey": self.public_key_str
        }
        
        async with httpx.AsyncClient() as client:
            response = await client.post(url, json=signed_data["payload"], headers=headers)
            response.raise_for_status()
            return response.json()

Разбор параметров

Для успешной интеграции подписи важно понимать назначение каждого компонента в коде:

  • Keypair.from_base58_string: Метод библиотеки solders, который восстанавливает объект приватного ключа Solana из стандартного Base58-представления (обычно это строка длиной 88 символов).
  • sort_keys=True: Параметр сериализации JSON, гарантирующий одинаковый порядок ключей на стороне клиента и сервера. Без него подпись будет невалидной из-за случайного порядка полей.
  • sign_message: Метод, выполняющий криптографическое подписание массива байтов с использованием алгоритма Ed25519 на эллиптической кривой Curve25519.
  • X-Signature: HTTP-заголовок, содержащий результирующую подпись в формате Base58, которую Jupiter использует для верификации отправителя.

Как запустить

Для параллельной отправки множества транзакций или отмены ордеров (аналогично тому, как реализуется Пакетная отмена ордеров (Batch Cancel) на Bybit V5 через asyncio.gather) в Solana требуется быстрая асинхронная генерация подписей. Если вы ранее занимались такой задачей, как Парсинг истории фандинга OKX на Python Asyncio: Гайд, то знаете, что биржи используют разные методы аутентификации. Solana-native протоколы полностью полагаются на криптографию эллиптических кривых.

Чтобы запустить скрипт, выполните следующие шаги:

1. Установите необходимые зависимости в ваше виртуальное окружение:

pip install solders base58 httpx

2. Подготовьте ваш приватный ключ Solana в формате Base58 (экспортируйте его из кошелька Phantom или Solflare).

3. Используйте следующий пример для инициализации и отправки тестового запроса:

import asyncio

async def main():
    # Замените на ваш реальный приватный ключ (будьте осторожны, не коммитьте его в публичные репозитории!)
    private_key = "YOUR_SOLANA_PRIVATE_KEY_BASE58"
    
    signer = JupiterSigner(private_key)
    
    # Пример payload для создания лимитного ордера на Jupiter
    order_payload = {
        "inputMint": "So11111111111111111111111111111111111111112", # SOL
        "outputMint": "EPjFW311l7qLGP8fcx281JCgVW8gmeWmoVpXJ9ks133", # USDC
        "inAmount": 1000000000, # 1 SOL (в лампортах)
        "outAmount": 150000000 # Минимальный выходной объем
    }
    
    # Отправка запроса на эндпоинт Jupiter (замените URL на актуальный эндпоинт лимитных ордеров)
    target_url = "https://jup.ag/api/v1/limit/create"
    try:
        response = await signer.send_authenticated_request(target_url, order_payload)
        print("Ответ от Jupiter API:", response)
    except Exception as e:
        print("Ошибка при отправке запроса:", e)

if __name__ == "__main__":
    asyncio.run(main())

Оцените статью
FinFluct