feat: add AfterCoin (AFC) private blockchain for Minecraft casino
Some checks failed
Deploy / deploy (push) Has been cancelled
Some checks failed
Deploy / deploy (push) Has been cancelled
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>
This commit is contained in:
183
blockchain/contracts/AfterCoin.sol
Normal file
183
blockchain/contracts/AfterCoin.sol
Normal file
@@ -0,0 +1,183 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user