Полный список адресов с ненулевым остатком, а не верхушка. Собран не из обозревателя, а из событий блокчейна, и сверен с общим выпуском токена: пока сумма всех остатков не совпадёт с выпуском до последнего вея, список не публикуется.
Отсортирован по размеру остатка. Поиск принимает как полный адрес, так и его начало — достаточно нескольких знаков после 0x.
Подписи у адресов стоят там, где они известны: биржи, пулы ликвидности и контракты самого Rainbow. У остальных адресов подписи нет ни у кого — это обычные кошельки.
Баланс адреса равен сумме всего пришедшего минус сумма всего ушедшего. Поэтому список держателей и их остатки восстанавливаются из одной только ленты переводов токена, без единого обращения к обозревателю.
Контракт токена развёрнут в блоке 41349994. От него и до головы цепочки читаются все события Transfer — это порядка трёхсот шестидесяти тысяч событий. Проход возобновляемый: он сохраняет состояние по дороге и при обрыве продолжает с места, а не начинает заново.
У отправителя сумма вычитается, у получателя прибавляется. Нулевой адрес в список не попадает: через него проходят выпуск и сжигание, держателем он не является.
Сумма всех положительных остатков обязана совпасть с totalSupply() контракта. Совпасть точно, а не примерно: арифметика по событиям не округляет, и расхождение означало бы потерянные события. Не сошлось — отдача не перезаписывается, а проход запускается снова и дособирает пропущенное.
Почему не обозреватель. У Blockscout есть готовый список, но он отдаётся по пятьдесят адресов за запрос — на пятьдесят с лишним тысяч адресов это больше тысячи запросов. После полусотни он закрывается на часы и, что гораздо хуже, начинает отдавать неполные ответы без всякого признака обрезки. На этом у нас уже терялось 61,5% суммы кэшбэка, пока источник не заменили на ноды. Список, собранный так, был бы молча неправильным — а это хуже, чем отсутствие списка. И проверить его было бы не с чем: у обозревателя нет величины, с которой можно сверить итог.
Держать токен и держать позицию в стейкинге — разные вещи, и множества почти не пересекаются: держателей пятьдесят с лишним тысяч, стейкеров около трёх. Адрес, заперший весь баланс в стейкинге, становится нулевым и из этого списка выпадает — токены числятся за контрактом стейкинга, а не за человеком.
В списке есть пулы ликвидности, контракт стейкинга и казначейство. Это адреса, а не владельцы, и складывать их с кошельками как «держателей» было бы неверно. Поэтому известные из них подписаны — чтобы их было видно и можно было вычесть.
Обратное тоже верно: за одним адресом биржи стоят тысячи людей. Число строк в этом списке — это число адресов, а не число владельцев, и считать его числом людей нельзя.
Данные обновляются сами: после первого полного прохода сборщик дочитывает только новые блоки. Отдаются как /api/holdersall/index.json и файлы по пятьсот строк рядом с ним.