ManaGovernance.sol
Обзор
Контракт ManaGovernance реализует систему управления (governance) для держателей токенов MANA, которые могут создавать предложения, голосовать за них и инициировать изменения ключевых экономических и управленческих параметров в экосистеме. Контракт поддерживает создание различных типов предложений, включая экономические, управленческие и экстренные (emergency), с соответствующими периодами голосования и задержками исполнения.
В основе механизма лежит стейкинг MANA токенов: чем больше токенов застейкано, тем больше вес голоса пользователя. Для обеспечения безопасности и контроля предусмотрены роли доступа, паузы системы и многоступенчатая логика состояний предложений.
Составные части файла
Константы и Роли
EMERGENCY_ROLE— роль для создания экстренных предложений.PAUSER_ROLE— роль, позволяющая приостанавливать работу контракта.Временные ограничения (минимальный/максимальный период голосования, задержки таймлока).
Пороговые значения для создания предложений и кворума голосования.
Кастомные ошибки
Используются для оптимизации газа и повышения читаемости:
InvalidProposalId,ProposalNotActive,InsufficientStake,AlreadyVotedи др.
Основные типы и структуры данных
Перечисления
ProposalState — текущее состояние предложения:
Pending,Active,Succeeded,Defeated,Queued,Executed,Cancelled.
ProposalType — тип предложения:
EconomicParameters,GovernanceParameters,Emergency.
VoteType — тип голоса:
Against(против),For(за),Abstain(воздержался).
Структуры
Proposal — описание предложения:
id, proposer, тип, описание, данные, время старта/окончания, голоса, итоги, статусы.
Receipt — информация о голосовании конкретного участника:
голосовал ли, тип голоса, количество голосов, застейканная сумма.
GovernanceConfig — параметры управления:
периоды голосования, таймлоки, пороги.
StakerInfo — данные о застейканных токенах пользователя:
сумма, время начала стейкинга, последний созданный proposalId.
Взаимодействующие контракты
ManaToken — контракт ERC20 токена MANA, который используется для стейкинга.
GameManager — контракт, управляющий экономическими параметрами игры, который обновляется через успешные предложения.
Основные методы
Конструктор
constructor(address _manaToken, address _gameManager, address _admin)
Инициализирует контракт с адресами токена MANA, менеджера игры и администратора.
Назначает роли и устанавливает начальные параметры управления.
Стейкинг и вывод токенов
function stake(uint256 amount) external whenNotPaused nonReentrant
Пользователь передаёт MANA в контракт для участия в голосовании.
Обновляет учет застейканных токенов и время начала стейкинга.
Генерирует событие
StakeDeposited.
function withdraw(uint256 amount) external whenNotPaused nonReentrant
Позволяет вывести застейканные токены.
Проверяет достаточность баланса.
Обновляет данные и вызывает событие
StakeWithdrawn.
Создание предложений
function propose(ProposalType proposalType, string calldata description, bytes calldata proposalData) external whenNotPaused returns (uint256 proposalId)
Протокол проверки достаточного стейка и минимального времени стейкинга.
Проверка роли для экстренных предложений.
Создаёт предложение с уникальным ID, фиксирует время начала и окончания голосования.
Сохраняет снимок общего стейка на момент создания.
Событие
ProposalCreated.
Пример использования:
uint256 id = manaGovernance.propose(
ManaGovernance.ProposalType.EconomicParameters,
"Увеличить награды за квесты",
abi.encode(newEconomicConfig)
);
Голосование
function castVote(uint256 proposalId, VoteType vote, string calldata reason) external whenNotPaused
Доступно только в активном состоянии предложения.
Проверяет, что пользователь не голосовал ранее и имеет достаточный стейк.
Обновляет голоса в зависимости от выбора.
Сохраняет голос в
Receipt.Генерирует событие
VoteCast.
Управление жизненным циклом предложений
Очередь на исполнение
function queue(uint256 proposalId) external whenNotPaused
Позволяет поставить успешное предложение в очередь исполнения (таймлок).
Исполнение
function execute(uint256 proposalId) external whenNotPaused nonReentrant
Проверяет истечение таймлока (короткий для экстренных предложений).
Исполняет действия, декодируя данные предложения:
Изменение экономических параметров (
_executeEconomicParameterChange)Изменение параметров управления (
_executeGovernanceParameterChange)Экстренные действия (
_executeEmergencyProposal)
Генерирует событие
ProposalExecuted.Отмена
function cancel(uint256 proposalId) external
Может быть вызвано либо администратором, либо автором предложения.
Отменяет предложение до исполнения.
Вспомогательные методы
Получение состояния предложения:
getProposalStateПолучение детальной информации о предложении, голосах, стейкинге.
Проверка возможности создания предложения и вычисление веса голоса.
Функции
pauseиunpauseдля экстренного управления контрактом.
Важные детали реализации
Используется OpenZeppelin для ролей, защиты от повторных вызовов и паузы.
Применяется таймлок — задержка перед исполнением предложений для безопасности.
Голоса расчитываются по застейканному количеству токенов на момент создания предложения.
Экстренные предложения требуют отдельной роли и имеют сокращённый таймлок.
Для обновления параметров управления предусмотрена функция, доступная только администратору, как резервный вариант.
Взаимодействие с другими частями системы
ManaToken — источник токенов для стейкинга и голосования.
GameManager — получатель изменений экономических параметров после успешного голосования.
Другие контракты в экосистеме могут взаимодействовать с ManaGovernance для проверки результатов голосований и статусов предложений.
Диаграмма классов
classDiagram
class ManaGovernance {
+stake(amount: uint256)
+withdraw(amount: uint256)
+propose(proposalType: ProposalType, description: string, proposalData: bytes) uint256
+castVote(proposalId: uint256, vote: VoteType, reason: string)
+queue(proposalId: uint256)
+execute(proposalId: uint256)
+cancel(proposalId: uint256)
+getProposalState(proposalId: uint256) ProposalState
+getProposal(proposalId: uint256) Proposal
+getReceipt(proposalId: uint256, voter: address) Receipt
+getStakerInfo(staker: address) StakerInfo
+getGovernanceConfig() GovernanceConfig
+getVotingPower(account: address) uint256
+canCreateProposal(account: address) bool
+pause()
+unpause()
+updateGovernanceConfig(newConfig: GovernanceConfig)
-_castVote(proposalId: uint256, voter: address, vote: VoteType, reason: string)
-_executeEconomicParameterChange(proposalData: bytes)
-_executeGovernanceParameterChange(proposalData: bytes)
-_executeEmergencyProposal(proposalData: bytes)
}
class ManaToken
class GameManager
ManaGovernance --> ManaToken : uses
ManaGovernance --> GameManager : uses
ManaGovernance : +EMERGENCY_ROLE
ManaGovernance : +PAUSER_ROLE
ManaGovernance : +ProposalState
ManaGovernance : +ProposalType
ManaGovernance : +VoteType
ManaGovernance : +Proposal
ManaGovernance : +Receipt
ManaGovernance : +GovernanceConfig
ManaGovernance : +StakerInfo
Заключение
Контракт ManaGovernance обеспечивает надежный, гибкий и безопасный механизм управления параметрами экосистемы через децентрализованное голосование держателей токенов MANA. Его архитектура учитывает разные сценарии — от стандартных изменений параметров до экстренных случаев, при этом гарантирует прозрачность и контроль через роли и временные задержки.
Данный файл является ключевым компонентом системы управления и тесно интегрирован с контрактами токена и менеджера игры, формируя основу для устойчивого развития и адаптации платформы под запросы сообщества.