Интеграция с Tally (governance)
Tally — это frontend и инфраструктура для on-chain governance. Протокол создаёт DAO с Governor контрактом, Tally автоматически индексирует предложения, голоса и делегирование — и отображает всё в удобном интерфейсе. Без Tally команде пришлось бы строить этот UI с нуля или пользоваться Snapshot (который off-chain).
Интеграция с Tally не требует специального SDK — достаточно задеплоить совместимый Governor контракт. Но «совместимый» означает несколько конкретных вещей.
Совместимые Governor контракты
Tally работает с двумя семействами контрактов:
OpenZeppelin Governor (рекомендуется). Базовый контракт Governor.sol с модульными расширениями: GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl. Это стандарт де-факто для новых DAO.
Compound Bravo Governor (legacy). Оригинальный Governor от Compound, используется в Uniswap, Compound, многих других. Tally поддерживает его, но новым проектам лучше использовать OZ.
Минимальная конфигурация для нового DAO:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/governance/Governor.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";
contract MyDAOGovernor is
Governor,
GovernorSettings,
GovernorCountingSimple,
GovernorVotes,
GovernorVotesQuorumFraction,
GovernorTimelockControl
{
constructor(
IVotes _token,
TimelockController _timelock
)
Governor("MyDAO Governor")
GovernorSettings(
7200, // votingDelay: 1 день в блоках (Ethereum ~12s/block)
50400, // votingPeriod: 7 дней
100e18 // proposalThreshold: 100 токенов для создания предложения
)
GovernorVotes(_token)
GovernorVotesQuorumFraction(4) // 4% от total supply для кворума
GovernorTimelockControl(_timelock)
{}
// Обязательные overrides для разрешения конфликтов между расширениями
function votingDelay() public view override(Governor, GovernorSettings) returns (uint256) {
return super.votingDelay();
}
// ... остальные overrides
}
Токен с поддержкой голосования
Важный нюанс: обычный ERC-20 не работает с Governor. Нужен ERC20Votes — расширение, которое хранит исторические балансы (checkpoints) для подсчёта голосов на момент создания предложения.
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
contract GovernanceToken is ERC20, ERC20Permit, ERC20Votes {
constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {}
// ERC20Votes требует override _afterTokenTransfer
function _afterTokenTransfer(address from, address to, uint256 amount)
internal override(ERC20, ERC20Votes)
{
super._afterTokenTransfer(from, to, amount);
}
}
Checkpoint механизм критичен: без него можно купить токены, проголосовать, продать — в одном блоке. С checkpoint голоса считаются на block number создания предложения.
Делегирование: держатель должен делегировать голоса (даже самому себе), чтобы они учитывались. Без delegate() голосовательная сила равна нулю. Tally отображает это и напоминает пользователям делегировать.
Регистрация в Tally
Tally автоматически индексирует Governor контракты, задеплоенные на поддерживаемых сетях (Ethereum, Arbitrum, Optimism, Polygon, Base и другие). Чтобы DAO появилась в Tally:
- Зайти на tally.xyz → «Add DAO»
- Указать адрес Governor контракта и сеть
- Tally верифицирует ABI и начинает индексацию
Дополнительно можно добавить: логотип DAO, описание, социальные ссылки — это редактируется в Tally admin panel.
TimelockController: защита между голосованием и исполнением
Timelock — обязательный компонент. После принятия предложения изменения не применяются сразу — есть период ожидания (обычно 2-7 дней), в течение которого сообщество может заметить потенциально вредоносное предложение и принять меры.
TimelockController timelock = new TimelockController(
2 days, // minDelay
proposers, // только Governor может предлагать
executors, // address(0) = любой может исполнить после задержки
admin // admin для начальной настройки, потом renounce
);
// Критично: передать ownership всех управляемых контрактов Timelock
managedContract.transferOwnership(address(timelock));
После деплоя: Governor добавляется как proposer, после тестирования admin роль renounce-ится. Контракт полностью под управлением DAO.
Что Tally показывает и как это влияет на UX
Tally отображает:
- Список всех предложений с текущим статусом и результатами голосования
- Делегирование: кому делегированы голоса, история изменений
- Профили делегатов с историей голосований
- Подробности предложения: описание, on-chain actions (какие функции вызываются)
- Quorum progress bar в реальном времени
Хорошая практика: в описание предложения включать полное обоснование (markdown поддерживается), ссылки на форум обсуждений. Tally рендерит это красиво. Предложения с пустым описанием теряют доверие сообщества.
Типичные проблемы при интеграции
Неправильные параметры кворума: 4% от total supply звучит разумно, но если 60% токенов у команды и не делегированы — реальный circulating supply меньше, кворум фактически недостижим. Считайте кворум от circulating supply, а не total.
Слишком короткий votingDelay: если votingDelay = 0, создатель предложения может купить токены, создать предложение и проголосовать в одном блоке. Минимум 1-2 дня.
Нет proposal threshold: любой может спамить предложениями. Устанавливайте разумный порог — например, 0.1-1% от total supply.
Governor не имеет права на управляемые контракты: частая ошибка при первом деплое. Убедитесь, что Timelock является owner-ом всех контрактов, которыми управляет DAO.
Интеграция с Tally занимает 1-3 недели включая деплой, настройку параметров, тестирование на testnet и регистрацию DAO.







