aere-contracts/contracts/season1/AerePointsLedger.sol
Aere Network a13a649b77
Some checks are pending
contracts-ci / Install (lockfile) → compile → full test suite (push) Waiting to run
contracts-ci / PQC known-answer tests (NIST vectors) (push) Waiting to run
contracts-ci / Coverage (scoped, with artifacts) (push) Waiting to run
Initial public release
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.
2026-07-20 01:02:37 +03:00

104 lines
4.2 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title AerePointsLedger — AERE Season 1 "Altitude" non-transferable points
* @notice A CREDIT-ONLY, NON-TRANSFERABLE ledger of "Altitude Points" (AP).
*
* HARD SAFETY DESIGN — AP is NOT a token and can never become one:
* - transfer / transferFrom / approve HARD-REVERT (NotTransferable). AP can
* never move between accounts, so it can never trade as a shadow token.
* - There is NO burn, NO redeem, NO conversion, NO "claim your tokens"
* path anywhere in this contract. AP is a scoreboard, nothing else.
* - Only Foundation-authorized attestors may `credit`. There is no mint()
* callable by users and no way for AP to leave an account.
*
* HONESTY / DISCLAIMER (must accompany any user-facing surfacing of AP):
* Altitude Points are NOT a token, carry NO guaranteed value, and confer
* NO right to returns. Any future reward depends on the network growing
* and is not promised. There is no listing.
*
* ERC-20 read shape (name/symbol/decimals/balanceOf/totalSupply) plus a
* mint-style Transfer(address(0), account, amount) event are emitted purely
* so block explorers / the AERE indexer can display balances. The WRITE side
* of ERC-20 is deliberately bricked.
*
* Owner = Foundation multisig. Ownable only manages the attestor allowlist;
* the owner cannot move, mint to itself for transfer, or reduce balances.
*/
contract AerePointsLedger is Ownable {
string public constant name = "AERE Altitude Points";
string public constant symbol = "AP";
uint8 public constant decimals = 0; // whole points, not a token
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
/// @notice Foundation-authorized credit sources (the quest attestor and the
/// referral registry are added here post-deploy).
mapping(address => bool) public isAttestor;
/* --------------------------------- events ------------------------------- */
/// @dev ERC-20 mint-style event for indexers. address(0) => account only.
event Transfer(address indexed from, address indexed to, uint256 value);
/// @dev Rich credit event carrying the quest attribution for the indexer.
event PointsCredited(address indexed account, uint256 amount, bytes32 indexed questId, uint256 newBalance);
event AttestorSet(address indexed attestor, bool allowed);
/* --------------------------------- errors ------------------------------- */
error NotTransferable();
error NotAttestor();
error ZeroAccount();
error ZeroAmount();
/* ------------------------------- attestors ------------------------------ */
function setAttestor(address attestor, bool allowed) external onlyOwner {
if (attestor == address(0)) revert ZeroAccount();
isAttestor[attestor] = allowed;
emit AttestorSet(attestor, allowed);
}
modifier onlyAttestor() {
if (!isAttestor[msg.sender]) revert NotAttestor();
_;
}
/* -------------------------------- credit -------------------------------- */
/// @notice Credit `amount` AP to `account`, attributed to `questId`.
/// Credit-only: balances can only ever go up.
function credit(address account, uint256 amount, bytes32 questId) external onlyAttestor {
if (account == address(0)) revert ZeroAccount();
if (amount == 0) revert ZeroAmount();
balanceOf[account] += amount;
totalSupply += amount;
emit Transfer(address(0), account, amount);
emit PointsCredited(account, amount, questId, balanceOf[account]);
}
/* --------------------------- bricked ERC-20 write ----------------------- */
function transfer(address, uint256) external pure returns (bool) {
revert NotTransferable();
}
function transferFrom(address, address, uint256) external pure returns (bool) {
revert NotTransferable();
}
function approve(address, uint256) external pure returns (bool) {
revert NotTransferable();
}
/// @notice Always zero — AP has no allowance concept.
function allowance(address, address) external pure returns (uint256) {
return 0;
}
}