ManaSettlement.sol
Обзор
ManaSettlement.sol — это смарт-контракт на языке Solidity, реализующий систему расчётов и управления состоянием игроков в игровой экономике с использованием токена MANA. Контракт обеспечивает хранение и обновление индивидуальных профилей игроков, балансов MANA, а также поддерживает партии обновлений для оптимизации работы. В основе лежит роль-ориентированный контроль доступа, что позволяет разграничить права между игровым менеджером и администраторами.
Это автономный модуль, предназначенный для интеграции с игровыми системами и потенциальной интеграции с Symbiotic Settlement, обеспечивающий безопасное, эффективное и прозрачное управление экономикой игры.
Основные возможности
Управление профилями игроков с детальной статистикой (уровень, опыт, PvP-статистика, достижения и др.)
Отдельное хранение и обновление балансов MANA игроков, синхронизируемое с токеном MANA
Ролевой доступ: игровой менеджер и администраторы с возможностями паузы и управления
Защита от повторного вызова (reentrancy-атаки)
Пакетная обработка обновлений состояний для оптимизации газа
Возможность регистрации новых игроков и добавления достижений
Эмердженси-функции паузы и возобновления работы контракта
Классы и структуры
ManaSettlement (контракт)
Наследует: AccessControl (OpenZeppelin)
Роли
GAME_MANAGER_ROLE— роль игрового менеджера с правом обновления состояния игроков.PAUSER_ROLE— роль с правом ставить контракт на паузу и снимать с паузы.
Структуры
struct PlayerProfile {
uint256 level;
uint256 experience;
uint256 totalManaEarned;
uint256 totalManaSpent;
uint256 lastActionTimestamp;
uint256 wins;
uint256 losses;
uint256 rating;
uint256 itemsCrafted;
bytes32[] achievements;
}
Хранит детальную статистику игрока, включая PvP, опыт, достижения и экономические показатели.
struct PlayerStateUpdate {
address player;
uint256 newManaBalance;
PlayerProfile newProfile;
}
Используется для пакетного обновления состояния игроков.
Функции и методы
Конструктор и инициализация
constructor(address _manaToken)
Инициализирует контракт указанием адреса токена MANA.
Устанавливает начальное состояние reentrancy-стража и флага паузы.
Параметры:
_manaToken— адрес контракта MANA токена (обязателен, не нулевой).
function initialize(address defaultAdmin, address gameManager)
Назначает роли администратора и игрового менеджера.
Параметры:
defaultAdmin— адрес администратора.gameManager— адрес контракта игрового менеджера.
Ограничения: оба адреса не должны быть нулевыми.
Пример использования:
manaSettlement.initialize(adminAddress, gameManagerAddress);
Управление состоянием игроков
function updatePlayerState(address player, uint256 newManaBalance, PlayerProfile calldata newProfile)
Обновляет баланс и профиль одного игрока.
Только для
GAME_MANAGER_ROLE.Параметры:
player— адрес игрока.newManaBalance— новый баланс MANA.newProfile— новая структура профиля.
Регистрирует игрока, если он не был ранее зарегистрирован.
Генерирует события обновления.
Пример:
manaSettlement.updatePlayerState(playerAddress, 500, newProfileData);
function batchUpdatePlayerStates(PlayerStateUpdate[] calldata updates)
Пакетное обновление состояний нескольких игроков.
Только для
GAME_MANAGER_ROLE.Параметр:
updates— массив структур с обновлениями для каждого игрока.
Увеличивает счётчик партий (
batchCounter).Генерирует события для каждой записи и для всей партии.
Пример:
PlayerStateUpdate[] memory batch = new PlayerStateUpdate[](2);
batch[0] = PlayerStateUpdate(player1, 300, profile1);
batch[1] = PlayerStateUpdate(player2, 450, profile2);
manaSettlement.batchUpdatePlayerStates(batch);
function getPlayerState(address player) external view returns (uint256 manaBalance, PlayerProfile memory profile, bool isRegistered)
Получение текущего состояния игрока.
Возвращает баланс, профиль и статус регистрации.
function getMultiplePlayerStates(address[] calldata players) external view returns (PlayerStateUpdate[] memory states)
Получение состояния нескольких игроков за один вызов.
Работа с балансом MANA
function getPlayerManaBalances(address player) external view returns (uint256 settlementBalance, uint256 tokenBalance)
Возвращает баланс игрока, отслеживаемый в контракте расчёта и баланс в токене MANA.
function updatePlayerManaBalance(address player, uint256 newBalance)
Обновляет только баланс MANA игрока.
Только для
GAME_MANAGER_ROLE.Требует регистрацию игрока.
Управление профилями и достижениями
function addPlayerAchievement(address player, bytes32 achievement)
Добавляет достижение игроку.
Только для
GAME_MANAGER_ROLE.Требует, чтобы игрок был зарегистрирован.
function getPlayerProfile(address player) external view returns (PlayerProfile memory profile)
Возвращает профиль игрока.
function getPlayerAchievements(address player) external view returns (bytes32[] memory achievements)
Возвращает массив достижений игрока.
Регистрация игроков
function registerPlayer(address player)
Регистрирует нового игрока с начальными значениями профиля.
Только для
GAME_MANAGER_ROLE.Игроку присваивается уровень 1, рейтинг 1000, опыт 0.
Пример:
manaSettlement.registerPlayer(newPlayerAddress);
function isPlayerRegistered(address player) external view returns (bool isRegistered)
Проверяет регистрацию игрока.
Управление состоянием контракта
function pause() external onlyRole(PAUSER_ROLE)
Останавливает работу контракта (пауза).
function unpause() external onlyRole(PAUSER_ROLE)
Возобновляет работу контракта.
function paused() public view returns (bool)
Проверяет, стоит ли контракт на паузе.
Дополнительные функции
function getTotalStats() external view returns (uint256 totalRegisteredPlayers, uint256 totalBatches)
Возвращает общее число зарегистрированных игроков и количество обработанных партий обновлений.
function supportsInterface(bytes4 interfaceId) public view override returns (bool)
Проверка поддержки интерфейсов (наследуется от AccessControl).
Важные детали реализации
Используется
AccessControlOpenZeppelin для управления ролями.Применён паттерн reentrancy-guard через
_statusдля защиты от повторных вызовов.Введён флаг
_pausedдля управления состоянием контракта в экстренных ситуациях.Ошибки реализованы через пользовательские ошибки
error, что экономит газ по сравнению с require+строками.Обновления профиля и баланса игроков сопровождаются эмитированием нескольких событий для прозрачности.
Отдельное хранение баланса в контракте для учёта внутренней логики игры, отличающейся от баланса на уровне токена.
Пакетная обработка обновлений повышает эффективность при массовых изменениях.
Взаимодействие с другими частями системы
Контракт зависит от внешнего контракта токена
ManaTokenдля получения балансов токенов.Роль
GAME_MANAGER_ROLEобычно назначается игровому менеджеру, который управляет логикой игры и вызывает методы обновления состояний.Административные роли обеспечивают безопасность и возможность экстренного управления (пауза, назначение ролей).
Контракт может использоваться как отдельный модуль либо интегрироваться в более сложные settlement-системы, например Symbiotic Settlement.
Пример использования
// Инициализация
manaSettlement.initialize(adminAddress, gameManagerAddress);
// Регистрация нового игрока
manaSettlement.registerPlayer(playerAddress);
// Обновление состояния игрока
ManaSettlement.PlayerProfile memory newProfile = ManaSettlement.PlayerProfile({
level: 5,
experience: 1500,
totalManaEarned: 10000,
totalManaSpent: 5000,
lastActionTimestamp: block.timestamp,
wins: 10,
losses: 3,
rating: 1200,
itemsCrafted: 7,
achievements: new bytes32[](0)
});
manaSettlement.updatePlayerState(playerAddress, 800, newProfile);
// Добавление достижения
manaSettlement.addPlayerAchievement(playerAddress, keccak256(abi.encodePacked("FirstWin")));
Диаграмма структуры контракта
classDiagram
class ManaSettlement {
<<contract>>
+bytes32 GAME_MANAGER_ROLE
+bytes32 PAUSER_ROLE
-uint256 _status
-bool _paused
+ManaToken manaToken
+mapping(address => uint256) manaBalances
+mapping(address => PlayerProfile) playerProfiles
+mapping(address => bool) registeredPlayers
+uint256 totalPlayers
+uint256 batchCounter
+constructor(address _manaToken)
+initialize(address defaultAdmin, address gameManager)
+updatePlayerState(address player, uint256 newManaBalance, PlayerProfile newProfile)
+batchUpdatePlayerStates(PlayerStateUpdate[] updates)
+getPlayerState(address player) returns (uint256, PlayerProfile, bool)
+getPlayerManaBalances(address player) returns (uint256, uint256)
+getPlayerProfile(address player) returns PlayerProfile
+getPlayerAchievements(address player) returns bytes32[]
+addPlayerAchievement(address player, bytes32 achievement)
+updatePlayerManaBalance(address player, uint256 newBalance)
+registerPlayer(address player)
+getTotalStats() returns (uint256, uint256)
+pause()
+unpause()
+paused() returns bool
+isPlayerRegistered(address player) returns bool
+getMultiplePlayerStates(address[] players) returns PlayerStateUpdate[]
+supportsInterface(bytes4 interfaceId) returns bool
}
class PlayerProfile {
+uint256 level
+uint256 experience
+uint256 totalManaEarned
+uint256 totalManaSpent
+uint256 lastActionTimestamp
+uint256 wins
+uint256 losses
+uint256 rating
+uint256 itemsCrafted
+bytes32[] achievements
}
class PlayerStateUpdate {
+address player
+uint256 newManaBalance
+PlayerProfile newProfile
}
ManaSettlement --> ManaToken : uses
ManaSettlement o-- PlayerProfile : manages
ManaSettlement o-- PlayerStateUpdate : manages
Заключение
ManaSettlement.sol — ключевой модуль управления состоянием игроков и их экономикой в игровой экосистеме, обеспечивающий безопасность, масштабируемость и прозрачность. Контракт построен с использованием проверенных стандартов и паттернов, что позволяет легко интегрировать его в более крупные системы и обеспечивать надёжное управление игровыми активами и статистикой.