// SPDX-License-Identifier: MIT pragma solidity 0.8.28; /// @title Aroex /// @notice $Aroex. Holding the token earns a pro-rata share of USDC sent here. /// x402 settlements are transferred in, then sync() records them for holders. interface IERC20 { function balanceOf(address account) external view returns (uint256); function transfer(address to, uint256 amount) external returns (bool); } contract Aroex { string public constant name = "Aroex"; string public constant symbol = "AROEX"; uint8 public constant decimals = 18; uint256 public constant MAGNITUDE = 2 ** 128; IERC20 public immutable usdc; uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; uint256 public magnifiedDividendPerShare; mapping(address => int256) public magnifiedDividendCorrections; mapping(address => uint256) public withdrawnDividends; uint256 public totalDividendsDistributed; uint256 public totalDividendsClaimed; event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); event DividendsDistributed(uint256 amount); event DividendClaimed(address indexed holder, uint256 amount); error ZeroAddress(); error InsufficientBalance(); error InsufficientAllowance(); error TransferFailed(); constructor(address usdcToken, address treasury) { if (usdcToken == address(0) || treasury == address(0)) revert ZeroAddress(); usdc = IERC20(usdcToken); _mint(treasury, 1_000_000_000 * 10 ** decimals); } /// @notice Record any USDC that arrived since the last sync. Share is balance / supply. function sync() external returns (uint256 incoming) { incoming = undistributed(); if (incoming == 0 || totalSupply == 0) return 0; magnifiedDividendPerShare += (incoming * MAGNITUDE) / totalSupply; totalDividendsDistributed += incoming; emit DividendsDistributed(incoming); } /// @notice USDC held by the contract that has not been assigned to holders yet. function undistributed() public view returns (uint256) { uint256 balance = usdc.balanceOf(address(this)); uint256 owed = totalDividendsDistributed - totalDividendsClaimed; if (balance <= owed) return 0; return balance - owed; } function accumulativeDividendOf(address holder) public view returns (uint256) { return uint256( int256(magnifiedDividendPerShare * balanceOf[holder]) + magnifiedDividendCorrections[holder] ) / MAGNITUDE; } function withdrawableDividendOf(address holder) public view returns (uint256) { return accumulativeDividendOf(holder) - withdrawnDividends[holder]; } function claim() external returns (uint256 amount) { amount = withdrawableDividendOf(msg.sender); if (amount == 0) return 0; withdrawnDividends[msg.sender] += amount; totalDividendsClaimed += amount; _usdcTransfer(msg.sender, amount); emit DividendClaimed(msg.sender, amount); } function approve(address spender, uint256 amount) external returns (bool) { if (spender == address(0)) revert ZeroAddress(); allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) external returns (bool) { _transfer(msg.sender, to, amount); return true; } function transferFrom(address from, address to, uint256 amount) external returns (bool) { uint256 allowed = allowance[from][msg.sender]; if (allowed != type(uint256).max) { if (allowed < amount) revert InsufficientAllowance(); allowance[from][msg.sender] = allowed - amount; } _transfer(from, to, amount); return true; } function _mint(address to, uint256 amount) internal { if (to == address(0)) revert ZeroAddress(); totalSupply += amount; balanceOf[to] += amount; magnifiedDividendCorrections[to] -= int256(magnifiedDividendPerShare * amount); emit Transfer(address(0), to, amount); } function _transfer(address from, address to, uint256 amount) internal { if (to == address(0)) revert ZeroAddress(); if (balanceOf[from] < amount) revert InsufficientBalance(); balanceOf[from] -= amount; balanceOf[to] += amount; int256 mag = int256(magnifiedDividendPerShare * amount); magnifiedDividendCorrections[from] += mag; magnifiedDividendCorrections[to] -= mag; emit Transfer(from, to, amount); } function _usdcTransfer(address to, uint256 amount) internal { bool ok = usdc.transfer(to, amount); if (!ok) revert TransferFailed(); } }