Skip to content

About

Восстановление истории переводов и балансов кошелька Polymarket напрямую с Polygon RPC (eth_getLogs/eth_call) - без API Polymarket и сторонних индексаторов.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

Polymarket Wallet Reconstruction

Восстановление истории и текущих балансов кошелька Polymarket напрямую через Polygon RPC — без API Polymarket и без готовых блокчейн-индексаторов.

Баланс каждого актива считается единственным способом, который не требует доверия ничему, кроме самого блокчейна: как сумма входящих минус сумма исходящих переводов по сырым ончейн-событиям, затем сверяется с eth_call на том же блоке.

Активы

  • USDC.e (bridged USDC), ERC20: 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
  • native USDC, ERC20: 0x3c499c542cef5E3811e1192ce70d8cc03d5c3359
  • Conditional Tokens Framework (позиции Polymarket), ERC1155: 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045

Отслеживаются события Transfer (ERC20) и TransferSingle/TransferBatch (ERC1155) — это единственные события, которые меняют баланс.

Архитектура

Три файла, один пайплайн:

  • config.py — RPC, подключение к Postgres, адреса контрактов, параметры сканирования. Никаких секретов в коде — всё из .env.
  • ingest.py — сбор сырых событий переводов в Postgres:
    1. Находит блок деплоя каждого контракта и самого кошелька через бинарный поиск по eth_getCode (кошелёк Polymarket — не обычный EOA, а proxy-контракт, у него тоже есть блок деплоя). Это не оценка и не обращение к внешнему сервису — просто нижняя граница сканирования, выведенная из RPC-примитива.
    2. Сканирует диапазон блоков чанками, параллельно запрашивая from=wallet и to=wallet для каждого события (позиционные топики не позволяют выразить OR между разными полями одним запросом).
    3. Если у провайдера сработал лимит на диапазон/объём ответа — рекурсивно делит диапазон пополам и запрашивает половины отдельно, вместо того чтобы держать в коде захардкоженный "магический" размер чанка под конкретный RPC.
    4. Пишет строки пачками (execute_values), с ON CONFLICT DO NOTHING по первичному ключу лога — безопасно перезапускать.
    5. Продолжает с MAX(block_number), уже закоммиченного в таблицах, если предыдущий запуск прервался — без отдельного checkpoint-файла.
    6. В конце фиксирует scanned_to_block — тот самый блок, до которого реально досканировано, а не "текущий последний".
  • balance.py — считает баланс SQL-агрегацией (SUM(inflow) - SUM(outflow)) из сырых событий и сверяет с eth_call на блоке, зафиксированном в scan_meta, а не на "latest".

Почему сверка идёт не на "latest"

Между тем, как ingest.py останавливается на блоке N, и моментом запуска balance.py в блокчейне неизбежно проходит ещё сколько-то блоков — в них могли пройти новые переводы этого же кошелька. Сверка с balanceOf(wallet) на "latest" в этом случае сравнивает две разные точки во времени: сумму событий по блок N против состояния на блоке N+k. Расхождение будет выглядеть как ошибка в расчёте, хотя на самом деле это просто сравнение несопоставимых моментов. Поэтому и SQL-фильтр (block_number <= scanned_to_block), и eth_call (block_identifier=scanned_to_block) всегда смотрят на один и тот же зафиксированный номер блока.

Запуск

cd reconstruct
pip install -r requirements.txt

.env (создать в reconstruct/, не коммитить):

POLYGON_RPC_URL=...       # архивный RPC с полным доступом к eth_getLogs
WALLET_ADDRESS=0x46b353667fd7d846af3bbeda6584b0e5b883d3de
PG_HOST=localhost
PG_PORT=5433
PG_DB=polymarket
PG_USER=postgres
PG_PASSWORD=...

Postgres можно поднять локально одной командой:

docker run -d --name pm-postgres -e POSTGRES_PASSWORD=... -e POSTGRES_DB=polymarket -p 5433:5432 postgres:16

Про выбор RPC — важно: публичные балансировщики (polygon-rpc.com и аналоги) режут глубину архива и диапазон eth_getLogs, из-за чего полное сканирование истории физически невозможно. Нужен провайдер с настоящим архивным доступом к логам (Infura/Alchemy free tier или публичный шлюз Tenderly — все по-разному ограничивают eth_getLogs, отсюда и адаптивное дробление диапазона в ingest.py, а не жёстко зашитое число).

Запуск:

python ingest.py    # может занять от минут до часов — зависит от активности кошелька и лимитов RPC
python balance.py

Разбор конкретного кошелька

0x46b353667fd7d846af3bbeda6584b0e5b883d3de

Это не рядовой личный кошелёк, а proxy-контракт (деплоен в блоке 80 813 428, задолго до первого перевода), судя по паттерну активности — высокочастотный маркет-мейкер/трейдер Polymarket:

  • Первая транзакция — вызов matchOrders на CTF Exchange, а не входящий перевод, что типично для автоматизированного контрагента ордеров.
  • Вся релевантная история уложилась в диапазон блоков 80 813 428 — 93 817 332 (~13 млн блоков, ~2025–2026 гг.) — контракты при этом задеплоены ещё в 2020 году. Если бы граница сканирования бралась от блока деплоя контрактов, а не кошелька, пришлось бы просканировать почти в 7 раз больше истории без единого релевантного события.
  • 238 797 переводов USDC.e и 464 483+ строк ERC1155-переводов (включая разворачивание TransferBatch).
  • 392 343 уникальные позиции Conditional Tokens с ненулевым балансом на момент сверки — то есть кошелёк одновременно держит позиции в сотнях тысяч разных исходов рынков.

Итоговые балансы на блоке 93 817 332:

Актив Баланс
USDC.e 0
native USDC 0
CTF-позиции 392 343 позиции, все сошлись

Нулевой баланс по обеим стейблкоинам — не аномалия и не признак ошибки: для активного маркет-мейкера это ожидаемо, весь капитал развёрнут в открытые позиции, а не лежит в свободном USDC.

Результат сверки: ВСЁ СОШЛОСЬ — 0 расхождений между суммой сырых ончейн-событий и состоянием контрактов на блоке 93 817 332.

Ограничения

  • Полное сканирование истории конкретного кошелька зависит от лимитов бесплатного RPC-провайдера — на очень активных кошельках счёт может идти на часы даже с адаптивным дроблением и параллелизмом.
  • Не учитываются производные/обёрточные позиции вне ERC20/ERC1155 (например, промежуточные состояния внутри самого CTF Exchange до момента, пока актив не стал переводом одного из трёх отслеживаемых контрактов) — баланс считается по тем же примитивам, что видит и сам блокчейн.

About

Восстановление истории переводов и балансов кошелька Polymarket напрямую с Polygon RPC (eth_getLogs/eth_call) - без API Polymarket и сторонних индексаторов.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages