Files
consultoria-as 14279a878c
Some checks failed
Deploy / deploy (push) Has been cancelled
feat: add AfterCoin (AFC) private blockchain for Minecraft casino
Private Ethereum chain (Clique PoA, chain ID 8888) with ERC-20 token
(0 decimals, 1 AFC = 1 diamond) bridging casino balances on-chain so
players can view tokens in MetaMask.

- Geth v1.13.15 node with 5s block time, zero gas cost
- AfterCoin ERC-20 contract with owner-gated mint/burn/bridgeTransfer
- Bridge API (Express + ethers.js + SQLite) with register, deposit,
  withdraw, balance, and wallet endpoints
- Nonce queue for serial transaction safety
- Auto-deploys contract on first boot
- Updated mainframe Lua with diff-based on-chain sync (pcall fallback)
- Updated card generator Lua with wallet info display

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 00:48:22 +00:00

184 lines
7.1 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title AfterCoin (AFC)
* @notice ERC-20 token for the Afterlife Project game preservation platform.
* 1 AFC = 1 diamond. Zero decimals — integer-only balances.
* @dev Self-contained implementation (no OpenZeppelin). Owner-gated mint,
* burn-from, and bridge-transfer helpers for the off-chain bridge service.
*/
contract AfterCoin {
// ──────────────────────────── ERC-20 metadata ────────────────────────────
string private constant _name = "AfterCoin";
string private constant _symbol = "AFC";
uint8 private constant _decimals = 0; // 1 token = 1 diamond
// ──────────────────────────── State ──────────────────────────────────────
uint256 private _totalSupply;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
address public owner;
// ──────────────────────────── Events (ERC-20) ────────────────────────────
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
// ──────────────────────────── Errors ─────────────────────────────────────
error NotOwner();
error ZeroAddress();
error InsufficientBalance(address account, uint256 required, uint256 available);
error InsufficientAllowance(address spender, uint256 required, uint256 available);
// ──────────────────────────── Modifier ───────────────────────────────────
modifier onlyOwner() {
if (msg.sender != owner) revert NotOwner();
_;
}
// ──────────────────────────── Constructor ────────────────────────────────
constructor() {
owner = msg.sender;
// Initial supply is 0 — tokens are minted on demand by the bridge.
}
// ──────────────────────────── ERC-20 view functions ──────────────────────
function name() external pure returns (string memory) {
return _name;
}
function symbol() external pure returns (string memory) {
return _symbol;
}
function decimals() external pure returns (uint8) {
return _decimals;
}
function totalSupply() external view returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) external view returns (uint256) {
return _balances[account];
}
function allowance(address tokenOwner, address spender) external view returns (uint256) {
return _allowances[tokenOwner][spender];
}
// ──────────────────────────── ERC-20 mutative functions ──────────────────
function transfer(address to, uint256 amount) external returns (bool) {
_transfer(msg.sender, to, amount);
return true;
}
function approve(address spender, uint256 amount) external returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool) {
uint256 currentAllowance = _allowances[from][msg.sender];
if (currentAllowance != type(uint256).max) {
if (currentAllowance < amount) {
revert InsufficientAllowance(msg.sender, amount, currentAllowance);
}
unchecked {
_approve(from, msg.sender, currentAllowance - amount);
}
}
_transfer(from, to, amount);
return true;
}
// ──────────────────────────── Owner-only functions ───────────────────────
/**
* @notice Mint new tokens to `to`. Only callable by the contract owner.
* @param to Recipient address.
* @param amount Number of tokens to create.
*/
function mint(address to, uint256 amount) external onlyOwner {
if (to == address(0)) revert ZeroAddress();
_totalSupply += amount;
_balances[to] += amount;
emit Transfer(address(0), to, amount);
}
/**
* @notice Burn tokens from `from`. Only callable by the contract owner.
* Does NOT require an allowance — the owner is the bridge operator.
* @param from Address whose tokens are burned.
* @param amount Number of tokens to destroy.
*/
function burnFrom(address from, uint256 amount) external onlyOwner {
if (from == address(0)) revert ZeroAddress();
uint256 bal = _balances[from];
if (bal < amount) {
revert InsufficientBalance(from, amount, bal);
}
unchecked {
_balances[from] = bal - amount;
}
_totalSupply -= amount;
emit Transfer(from, address(0), amount);
}
/**
* @notice Transfer tokens between two addresses on behalf of the bridge.
* Only callable by the contract owner.
* @param from Source address.
* @param to Destination address.
* @param amount Number of tokens to move.
*/
function bridgeTransfer(
address from,
address to,
uint256 amount
) external onlyOwner {
_transfer(from, to, amount);
}
// ──────────────────────────── Internal helpers ───────────────────────────
function _transfer(address from, address to, uint256 amount) internal {
if (from == address(0)) revert ZeroAddress();
if (to == address(0)) revert ZeroAddress();
uint256 fromBal = _balances[from];
if (fromBal < amount) {
revert InsufficientBalance(from, amount, fromBal);
}
unchecked {
_balances[from] = fromBal - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
}
function _approve(address tokenOwner, address spender, uint256 amount) internal {
if (tokenOwner == address(0)) revert ZeroAddress();
if (spender == address(0)) revert ZeroAddress();
_allowances[tokenOwner][spender] = amount;
emit Approval(tokenOwner, spender, amount);
}
}