Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
130 lines
4.4 KiB
Solidity
130 lines
4.4 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity 0.8.23;
|
|
|
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
|
import "./interfaces/ISeason1.sol";
|
|
|
|
/**
|
|
* @title AereQuestRegistry — AERE Season 1 "Altitude" quest catalogue
|
|
* @notice Foundation-owned registry describing every quest: its point weight,
|
|
* active window, per-user cap, active flag, and whether it requires a
|
|
* verified human. Fully TUNABLE without redeploying the ledger or the
|
|
* attestor — those read quest config live from here.
|
|
*
|
|
* A quest is keyed by a bytes32 questId (e.g. keccak256("create-passkey")).
|
|
*
|
|
* This contract holds NO funds and issues NO credits. It is pure config that
|
|
* the attestor and referral registry consult. Owner = Foundation multisig.
|
|
*/
|
|
contract AereQuestRegistry is Ownable, IAereQuestRegistry {
|
|
|
|
mapping(bytes32 => Quest) private _quests;
|
|
bytes32[] public questIds;
|
|
|
|
event QuestCreated(
|
|
bytes32 indexed questId,
|
|
uint256 weight,
|
|
uint64 startTime,
|
|
uint64 endTime,
|
|
uint256 perUserCap,
|
|
bool requiresVerifiedHuman
|
|
);
|
|
event QuestUpdated(
|
|
bytes32 indexed questId,
|
|
uint256 weight,
|
|
uint64 startTime,
|
|
uint64 endTime,
|
|
uint256 perUserCap,
|
|
bool requiresVerifiedHuman
|
|
);
|
|
event QuestActiveSet(bytes32 indexed questId, bool active);
|
|
|
|
error QuestExists();
|
|
error UnknownQuest();
|
|
error BadWindow();
|
|
error BadWeight();
|
|
|
|
/* ------------------------------- mutations ------------------------------ */
|
|
|
|
function createQuest(
|
|
bytes32 questId,
|
|
uint256 weight,
|
|
uint64 startTime,
|
|
uint64 endTime,
|
|
uint256 perUserCap,
|
|
bool requiresVerifiedHuman
|
|
) external onlyOwner {
|
|
if (questId == bytes32(0)) revert UnknownQuest();
|
|
if (_quests[questId].exists) revert QuestExists();
|
|
_validate(weight, startTime, endTime, perUserCap);
|
|
|
|
_quests[questId] = Quest({
|
|
weight: weight,
|
|
startTime: startTime,
|
|
endTime: endTime,
|
|
perUserCap: perUserCap,
|
|
active: true,
|
|
requiresVerifiedHuman: requiresVerifiedHuman,
|
|
exists: true
|
|
});
|
|
questIds.push(questId);
|
|
emit QuestCreated(questId, weight, startTime, endTime, perUserCap, requiresVerifiedHuman);
|
|
}
|
|
|
|
function updateQuest(
|
|
bytes32 questId,
|
|
uint256 weight,
|
|
uint64 startTime,
|
|
uint64 endTime,
|
|
uint256 perUserCap,
|
|
bool requiresVerifiedHuman
|
|
) external onlyOwner {
|
|
Quest storage q = _quests[questId];
|
|
if (!q.exists) revert UnknownQuest();
|
|
_validate(weight, startTime, endTime, perUserCap);
|
|
|
|
q.weight = weight;
|
|
q.startTime = startTime;
|
|
q.endTime = endTime;
|
|
q.perUserCap = perUserCap;
|
|
q.requiresVerifiedHuman = requiresVerifiedHuman;
|
|
emit QuestUpdated(questId, weight, startTime, endTime, perUserCap, requiresVerifiedHuman);
|
|
}
|
|
|
|
function setQuestActive(bytes32 questId, bool active) external onlyOwner {
|
|
if (!_quests[questId].exists) revert UnknownQuest();
|
|
_quests[questId].active = active;
|
|
emit QuestActiveSet(questId, active);
|
|
}
|
|
|
|
function _validate(uint256 weight, uint64 startTime, uint64 endTime, uint256 perUserCap) internal pure {
|
|
if (weight == 0) revert BadWeight();
|
|
// perUserCap must admit at least one completion.
|
|
if (perUserCap < weight) revert BadWeight();
|
|
// endTime 0 == open-ended; otherwise must be after start.
|
|
if (endTime != 0 && endTime <= startTime) revert BadWindow();
|
|
}
|
|
|
|
/* --------------------------------- views -------------------------------- */
|
|
|
|
function getQuest(bytes32 questId) external view returns (Quest memory) {
|
|
Quest memory q = _quests[questId];
|
|
if (!q.exists) revert UnknownQuest();
|
|
return q;
|
|
}
|
|
|
|
/// @notice True iff the quest exists, is active, and `atTime` is within its
|
|
/// window. endTime == 0 means open-ended.
|
|
function isOpen(bytes32 questId, uint256 atTime) external view returns (bool) {
|
|
Quest memory q = _quests[questId];
|
|
if (!q.exists || !q.active) return false;
|
|
if (atTime < q.startTime) return false;
|
|
if (q.endTime != 0 && atTime > q.endTime) return false;
|
|
return true;
|
|
}
|
|
|
|
function questCount() external view returns (uint256) {
|
|
return questIds.length;
|
|
}
|
|
}
|