Інтеграція з Tally (управління)
Tally — це фронтенд та інфраструктура для on-chain управління. Протокол створює 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/блок)
50400, // votingPeriod: 7 днів
100e18 // proposalThreshold: 100 токенів для створення пропозиції
)
GovernorVotes(_token)
GovernorVotesQuorumFraction(4) // 4% від загального для кворуму
GovernorTimelockControl(_timelock)
{}
// Обов'язкові перевизначення для вирішення конфліктів між розширеннями
function votingDelay() public view override(Governor, GovernorSettings) returns (uint256) {
return super.votingDelay();
}
// ... інші перевизначення
}
Токен голосування
Важливий нюанс: стандартний ERC-20 не працює з Governor. Потрібен ERC20Votes — розширення, яке зберігає історичні баланси (чекпоїнти) для підрахунку голосів у момент створення пропозиції.
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 вимагає перевизначення _afterTokenTransfer
function _afterTokenTransfer(address from, address to, uint256 amount)
internal override(ERC20, ERC20Votes)
{
super._afterTokenTransfer(from, to, amount);
}
}
Механізм чекпоїнту критичний: без нього ви можете купити токени, проголосувати, продати — все в одному блоці. З чекпоїнтами голоси рахуються в номері блоку створення пропозиції.
Делегування: емітент повинен делегувати голоси (навіть собі) для їх врахування. Без delegate() голосувальна сила дорівнює нулю. Tally це відображає й нагадує користувачам про делегування.
Реєстрація у Tally
Tally автоматично індексує контракти Governor розгорнені на підтримуваних мережах (Ethereum, Arbitrum, Optimism, Polygon, Base та інші). Щоб DAO з'явилася в Tally:
- Перейдіть на tally.xyz → "Add DAO"
- Введіть адресу контракту Governor та мережу
- Tally перевіряє ABI й починає індексацію
Додатково можна додати: логотип DAO, опис, соціальні посилання — редагуються в панелі адміністратора Tally.
TimelockController: захист між голосуванням та виконанням
Timelock обов'язковий. Після того, як пропозиція пройде, зміни не застосовуються негайно — є період очікування (зазвичай 2-7 днів), протягом якого спільнота може помітити потенційно шкідливі пропозиції й вжити заходів.
TimelockController timelock = new TimelockController(
2 days, // minDelay
proposers, // тільки Governor може пропозиції
executors, // address(0) = будь-хто може виконати після затримки
admin // admin для первинного налаштування, потім відмовитися
);
// Критично: передати власність всіх керованих контрактів Timelock
managedContract.transferOwnership(address(timelock));
Після розгортання: Governor додається як proposer; після тестування роль admin відмовляється. Контракт повністю під контролем DAO.
Що показує Tally й як це впливає на UX
Tally відображає:
- Список всіх пропозицій з поточним статусом та результатами голосування
- Делегування: кому делеговані голоси, історія змін
- Профілі делегатів з історією голосування
- Деталі пропозиції: опис, on-chain дії (які функції викликаються)
- Рядок прогресу кворуму в реальному часі
Найкраща практика: включіть повне обґрунтування в опис пропозиції (підтримується markdown), посилання на обговорення форуму. Tally це гарно рендерує. Пропозиції з порожніми описами втрачають довіру спільноти.
Типові проблеми інтеграції
Неправильні параметри кворуму: 4% від загального звучить розумно, але якщо 60% токенів у команди й не делеговано — реальна циркуляцій менша; кворум фактично недосяжний. Рахуйте кворум від циркуляції, не загального.
Занадто короткий votingDelay: якщо votingDelay = 0, творець пропозиції може купити токени, створити пропозицію й проголосувати в одному блоці. Мінімум 1-2 дні.
Немає порога пропозиції: будь-хто може спамити пропозиціями. Встановіть розумний поріг — наприклад, 0.1-1% від загального.
Governor не є власником керованих контрактів: часта помилка при першому розгортанні. Переконайтеся, що Timelock є власником всіх контрактів, які DAO керує.
Інтеграція з Tally займає 1-3 тижні включаючи розгортання, налаштування параметрів, тестування на testnet й реєстрацію DAO.







