Moon

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "contracts/Moon.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.24;\r
\r
/* \r
 ┌────────────────────────────────────────────────────────────────────────┐\r
 │                                                                        │\r
 │                 ███    ███  ██████   ██████  ███    ██                 │\r
 │                 ████  ████ ██    ██ ██    ██ ████   ██                 │\r
 │                 ██ ████ ██ ██    ██ ██    ██ ██ ██  ██                 │\r
 │                 ██  ██  ██ ██    ██ ██    ██ ██  ██ ██                 │\r
 │                 ██      ██  ██████   ██████  ██   ████                 │\r
 │                                                                        │\r
 │                                                                        │\r
 │  MOON is the heart of a fully decentralized discovery system. It       │\r
 │  converts swap activity into reflections for SUN holders while         │\r
 │  benefiting every project that pairs with it.                          │       \r
 │                                                                        │\r
 │  How it works                                                          │\r
 │   • All swaps through official Uniswap V2 pairs are taxed 3%.          │                             \r
 │   • MOON uses the tax to buy back the paired token and distributes it  │\r
 │     to SUN holders automatically.                                      │\r
 │   • Wallet transfers, liquidity mints/burns as well as swaps on other  │\r
 │     DEXs are untaxed.                                                  │\r
 │                                                                        │\r
 │  Add your token                                                        │                                                     \r
 │   • Create a liquidity pair with your token and MOON on Uniswap V2:    │                                                                                  \r
 │        → Add your token first.                                         │\r
 │        → Add MOON second. (Uniswap UI: MOON on the right)              │\r
 │   • This lets you add/remove liquidity tax free and plugs your         │\r
 │     token into the reflection system automatically.                    │\r
 │                                                                        │\r
 │  Why pair with MOON?                                                   │\r
 │   • Organic exposure: Natural arbitrage connects your token directly   │\r
 │     with SUN holders, building awareness without paid promotion.       │\r
 │   • Constant buy pressure: whether users buy or sell through the pair, │\r
 │     the tax is always used to buy your token.                          │\r
 │   • Enhanced LP rewards: a built-in “pair bonus” leaves part of        │\r
 │     swap-back yield in the pool, boosting LP take on top of V2 fees.   │\r
 │                                                                        │\r
 └────────────────────────────────────────────────────────────────────────┘\r
*/\r
\r
/*────────────────────────────  INTERFACES  ─────────────────────────────*/\r
\r
/// @dev Minimal ERC-20 subset used by this contract.\r
interface IERC20 {\r
    function totalSupply() external view returns (uint256);\r
    function balanceOf(address owner) external view returns (uint256);\r
    function allowance(address owner, address spender) external view returns (uint256);\r
    function approve(address spender, uint256 amount) external returns (bool);\r
    function transfer(address recipient, uint256 amount) external returns (bool);\r
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\r
\r
    event Transfer(address indexed from, address indexed to, uint256 value);\r
    event Approval(address indexed owner, address indexed spender, uint256 value);\r
}\r
\r
/// @dev Uniswap V2 Pair subset used by the contract’s swap-backs.\r
interface IUniswapV2Pair {\r
    function swap(\r
        uint amount0Out,  \r
        uint amount1Out,\r
        address to,\r
        bytes calldata data\r
    ) external;\r
}\r
\r
/// @notice Vault payout used in _emitRay.\r
interface IVault {\r
    function releaseToMember(address ray, uint256 amount, address member) external;\r
}\r
\r
/// @notice All other external calls use precomputed selectors\r
\r
/*──────────────────────── FLOAT‑96 CODEC (88+8) ────────────────────────*/\r
\r
/// @title Uint256 <-> Float96 (88-bit mantissa + 8-bit exponent)\r
/// @notice Compact, lossy encoding for non-negative uint256 values.\r
/// @dev Layout: packed[95:88]=exponent, packed[87:0]=mantissa.\r
///      Decodes as (mantissa << exponent). Rounding = nearest, ties-to-even.\r
library Uint256Float96 {\r
    uint256 private constant MANTISSA_BITS = 88;\r
    uint256 private constant EXPONENT_BITS = 8; // reserved for clarity\r
    uint256 private constant MANTISSA_MASK = (uint256(1) << MANTISSA_BITS) - 1;\r
    uint8   private constant MAX_EXPONENT  = 168; // 256 - 88\r
\r
    error BadPackedExponent(uint8 e);\r
\r
    /// @notice Encode a uint256 into a uint96 float-like value.\r
    /// @dev Exact for values < 2^88 (exponent=0). Larger values are rounded\r
    ///      to nearest, ties-to-even; may saturate if exponent would overflow.\r
    function encode(uint256 x) internal pure returns (uint96 packed) {\r
        if (x == 0) return 0;\r
\r
        // Find msb(x). After this block: bitLen = floor(log2(x)) + 1.\r
        uint256 msb;\r
        unchecked {\r
            uint256 y = x;\r
            if (y >= 1 << 128) { y >>= 128; msb += 128; }\r
            if (y >= 1 <<  64) { y >>=  64; msb +=  64; }\r
            if (y >= 1 <<  32) { y >>=  32; msb +=  32; }\r
            if (y >= 1 <<  16) { y >>=  16; msb +=  16; }\r
            if (y >= 1 <<   8) { y >>=   8; msb +=   8; }\r
            if (y >= 1 <<   4) { y >>=   4; msb +=   4; }\r
            if (y >= 1 <<   2) { y >>=   2; msb +=   2; }\r
            if (y >= 1 <<   1) {           msb +=   1; }\r
        }\r
        uint256 bitLen = msb + 1;\r
\r
        // Fits entirely in mantissa -> exponent=0, exact store.\r
        if (bitLen <= MANTISSA_BITS) {\r
            return uint96(x);\r
        }\r
\r
        // Normalize into 88-bit mantissa and an exponent in [1..168].\r
        uint256 shift = bitLen - MANTISSA_BITS;\r
        uint256 mant  = x >> shift;\r
\r
        // Round to nearest, ties-to-even.\r
        {\r
            uint256 remMask = (uint256(1) << shift) - 1;\r
            uint256 rem     = x & remMask;\r
            uint256 half    = uint256(1) << (shift - 1);\r
            bool roundUp    = (rem > half) || (rem == half && (mant & 1) == 1);\r
\r
            if (roundUp) {\r
                unchecked { mant += 1; }\r
                // If rounding overflowed mantissa to 2^88, renormalize.\r
                if (mant == (uint256(1) << MANTISSA_BITS)) {\r
                    mant >>= 1;\r
                    shift += 1;\r
                }\r
            }\r
        }\r
\r
        // Saturate if exponent would exceed representable range.\r
        if (shift > MAX_EXPONENT) {\r
            shift = MAX_EXPONENT;\r
            mant  = MANTISSA_MASK;\r
        }\r
\r
        // Pack: [ exponent | mantissa ].\r
        return (uint96(uint8(shift)) << uint96(MANTISSA_BITS)) | uint96(mant & MANTISSA_MASK);\r
    }\r
\r
    /// @notice Decode a packed uint96 back into a uint256.\r
    /// @dev Reverts if exponent field is malformed (> MAX_EXPONENT).\r
    function decode(uint96 packed) internal pure returns (uint256 x) {\r
        uint8 exponent = uint8(packed >> MANTISSA_BITS);\r
        if (exponent > MAX_EXPONENT) revert BadPackedExponent(exponent);\r
\r
        uint256 mantissa = uint256(packed) & MANTISSA_MASK;\r
        return mantissa << exponent;\r
    }\r
}\r
\r
/*────────────────────────────────  MOON  ───────────────────────────────*/\r
\r
/// @title Moon (MOON)\r
/// @notice ERC‑20 token with integrated pair‑aware taxation and SUN reflections.\r
contract Moon is IERC20 {\r
\r
    /*//////////////////////////////////////////////////////////////////////\r
                                  METADATA                                \r
    //////////////////////////////////////////////////////////////////////*/\r
\r
    /// @notice Token name.\r
    string  public constant name     = "Moon";\r
    /// @notice Token symbol.\r
    string  public constant symbol   = "MOON";\r
    /// @notice Token decimals (fixed at 18).\r
    uint8   public constant decimals = 18;\r
\r
    /*//////////////////////////////////////////////////////////////////////\r
                                    EVENTS                                 \r
    //////////////////////////////////////////////////////////////////////*/\r
\r
    /// @dev Fired once when a new ray (paired token) is discovered & cached.\r
    event RayInitialized(address indexed ray);\r
\r
    /*//////////////////////////////////////////////////////////////////////\r
                                  IMMUTABLES                               \r
    //////////////////////////////////////////////////////////////////////*/\r
\r
    /// @notice Total SUN supply credited at deploy (1e18‑scaled).\r
    uint256 private immutable totalSunSupply;\r
\r
    /// @notice Verified Uniswap‑style V2 factory used for pair recognition.\r
    address private immutable factory;\r
\r
    /// @notice SUN ERC‑20 contract linked for distributions.\r
    address private immutable sun;\r
\r
    /// @notice Vault that custodies Rays.\r
    address private immutable vault;\r
\r
    /// @notice Uniswap‑style fee in basis points (e.g., 30 for 0.30%).\r
    uint24  private immutable feeBps;\r
\r
    /// @notice Multiplier used in x*y=k fee math: (FEE_DENOMINATOR - feeBps).\r
    /// @dev Example: 9_970 for a 0.30% fee.\r
    uint24  private immutable feeMul;\r
\r
    /*//////////////////////////////////////////////////////////////////////\r
                                   CONSTANTS                                \r
    //////////////////////////////////////////////////////////////////////*/\r
\r
    /// @dev Basis points denominator for AMM fee math (10_000 = 100%).\r
    uint24 private constant FEE_DENOMINATOR     = 10_000;\r
\r
    /// @notice Swap tax rate (3%).\r
    uint256 private constant SWAP_TAX           = 3e16;\r
\r
    /// @notice Percentage of swap-back left in the pair as an LP bonus (25%).\r
    uint256 private constant PAIR_BONUS         = 25e16;\r
\r
    /// @notice Appreciation tax applied to positive value deltas (20%).\r
    uint256 private constant APPRECIATION_TAX   = 20e16;\r
\r
    /// @notice Gas stipend for the radiation loop.\r
    uint256 private constant RADIATE_GAS_LIMIT  = 220_000;\r
\r
    /// @notice Gas stipend for swapBack.\r
    uint256 private constant SWAPBACK_CALL_GAS  = 350_000;\r
\r
    /// @notice Minimum pending MOON before a swap-back is attempted (1 MOON).\r
    uint256 private constant MIN_SWAP_BACK      = 1e18;\r
\r
    /// @notice Minimum value emitted per payout (1e-9 MOON).\r
    uint256 private constant MIN_EMIT           = 1e9;\r
\r
    /// @notice Minimum SUN tokens for automatic payout (1 SUN)\r
    /// Members below this threshold can still call collect()\r
    uint256 private constant MIN_SUN_RADIATE    = 1e18;\r
\r
    /// @notice Maximum distinct tokens to attempt in a single payout iteration.\r
    uint256 private constant MAX_PAYOUT_TOKENS  = 6;\r
\r
    /// @notice Index scaling factor (1e32) — “index decimals”.\r
    uint256 private constant INDEX_DECIMALS     = 1e32;\r
\r
    /// @notice Conventional burn sink address (irretrievable).\r
    /// @dev Tokens sent here are considered permanently destroyed.\r
    address private constant DEAD = 0x000000000000000000000000000000000000dEaD;\r
\r
    /*//////////////////////////////////////////////////////////////////////\r
                                ERC-20 STORAGE                             \r
    //////////////////////////////////////////////////////////////////////*/\r
\r
    /// @notice Current total supply of MOON tokens in existence.\r
    /// @dev This value is initialized at deployment and monotonically decreases \r
    ///      as tokens are burned. There is no mechanism to increase supply.\r
    uint256 public override totalSupply;\r
\r
    /// @dev MOON balances.\r
    mapping(address => uint256) internal balances;\r
\r
    /// @dev ERC‑20 allowances: owner => (spender => amount).\r
    mapping(address => mapping(address => uint256)) internal allowances;\r
\r
    /*//////////////////////////////////////////////////////////////////////\r
                           CLASSIFICATION BOOKKEEPING                         \r
    //////////////////////////////////////////////////////////////////////*/\r
    \r
    /*\r
     * moonClass:\r
     *   0 = unknown (not yet probed)\r
     *   1 = regular holder or non‑verified contract\r
     *   2 = verified V2 pair that contains MOON (taxed)\r
     */\r
    mapping(address => uint8) internal moonClass;\r
\r
    /*//////////////////////////////////////////////////////////////////////\r
                               SUN MEMBER STATE                            \r
    //////////////////////////////////////////////////////////////////////*/\r
\r
    /// @dev Member accounting snapshot (first four fields are persisted).\r
    struct Member {\r
        // persisted fields\r
        uint128 pastIndex;   // index snapshot (1e32‑scaled)\r
        uint112 uncollected; // uncollected value (MOON‑value terms)\r
        uint8   class;       // 0 unknown | 1 eligible | 2 ineligible\r
        uint8   status;      // 0 not active | 1 queued for removal | 2 active\r
\r
        // transient helpers (NEVER written to storage) \r
        address self;        // member address in memory\r
        uint256 balance;     // SUN balance (queried lazily)\r
    }\r
\r
    /// @dev Member records (only the first four fields are read/written).\r
    mapping(address => Member) internal members;\r
\r
    /*//////////////////////////////////////////////////////////////////////\r
                               RAY TOKEN STATE                        \r
    //////////////////////////////////////////////////////////////////////*/\r
\r
    /// @dev Ray = per‑token accounting for a reflection asset paired with MOON.\r
    struct Ray {\r
        // slot 0\r
        address pair;             // verified V2 pair that contains MOON & this ray\r
\r
        // slot 1 (tightly packed to 256 bits)\r
        uint112 reserve;          // current Vault balance credited as “value bearing”\r
        uint112 pending;          // pending MOON earmarked for swap‑back\r
        uint8   swapStatus;       // 0 not listed | 2 in swapQueue\r
        uint8   brightStatus;     // 0 not listed | 1 pending removal | 2 in brightRays\r
        bool    thisZero;         // true if MOON is token0 in the pair\r
\r
        // slot 2 (tightly packed to 256 bits)\r
        uint96  quote96;          // MOON per token, 1e38‑scaled (compressed)\r
        uint96  candidateQuote96; // intra‑block max quote (compressed)\r
        uint64  updateBlock;      // last quote update block\r
\r
        // transient helpers (NEVER written to storage)\r
        address self;             // this ray address (for convenience)\r
        uint256 ra;               // pair’s ray reserve (pre‑event)\r
        uint256 rm;               // pair’s MOON reserve (pre‑event)\r
        uint256 quote;            // decoded committed quote (1e38‑scaled)\r
        uint256 candidateQuote;   // decoded candidate quote (1e38‑scaled)\r
        uint256 cursor;           // place in brightRays list during emitRay\r
    }\r
\r
    /// @dev Per‑token accounting. Public getter exposes persisted fields.\r
    mapping(address => Ray) internal rays;\r
\r
    /*//////////////////////////////////////////////////////////////////////\r
                                  PAIR STATE                        \r
    //////////////////////////////////////////////////////////////////////*/\r
\r
     /// @dev Per-pair bookkeeping.\r
    struct Pair {\r
        address ray;       // Ray associated with that pair\r
        bool    swapLock;  // prevents swaps during untaxed mints/burns\r
    }\r
\r
    /// @notice Registered pairs containing MOON, keyed by pair address.\r
    mapping(address => Pair) public pairs;\r
\r
    /*//////////////////////////////////////////////////////////////////////\r
                          GLOBAL AGGREGATES (PACKED)                         \r
    //////////////////////////////////////////////////////////////////////*/\r
\r
    /// @dev [hi 128] = active SUN tokens | [lo 128] = index (1e32‑scaled).\r
    uint256 private packedIndexAndActive;\r
\r
    /// @dev [hi 128] = oath (MOON‑value) | [lo 128] = pool (MOON‑value).\r
    uint256 private packedPoolAndOath;\r
\r
    /// @dev Ephemeral “global” bundle to pass between helpers.\r
    struct GlobalMemory {\r
        uint128 pool;   // total value currently held by vault\r
        uint128 oath;   // total value owed to active SUN members\r
        uint128 index;  // cumulative owed value/share (1e32‑scaled)\r
        uint128 active; // total SUN tokens held by active SUN members\r
    }\r
\r
    /*//////////////////////////////////////////////////////////////////////\r
                           DYNAMIC LISTS & CURSORS                          \r
    //////////////////////////////////////////////////////////////////////*/\r
\r
    /// @dev Tokens whose pairs should be swapped through (pending ≥ MIN_SWAP_BACK).\r
    address[] private swapQueue;\r
\r
    /// @dev Rays ready to be distributed to SUN members.\r
    address[] private brightRays;\r
\r
    /// @dev Active SUN members (round‑robin radiation processor).\r
    address[] private activeMembers;\r
\r
    /// @dev Cursor for `activeMembers` round‑robin.\r
    uint256 public activeMembersCursor;\r
\r
    /*//////////////////////////////////////////////////////////////////////////\r
                              PRECOMPUTED SELECTORS\r
    //////////////////////////////////////////////////////////////////////////*/\r
\r
    /// @dev Precomputed selectors for gas savings.\r
    bytes4 constant SEL_BALANCEOF     = bytes4(keccak256("balanceOf(address)"));         // ERC-20 style balanceOf(owner)\r
    bytes4 constant SEL_V1_tokenAddr  = bytes4(keccak256("tokenAddress()"));             // Uniswap V1: tokenAddress()\r
    bytes4 constant SEL_TOKEN0        = bytes4(keccak256("token0()"));                   // token0()\r
    bytes4 constant SEL_TOKEN1        = bytes4(keccak256("token1()"));                   // token1()    \r
    bytes4 constant SEL_BALANCEOF6909 = bytes4(keccak256("balanceOf(address,uint256)")); // ERC‑6909 style balanceOf(owner,id)\r
    bytes4 constant SEL_GETRESERVES   = bytes4(keccak256("getReserves()"));              // Uniswap V2: getReserves()\r
    bytes4 constant SEL_GETPAIR       = bytes4(keccak256("getPair(address,address)"));   // Ask factory for pair   \r
\r
    /*//////////////////////////////////////////////////////////////////////\r
                               REENTRANCY GUARDS                          \r
    //////////////////////////////////////////////////////////////////////*/\r
\r
    /// @dev Reentrancy guard state: 1 = unlocked, 2 = locked. Never write zero (gas savings)\r
    uint256 private constant _UNLOCKED = 1;\r
    uint256 private constant _LOCKED   = 2;\r
\r
    /// @dev Storage slot for the guard (initialized to unlocked).\r
    uint256 private _reentrancyStatus = _UNLOCKED;\r
\r
    /// @notice Reentrancy guard using a dedicated storage slot (sload/sstore).\r
    /// @dev\r
    /// - Uses non-zero states (1↔2) to avoid clearing slot.\r
    /// - Contract-wide single-entry guard: an external `nonReentrant` function\r
    ///   cannot `external`-call another `nonReentrant` one in the same tx.\r
    /// - Pattern: check-effects-interactions still applies inside the body.\r
    modifier nonReentrant() {\r
        require (_reentrancyStatus == _UNLOCKED, "Reentrancy");\r
        _reentrancyStatus = _LOCKED;\r
        _;\r
        _reentrancyStatus = _UNLOCKED;\r
    }\r
\r
    /*//////////////////////////////////////////////////////////////////////////\r
                                   CONSTRUCTOR\r
    //////////////////////////////////////////////////////////////////////////*/\r
\r
    /// @notice Initializes Moon: mints full supply to deployer, wires SUN/Vault, and seeds SUN accounting.\r
    /// @dev Scales `supply` and `sunSupply` by 1e18; requires non-zero key addrs and `v2FactoryFee <= 10_000` BPS.\r
    ///      Caches factory/fee, marks Moon/SUN/Vault as ineligible for reflections, seeds SUN accounting,\r
    ///      enlists sunDeployer in the active rotation, and emits the initial {Transfer}.\r
    /// @param supply             Whole-token MOON amount to mint to deployer (unscaled; 18 decimals applied).\r
    /// @param verifiedV2Factory  Canonical V2 factory used to recognize taxable pairs.\r
    /// @param v2FactoryFee       Factory swap fee in basis points (e.g., 30 = 0.30%).\r
    /// @param sunAddress         SUN ERC-20 used for distributions.\r
    /// @param vaultAddress       Vault that holds rays.\r
    /// @param sunDeployer        Initial SUN holder to seed reflection index.\r
    /// @param sunSupply          Whole-token SUN credited to `sunDeployer` (unscaled; 18 decimals applied).\r
    constructor(\r
        uint256  supply,\r
        address  verifiedV2Factory,\r
        uint24   v2FactoryFee,\r
        address  sunAddress,\r
        address  vaultAddress,\r
        address  sunDeployer,\r
        uint256  sunSupply\r
    )\r
    {\r
        // ──────────────────────────── Sanity checks ────────────────────────────\r
        // Require all critical external addresses (factory, SUN, Vault) to be set.\r
        require(\r
            verifiedV2Factory != address(0) &&\r
            sunAddress        != address(0) &&\r
            sunDeployer       != address(0) &&\r
            vaultAddress      != address(0),\r
            "zero address"\r
        );\r
\r
        // Ensure AMM fee (in BPS) is not larger than 100% (10_000 BPS).\r
        require(v2FactoryFee <= FEE_DENOMINATOR, "fee too large");\r
\r
        // Bound the unscaled MOON and SUN supplies so that, once multiplied by 1e18,\r
        // they can still be safely packed into the internal uint112 fields used elsewhere.\r
        require(supply    <= type(uint112).max / 1e18 &&\r
                sunSupply <= type(uint112).max / 1e18, "Supply too large");\r
        \r
        // ──────────────────────── Immutable configuration ───────────────────────\r
        // Save addresses/fee knobs used for pair detection & AMM math.\r
        factory        = verifiedV2Factory;                // Canonical (taxable) V2 factory\r
        sun            = sunAddress;                       // SUN token used for payouts\r
        vault          = vaultAddress;                     // Custody for rays\r
        totalSupply    = supply * 1e18;                    // Scale to 18 decimals\r
        totalSunSupply = sunSupply * 1e18;                 // Scale to 18 decimals\r
        feeBps         = v2FactoryFee;                     // e.g., 30 for 0.30%\r
        feeMul         = uint24(FEE_DENOMINATOR - feeBps); // e.g., 9_970 for 0.30%\r
\r
        // ─────────────────────────── Mint MOON to deployer ──────────────────────\r
        // Mint the entire MOON supply to the deployer (`msg.sender`).\r
        balances[msg.sender] = totalSupply;\r
\r
        // Cache the deployer as a known class-1 MOON holder (regular holder, not a pair).\r
        // (micro-gas: avoids first-touch classification on their first transfer)\r
        moonClass[msg.sender] = 1;\r
\r
        // Standard ERC-20 Transfer event for the initial mint.\r
        emit Transfer(address(0), msg.sender, totalSupply);\r
\r
        // ────────────────────────── Seed SUN bookkeeping ────────────────────────\r
        // Add the initial SUN holder to the active rotation list.\r
        activeMembers.push(sunDeployer);\r
\r
        // Mark MOON, SUN, and Vault as class-2 for SUN eligibility (ineligible).\r
        // - MOON contract itself (no dividends to the token contract)\r
        // - SUN token contract\r
        // - Vault (custody contract)\r
        members[address(this)].class = 2;\r
        members[sunAddress].class    = 2;\r
        members[vaultAddress].class  = 2;\r
\r
        // Initialize the global dividend index & active SUN supply:\r
        //   index   = 0 (no value distributed yet)\r
        //   active  = totalSunSupply (all initial SUN held by `sunDeployer`)\r
        writeIndexActive(0, uint128(totalSunSupply));\r
\r
        // Initialize the `sunDeployer` member record:\r
        //   class   = 1 (eligible holder)\r
        //   status  = 2 (in activeMembers rotation)\r
        writeMember(sunDeployer, 0, 0, 1, 2);\r
\r
        // Initialize DEAD as ineligible for emissions.\r
        //   class   = 2 (ineligible)\r
        writeMember(DEAD, 0, 0, 2, 0);\r
\r
    }\r
\r
    /*//////////////////////////////////////////////////////////////////////////\r
                                ERC-20 — VIEW FUNCTIONS\r
    //////////////////////////////////////////////////////////////////////////*/\r
\r
    /// @notice Return MOON balance of `owner`.\r
    /// @dev Can revert only when part of a deceptive swap.\r
    function balanceOf(address owner) public view override returns (uint256) {\r
        require(_unlocked(owner), "Moon: Pair locked. Call skim()");\r
        return balances[owner];\r
    }\r
\r
    /// @notice Return allowance from `owner` to `spender`.\r
    function allowance(address owner, address spender) public view override returns (uint256) {\r
        return allowances[owner][spender];\r
    }\r
\r
    /// @notice Returns the number of tokens currently in the swap queue.\r
    function swapQueueLength() external view returns (uint256) {\r
        return swapQueue.length;\r
    }\r
\r
    /// @notice Returns the number of rays currently marked as bright rays.\r
    function brightRaysLength() external view returns (uint256) {\r
        return brightRays.length;\r
    }\r
\r
    /// @notice Returns the number of active SUN members in the rotation.\r
    function activeMembersLength() external view returns (uint256) {\r
        return activeMembers.length;\r
    }\r
\r
    /// @notice Returns the current global pool and oath values (MOON-value terms).\r
    function getPoolOath() external view returns (uint128 pool, uint128 oath) {\r
        (pool, oath) = readPoolOath();\r
    }\r
\r
    /// @notice Returns the current global dividend index and active SUN supply.\r
    function getIndexActive() external view returns (uint128 index, uint128 active) {\r
        (index, active) = readIndexActive();\r
    }\r
\r
    /// @notice Returns the stored member record for a given SUN holder.\r
    /// @dev Exposes the persisted fields of the Member struct from storage.\r
    /// @param a The SUN holder’s address.\r
    /// @return pastIndex   Last index checkpoint for this member (1e32-scaled).\r
    /// @return uncollected Accrued but unclaimed MOON-value credit.\r
    /// @return class       Eligibility class (1 = eligible, 2 = ineligible).\r
    /// @return status      List status code (0 = none, 1 = pending removal, 2 = active).\r
    function getMember(address a)\r
        external\r
        view\r
        returns (uint128 pastIndex, uint112 uncollected, uint8 class, uint8 status)\r
    {\r
        (pastIndex, uncollected, class, status) = readMember(a);\r
    }\r
\r
    /// @notice Returns the stored ray accounting data for a given paired token.\r
    /// @dev Provides both persisted fields and live Vault balance/decoded quotes.\r
    /// @param  token The address of the paired token (ray) to inspect.\r
    /// @return pair            Verified V2 pair that contains MOON and this token.\r
    /// @return reserve         Credited Vault reserve for this token.\r
    /// @return liveVaultBal    Current on-chain Vault balance for this token.\r
    /// @return pending         Pending MOON earmarked for swap-back.\r
    /// @return swapStatus      Swap queue status.\r
    /// @return brightStatus    Bright-rays list status.\r
    /// @return thisZero        True if MOON is token0 in the pair.\r
    /// @return decodedQuote    Committed price quote (MOON per token, 1e38-scaled).\r
    /// @return candidateQuote  Candidate intra-block high quote (1e38-scaled).\r
    /// @return updateBlock     Block number of last quote update.\r
    function getRay(address token)\r
        external\r
        view\r
        returns (\r
            address pair,\r
            uint112 reserve,\r
            uint256 liveVaultBal,\r
            uint112 pending,\r
            uint8   swapStatus,\r
            uint8   brightStatus,\r
            bool    thisZero,\r
            uint256 decodedQuote,\r
            uint256 candidateQuote,\r
            uint64  updateBlock\r
        )\r
    {\r
        Ray memory r;\r
        r.self = token;\r
        (,liveVaultBal) = _safeBalanceOf(token, vault);\r
        (r.pair) = readRay0(r.self);\r
        (r.reserve, r.pending, r.swapStatus, r.brightStatus, r.thisZero) = readRay1(r.self);\r
        (r.quote, r.candidateQuote, r.updateBlock) = readRay2(r.self);\r
        return (\r
            r.pair,\r
            r.reserve,\r
            liveVaultBal,\r
            r.pending,\r
            r.swapStatus,\r
            r.brightStatus,\r
            r.thisZero,\r
            r.quote,\r
            r.candidateQuote,\r
            r.updateBlock\r
        );\r
    }\r
\r
    /*//////////////////////////////////////////////////////////////////////////\r
                    ERC-20 — MUTATIVE (ALLOWANCE & TRANSFERS)\r
    //////////////////////////////////////////////////////////////////////////*/\r
\r
    /// @notice Approve `spender` to transfer up to `amount` MOON on caller’s behalf.\r
    /// @dev Emits an {Approval} event.\r
    function approve(address spender, uint256 amount)\r
        external \r
        override\r
        returns (bool)\r
    {\r
        _approve(msg.sender, spender, amount);\r
        return true;\r
    }\r
\r
    /// @notice Transfer `amount` MOON from msg.sender to `to`.\r
    /// @dev Triggers tax logic when interacting with class-2 V2 pairs.\r
    function transfer(address to, uint256 amount)\r
        external\r
        override\r
        nonReentrant\r
        returns (bool)\r
    {\r
        _transfer(msg.sender, to, amount);\r
        return true;\r
    }\r
\r
    /// @notice Move `amount` MOON from `from` to `to` using caller’s allowance.\r
    /// @dev Deducts allowance and emits {Transfer} & {Approval} events.\r
    function transferFrom(address from, address to, uint256 amount)\r
        external\r
        override\r
        nonReentrant\r
        returns (bool)\r
    {\r
        uint256 currentAllowance = allowances[from][msg.sender];\r
        if (currentAllowance != type(uint256).max) {\r
            require(currentAllowance >= amount, "ERC20: insufficient allowance");\r
            unchecked {\r
                allowances[from][msg.sender] = currentAllowance - amount;\r
            }\r
            emit Approval(from, msg.sender, currentAllowance - amount);\r
        }\r
        _transfer(from, to, amount);\r
        return true;\r
    }\r
\r
    /*//////////////////////////////////////////////////////////////////////////\r
                            ERC-20 — INTERNAL MUTATORS\r
    //////////////////////////////////////////////////////////////////////////*/\r
\r
    /// @notice Set `spender`'s allowance over `owner`'s tokens to `amount`.\r
    /// @dev Internal helper, emits an {Approval} event.\r
    function _approve(address owner, address spender, uint256 amount) internal {\r
        allowances[owner][spender] = amount;\r
        emit Approval(owner, spender, amount);\r
    }\r
\r
    /// @notice Permanently destroys `amount` of MOON from `from`, reducing the total supply.\r
    /// @dev\r
    /// Behavior:\r
    ///  • Updates storage under `unchecked` (safe after guards).  \r
    ///  • Emits the ERC-20 canonical {Transfer} to the zero address.\r
    /// @param from   The address whose balance is reduced (often `address(this)`).\r
    /// @param amount The amount of MOON to destroy (18-decimals).\r
    function _burn(address from, uint256 amount) internal {\r
        require(balances[from] >= amount);\r
        unchecked {\r
            balances[from] -= amount;\r
            totalSupply    -= amount;\r
        }\r
        emit Transfer(from, address(0), amount); // ERC-20 canonical burn signal\r
    }\r
\r
    /// @notice Internal untaxed transfer helper — moves MOON without any classification or hooks.\r
    /// @dev\r
    ///  • Performs only balance updates and emits the standard {Transfer} event.  \r
    ///  • Skips all taxation, swap-back, and radiation logic.  \r
    ///  • Reverts if `from` lacks sufficient balance.  \r
    /// @param from   Source address.\r
    /// @param to     Destination address (may be any non-zero address).\r
    /// @param amount Amount of MOON to move (18-decimals).\r
    function _transferExempt(address from, address to, uint256 amount) internal {\r
        require(to != address(0));\r
        require(balances[from] >= amount);\r
\r
        unchecked {\r
            balances[from] -= amount;\r
            balances[to]   += amount;\r
        }\r
\r
        emit Transfer(from, to, amount);\r
    }\r
\r
    /*//////////////////////////////////////////////////////////////////////////\r
                        EXTERNAL ENTRYPOINTS (USER / SELF)\r
    //////////////////////////////////////////////////////////////////////////*/\r
\r
    /// @notice Claims caller’s SUN emissions and opportunistically advances maintenance.\r
    /// @dev If eligible, settles the caller via `_emitRay()`, then attempts one swap-back and\r
    ///      runs the radiation loop before committing updated aggregates. Calling is optional;\r
    ///      emissions accrue automatically.\r
    function collect() external nonReentrant {\r
        // Snapshot caller and their membership record.\r
        Member memory m;\r
        m.self = msg.sender;\r
        (m.pastIndex, m.uncollected, m.class, m.status) = readMember(m.self);\r
\r
        // Snapshot global aggregates (pool/oath/index/active) for this maintenance pass.\r
        (uint128 pool, uint128 oath)  = readPoolOath();\r
        (uint128 index, uint128 active) = readIndexActive();\r
        GlobalMemory memory g = GlobalMemory(pool, oath, index, active);\r
\r
        // If the caller is an eligible SUN holder, try to settle their pending value.\r
        if (m.class == 1) {\r
            Ray memory r;\r
            (g, r) = _emitRay(g, r, m);\r
            if (r.self != address(0)) {\r
                writeRay1(r.self, r.reserve, r.pending, r.swapStatus, r.brightStatus, r.thisZero);\r
            }\r
        }\r
\r
        // Opportunistic maintenance: try one swap-back (skip none) and advance payouts.\r
        g = _swapBack(g, address(0));\r
        g = _radiate(g);\r
        _commitFromG(g);\r
    }\r
\r
    /// @notice Thin wrapper that is nonReentrant and delegates to the internal implementation.\r
    function manuallyReclassify(address addr) external nonReentrant \r
        returns (uint8 moonC, uint8 sunC)\r
    {\r
        return _manuallyReclassify(addr);\r
    }\r
\r
    /// @notice Manually fund a ray with MOON (adds to that ray’s pending and updates value).\r
    /// @dev External wrapper; simply delegates to the internal implementation.\r
    ///      Callable by anyone. Transfer from the caller to this contract is untaxed.\r
    ///      Does not require a Ray with V2 MOON pair initialized. \r
    function manuallyFundRay(address ray, uint256 amount) external nonReentrant {\r
        _manuallyFundRay(ray, amount);\r
    }\r
\r
    /// @notice SUN transfer hook that keeps MOON’s accounting correct.\r
    /// @dev Only callable by `sun`. Respects MOON's reentrancy window. \r
    ///      Delegates full bookkeeping to `_transferSun()` using\r
    ///      pre-transfer balances for fair accrual.\r
    /// @param from    SUN holder sending tokens.\r
    /// @param to      SUN holder receiving tokens.\r
    /// @param fromBal `from` holder’s SUN balance before the transfer (1e18-scaled).\r
    /// @param toBal   `to` holder’s SUN balance before the transfer (1e18-scaled).\r
    /// @param amount  SUN amount moved (1e18-scaled).\r
    function zz__transferSun(\r
        address from,\r
        address to,\r
        uint256 fromBal,\r
        uint256 toBal,\r
        uint256 amount\r
    ) external {\r
        // Restrict caller to the configured SUN contract.\r
        require(msg.sender == sun, "Can only be called by SUN");\r
\r
        // Respect Moon’s reentrancy window.\r
        require(_reentrancyStatus == _UNLOCKED ,"Reentrancy");\r
\r
        _transferSun(from, to, fromBal, toBal, amount);\r
    }\r
\r
    /*//////////////////////////////////////////////////////////////////////////\r
                         TRANSFER ENGINE (MOON TAX LOGIC)\r
    //////////////////////////////////////////////////////////////////////////*/\r
\r
    /// @notice Core MOON transfer routine with pair‑aware taxation.\r
    /// @dev\r
    /// - Applies 3% tax on verified V2 swaps; all other movements are untaxed.\r
    /// - Tax is routed to `this` and attributed to the ray; then one swap‑back\r
    ///   and a radiation step are opportunistically executed.\r
    /// - Sending to `DEAD` performs a hard burn and returns early.\r
    /// @param from   Sender address.\r
    /// @param to     Recipient address (non‑zero).\r
    /// @param amount MOON amount to move.\r
    function _transfer(address from, address to, uint256 amount) internal {\r
        // Basic guards\r
        require(to != address(0), "ERC20: transfer to zero address");\r
        require(balances[from] >= amount, "ERC20: Balance insufficient");\r
\r
        // Burning path (official sink)\r
        if (to == DEAD) {\r
            _burn(from, amount);\r
            return;\r
        }\r
\r
        // Classify: verified‑pair swap (taxed) vs everything else (untaxed)\r
        (bool taxed, Ray memory r) = _transferType(amount, from, to);\r
\r
        if (taxed) {\r
            // Split to recipient and protocol tax\r
            uint256 tax     = (amount * SWAP_TAX) / 1e18;\r
            uint256 postTax = amount - tax;\r
\r
            unchecked {\r
                balances[from]          -= amount;\r
                balances[to]            += postTax;\r
                balances[address(this)] += tax;\r
            }\r
            emit Transfer(from, to, postTax);\r
            emit Transfer(from, address(this), tax);\r
\r
            // Attribute tax to the ray (may enqueue for swap‑back)\r
            _updatePending(r, tax);\r
\r
            // Opportunistic maintenance: one swap‑back (skip current ray) + radiation\r
            (uint128 pool, uint128 oath)  = readPoolOath();\r
            (uint128 index, uint128 active) = readIndexActive();\r
            GlobalMemory memory g = GlobalMemory(pool, oath, index, active);\r
\r
            // Performs system maintenance.\r
            g = _swapBack(g, r.self);\r
            g = _radiate(g);\r
\r
            // Defensive re‑read of active supply, then commit\r
            _commitFromG(g);\r
        } else {\r
            unchecked {\r
                balances[from] -= amount;\r
                balances[to]   += amount;\r
            }\r
            emit Transfer(from, to, amount);\r
        }\r
    }\r
\r
    /// @notice Classifies an address for MOON‑pair semantics (tax scope).\r
    /// @dev\r
    /// - Returns 2 iff `a` is the canonical V2 pair (from `factory`) that\r
    ///   contains MOON; otherwise 1.\r
    /// - On first positive identification, caches ray token + orientation,\r
    ///   wires `pairs[a].ray`, and emits {RayInitialized}.\r
    /// - All probes are gas‑capped; failures degrade to class 1.\r
    /// @param a Address to classify.\r
    /// @return c 2 = verified V2 MOON pair; 1 = regular holder/other.\r
    function _getMoonClass(address a) internal returns (uint8 c) {\r
        // Cached\r
        c = moonClass[a];\r
        if (c != 0) return c;\r
\r
        // EOAs are regular\r
        if (a.code.length == 0) { c = 1; moonClass[a] = c; return c; }\r
\r
        // token0()/token1() probe\r
        (bool ok0, address t0) = _probeToken(a, SEL_TOKEN0, 40000);\r
        if (!ok0) { c = 1; moonClass[a] = c; return c; }\r
        (bool ok1, address t1) = _probeToken(a, SEL_TOKEN1, 40000);\r
        if (!ok1) { c = 1; moonClass[a] = c; return c; }\r
\r
        // Must include MOON\r
        if (t0 != address(this) && t1 != address(this)) {\r
            c = 1; moonClass[a] = c; return c;\r
        }\r
\r
        // Factory confirmation\r
        (, address official) = _probeGetPair(t0, t1, 40000);\r
        if (official != a) { c = 1; moonClass[a] = c; return c; }\r
\r
        // Initialize ray state (pair + orientation)\r
        Ray memory r;\r
        r.pair = a;\r
\r
        if      (t1 == address(this)) { r.self = t0; r.thisZero = false; } // MOON is token1\r
        else if (t0 == address(this)) { r.self = t1; r.thisZero = true;  } // MOON is token0\r
\r
        pairs[r.pair].ray = r.self;\r
        moonClass[a] = 2;\r
\r
        (r.reserve, r.pending, r.swapStatus, r.brightStatus,) = readRay1(r.self);\r
        writeRay0(r.self, a);\r
        writeRay1(r.self, r.reserve, r.pending, r.swapStatus, r.brightStatus, r.thisZero);\r
\r
        emit RayInitialized(r.self);\r
        return 2;\r
    }\r
\r
    /// @notice Distinguishes taxed swaps from untaxed LP mints/burns/off‑pair transfers.\r
    /// @dev\r
    /// - If neither side is a verified MOON pair → untaxed.\r
    /// - If any reserve is zero (bootstrap) → untaxed.\r
    /// - Opposite‑sign deltas in (A,M) or unchanged A → swap (taxed).\r
    /// - Otherwise apply a proportionality window (~±20%); outside → swap,\r
    ///   inside → LP mint/burn (untaxed) with a temporary `swapLock`.\r
    /// Note: for mint or burn to be properly identified, MOON must be sent second.\r
    ///       For burns this happens automatically as long as the other token has a \r
    ///       smaller contract address than MOON. Hence MOON's large address.\r
    /// @param amount MOON amount moved.\r
    /// @param from   Sender.\r
    /// @param to     Recipient.\r
    /// @return taxed True if swap (taxed); false otherwise.\r
    /// @return r     Ray context (pair, token, reserves, orientation).\r
    function _transferType(\r
        uint256 amount,\r
        address from,\r
        address to\r
    )\r
        internal\r
        returns (\r
            bool taxed,\r
            Ray memory r\r
        )\r
    {\r
        if (amount == 0) return (false, r);\r
\r
        uint8 classFrom = _getMoonClass(from);\r
        uint8 classTo   = _getMoonClass(to);\r
\r
        // Neither touches a verified pair ⇒ untaxed\r
        if (!(classFrom == 2 || classTo == 2)) {\r
            return (false, r);\r
        }\r
\r
        // Resolve ray + orientation + reserves\r
        r.pair = (classFrom == 2) ? from : to;\r
        r.self = pairs[r.pair].ray;\r
        (r.reserve, r.pending, r.swapStatus, r.brightStatus, r.thisZero) = readRay1(r.self);\r
\r
        (bool okR, uint112 r0, uint112 r1, /*uint32 ts*/) = _probeReserves(r.pair, 40000);\r
        if (!okR) return (true, r); // Broken pair ⇒ taxed\r
\r
        r.ra = r.thisZero ? _cap112(r1) : _cap112(r0); \r
        r.rm = r.thisZero ? _cap112(r0) : _cap112(r1); \r
\r
        // Reconcile any prior swapLock\r
        uint256 bm = balances[r.pair]; // MOON live balance\r
        if (pairs[r.pair].swapLock) {\r
            // Tax the untaxed MOON in the pair\r
            // While swapLock is true, (bm - rm) amount was falsely untaxed.\r
            if (bm > r.rm){\r
                uint256 tax = (bm - r.rm) * SWAP_TAX / 1e18;\r
                _transferExempt(r.pair, address(this), tax);\r
                _updatePending(r, tax);\r
            }\r
            pairs[r.pair].swapLock = false;\r
        }\r
\r
        // Live A balance\r
        (bool okB, uint256 ba) = _safeBalanceOf(r.self, r.pair); // other‑token live bal\r
        if (!okB) return (true, r); // Broken token ⇒ taxed\r
\r
        // Adjust MOON balance directionally after this transfer\r
        if      (to   == r.pair) bm = _satAdd(bm, amount); // M→A swap or mint\r
        else if (from == r.pair) bm = _satSub(bm, amount); // A→M swap or burn\r
\r
        // Bootstrap guard\r
        if (r.ra == 0 || r.rm == 0) return (false, r);\r
\r
        // Sign test (opposite signs ⇒ swap); unchanged A ⇒ swap\r
        if (!_sameSign(ba, r.ra, bm, r.rm) || ba == r.ra) {\r
            return (true, r);\r
        }\r
\r
        // Proportionality (~±20%) — outside window ⇒ swap\r
        uint256 da = ba > r.ra ? ba - r.ra : r.ra - ba; // Difference between ba and ra\r
        uint256 dm = bm > r.rm ? bm - r.rm : r.rm - bm; // Difference between bm and rm\r
        unchecked {\r
            // Cross terms for the ratio comparison: da/dm = r.ra/r.rm  ⇔  da*r.rm = dm*r.ra\r
            uint256 a = da * r.rm;\r
            uint256 b = dm * r.ra;\r
\r
            // Scale once and compare to 6/5 (1.2) and 4/5 (0.8) bounds.\r
            uint256 a5 = a * 5;\r
\r
            // Out of bounds if a/b > 1.2  or  a/b < 0.8\r
            if (a5 > b * 6 || a5 < b * 4) return (true, r);\r
        }\r
\r
        // Inside window ⇒ LP mint/burn (untaxed); engage lock until completion\r
        pairs[r.pair].swapLock = true;\r
    }\r
\r
    /// @notice Accrues MOON tax to a ray and enqueues it for swap‑back when thresholded.\r
    /// @dev\r
    /// - `pending` saturates to uint112.\r
    /// - Enqueues once when `pending ≥ MIN_SWAP_BACK`.\r
    /// - If the ray is SUN, burn the tax immediately (do not queue).\r
    /// @param tax Newly collected MOON.\r
    function _updatePending(Ray memory r, uint256 tax) internal {\r
        if (r.self == sun) {_burn(address(this), tax); return;}\r
        r.pending = _cap112(r.pending + tax);\r
        if (r.pending >= MIN_SWAP_BACK && r.swapStatus == 0) {\r
            swapQueue.push(r.self);\r
            r.swapStatus = 2; // in list\r
        }\r
        writeRay1(r.self, r.reserve, r.pending, r.swapStatus, r.brightStatus, r.thisZero);\r
    }\r
\r
    /// @notice Read‑only guard used by `balanceOf` to enforce swap‑lock semantics.\r
    /// @dev\r
    /// - While `swapLock` is set, verifies that the (balance - reserve) are the same\r
    ///   sign for each token. If not, returns false (caller should `skim`).\r
    /// - Returns true when unlocked or probes fail (fail‑open).\r
    /// Note: SwapLock is only enabled when transferType identifies an LP action (Mint/Burn)\r
    ///       This function ensures that the action is really an LP action and not a swap.\r
    ///       This function should never return false outside of a malicious swap.\r
    /// @param pair The pair address to check.\r
    /// @return Whether the pair is safe/unlocked for balance queries.\r
    function _unlocked(address pair) internal view returns (bool){\r
        bool swapLock = pairs[pair].swapLock;\r
        if (!swapLock) return true;\r
\r
        Ray memory r;\r
        r.pair = pair;\r
        r.self = pairs[r.pair].ray;\r
        (r.reserve, r.pending, r.swapStatus, r.brightStatus, r.thisZero) = readRay1(r.self);\r
\r
        // Stored reserves\r
        (bool okR, uint112 r0, uint112 r1, /*uint32 ts*/) = _probeReserves(pair, 40000);\r
        if (!okR) return true;\r
\r
        // Map to (A,M)\r
        r.ra = r.thisZero ? _cap112(r1) : _cap112(r0);\r
        r.rm = r.thisZero ? _cap112(r0) : _cap112(r1);\r
\r
        // Live balances\r
        uint256 bm = balances[pair];\r
        (bool ok, uint256 ba) = _safeBalanceOf(r.self, pair);\r
        if (!ok) return true;\r
\r
        // If signs still match, it's safe; otherwise block\r
        if (_sameSign(ba, r.ra, bm, r.rm)) return true;\r
        return false;\r
    }\r
\r
\r
    /*//////////////////////////////////////////////////////////////////////////\r
                              SWAPBACK (QUEUE & SWAP)\r
    //////////////////////////////////////////////////////////////////////////*/\r
\r
    /// @notice Attempts at most one swap-back from the queue, then revalues the ray.\r
    /// @dev\r
    /// - Picks a ray pseudo-randomly, pruning small/invalid entries on the way.\r
    /// - Reads reserves, computes a safe `amountIn` (appreciation-coverage guard\r
    ///   + small impact guard), and performs a bounded self-call swap.\r
    /// - On success: decrements `pending`, re-probes reserves, revalues the ray,\r
    ///   and updates global aggregates.\r
    /// - On failure: removes the ray from the queue and returns.\r
    /// @param skipRay Optional ray to avoid (the ray in the user’s current taxed swap).\r
    function _swapBack(GlobalMemory memory g, address skipRay)\r
        internal\r
        returns (GlobalMemory memory)\r
    {\r
        // Early exit if nothing to do\r
        uint256 len = swapQueue.length;\r
        if (len == 0) return g;\r
\r
        // Pseudo-random starting point.\r
        uint256 cursor = block.prevrandao + activeMembersCursor;\r
\r
        Ray memory r;\r
        bool found;\r
\r
        // Candidate selection + lazy pruning (bounded attempts)\r
        for (uint256 attempts = 0; attempts < 6; ++attempts) {\r
            len = swapQueue.length;\r
            if (len == 0) return g;\r
            cursor = (cursor + 1) % len;\r
\r
            r.self = swapQueue[cursor];\r
\r
            // Skip the ray currently used by the calling swap\r
            if (r.self == skipRay) {\r
                if (len == 1) return g;\r
                continue;\r
            }\r
\r
            // Load packed ray fields\r
            (r.reserve, r.pending, r.swapStatus, r.brightStatus, r.thisZero) = readRay1(r.self);\r
\r
            // Cull entries below threshold\r
            if (r.pending < MIN_SWAP_BACK) {\r
                _removeFromList(swapQueue, cursor);\r
                writeRay1(r.self, r.reserve, r.pending, 0, r.brightStatus, r.thisZero);\r
\r
                // If queue emptied, we’re done; otherwise continue with element swapped into `cursor`\r
                len = swapQueue.length;\r
                if (len == 0) return g;\r
                continue;\r
            }\r
\r
            // Resolve pair and cached quotes for downstream logic\r
            (r.quote, r.candidateQuote, r.updateBlock) = readRay2(r.self);\r
            r.pair = readRay0(r.self);\r
\r
            found = true;\r
            break;\r
        }\r
        if (!found) return g;\r
\r
        // Probe reserves (drop from queue if probe fails or 0 reserves)\r
        (bool okR, uint112 r0, uint112 r1, /*uint32 ts*/) = _probeReserves(r.pair, 40000);\r
        if (!okR || r0 == 0 || r1 == 0) {\r
            _removeFromList(swapQueue, cursor);\r
            writeRay1(r.self, r.reserve, r.pending, 0, r.brightStatus, r.thisZero);\r
            return g;\r
        }\r
        r.ra = r.thisZero ? r1 : r0;  // other token reserve\r
        r.rm = r.thisZero ? r0 : r1;  // MOON reserve\r
\r
        //  A) Leave enough pending to cover appreciation tax after the swap\r
        uint256 maxInAppreciation = _maxInForAppreciation(r);\r
        //  B) Keep price impact no greater than SWAP_TAX\r
        uint256 maxInFee = (r.rm * SWAP_TAX) / 1e18;\r
\r
        // Combine guards and clamp to availability\r
        uint256 maxIn    = maxInAppreciation <= maxInFee ? maxInAppreciation : maxInFee;\r
        uint256 amountIn = r.pending <= maxIn ? r.pending : maxIn;\r
\r
        // Too small → drop from queue and update new price\r
        if (amountIn < MIN_SWAP_BACK) {\r
            _removeFromList(swapQueue, cursor);\r
            r.swapStatus = 0;\r
            g = _updateValue(g, r);\r
            return g;\r
        }\r
\r
        // Execute swap via bounded self-call\r
        bytes memory swapCalldata = abi.encodeWithSelector(\r
            this.zz__swapWithPair.selector,\r
            r.pair,\r
            r.thisZero,\r
            amountIn,\r
            r.rm,\r
            r.ra\r
        );\r
\r
        (bool ok, ) = address(this).call{gas: SWAPBACK_CALL_GAS}(swapCalldata);\r
\r
        if (ok) {\r
            // Swap succeeded — shrink pending and optionally dequeue\r
            r.pending = r.pending - uint112(amountIn);\r
            if (r.pending < MIN_SWAP_BACK && r.swapStatus == 2) {\r
                _removeFromList(swapQueue, cursor);\r
                r.swapStatus = 0;\r
            }\r
\r
            // Re-probe reserves (best effort)\r
            (okR, r0, r1, /*uint32 ts*/) = _probeReserves(r.pair, 40000);\r
            if (okR) {\r
                r.ra = r.thisZero ? r1 : r0;\r
                r.rm = r.thisZero ? r0 : r1;\r
            } // If probe fails, use old reserves\r
\r
            // Revalue and update global aggregates\r
            g = _updateValue(g, r);\r
            return g;\r
\r
        } else {\r
            // Swap failed — remove from queue\r
            _removeFromList(swapQueue, cursor);\r
            writeRay1(r.self, r.reserve, r.pending, 0, r.brightStatus, r.thisZero);\r
            return g;\r
        }\r
    }\r
\r
    \r
    /// @notice Computes the max MOON-in that keeps pending sufficient to pay appreciation tax post-swap.\r
    /// @dev\r
    /// Goal:\r
    /// - Choose `x ≤ r.pending` so that after swapping `x`, the remaining `pending` can still\r
    ///   cover the appreciation tax that would be owed if the ray’s MOON‑denominated value\r
    ///   increases using the *post‑swap* reserves and quote.\r
    /// Notes:\r
    /// - Considers pair fee, pair bonus (portion left in the pool), and any uncredited tokens\r
    ///   already in the Vault for this ray.\r
    /// - Uses saturating math and defensive guards; never reverts. Returns a ceil’d `x`.\r
    /// @param r Ray snapshot (expects `rm`, `ra`, `reserve`, `quote`, `pending`, `self`).\r
    /// @return x Max MOON-in to swap now while preserving coverage.\r
    function _maxInForAppreciation(Ray memory r) internal view returns (uint256 x) {\r
        // Unpack & early guards\r
        uint256 P = r.pending;\r
        if (P == 0) return 0;\r
\r
        uint256 M = r.rm;\r
        uint256 A = r.ra;\r
        if (M == 0 || A == 0) return 0;\r
\r
        // Live Vault balance of token (uncredited portion considered as part of new value)\r
        (, uint256 B) = _safeBalanceOf(r.self, vault);\r
\r
        // Shorthands (locals are cheap; immutables/consts already are)\r
        uint256 WAD = 1e18;\r
        uint256 D   = FEE_DENOMINATOR;  // 10_000\r
        uint256 F   = feeMul;           // ≤ 10_000\r
        uint256 K   = APPRECIATION_TAX; // 0.20e18\r
\r
        // Pair bonus and complement\r
        uint256 bBonusW = PAIR_BONUS;          // 0.25e18\r
        uint256 gammaW  = WAD - bBonusW;       // compile-time fold; safe\r
\r
        // Pending scaling vs reserves, prior credited value in MOON terms\r
        // pW = ceil(P * WAD / M) — safe to compute directly (P*WAD < 2^256)\r
        uint256 pW;\r
        unchecked { pW = (P * WAD + (M - 1)) / M; }\r
\r
        uint256 vq      = _mulDivDown(r.reserve, r.quote, 1e38);\r
        uint256 kBetaUp = _mulDivUp(K, vq, M);\r
\r
        // Constant term with up-bias (unsigned sign+magnitude)\r
        uint256 lhs   = _mulDivDown(K, B, A);       // cache: used twice\r
        uint256 rhs   = _satAdd(kBetaUp, pW);\r
        bool    negC  = lhs < rhs;\r
        uint256 absC  = negC ? (rhs - lhs) : (lhs - rhs);\r
\r
        // Helper pieces for coefficients\r
        uint256 FBoverA = _mulDivDown(F, B, A);\r
        // Fgamma = floor(F * gammaW / WAD) — safe (F*gammaW < 2^256)\r
        uint256 Fgamma;\r
        unchecked { Fgamma = (F * gammaW) / WAD; }\r
\r
        uint256 FBplus = _satAdd(FBoverA, Fgamma);\r
\r
        // Quadratic/linear coefficients (WAD units, up-biased)\r
        // aW = floor(bBonusW * F / D) — safe (product < 2^256)\r
        uint256 aW = (bBonusW * F) / D;\r
        // KFoverD cached once; may saturate inside _mulDivDown (that’s fine)\r
        uint256 KFoverD = _mulDivDown(K, FBplus, D);\r
        aW = _satAdd(aW, KFoverD);\r
\r
        uint256 bWpos = _satAdd(WAD, lhs);        // lhs was floor(K*B/A)\r
        bWpos         = _satAdd(bWpos, KFoverD);  // reuse\r
\r
        uint256 sTot  = _satAdd(pW, kBetaUp);\r
\r
        // neg = ceil( ceil(sTot * bBonusW / WAD) * F / D )\r
        uint256 tmp   = _mulDivUp(sTot, bBonusW, WAD);\r
        uint256 neg   = _mulDivUp(tmp, F, D);\r
\r
        uint256 bW = (neg >= bWpos) ? 0 : (bWpos - neg);\r
\r
        // Solve for t (normalized by WAD), using ceil where needed to preserve up-bias\r
        uint256 tW = 0;\r
\r
        if (aW == 0) {\r
            if (negC) {\r
                tW = _mulDivUp(absC, WAD, bW); // may saturate if bW==0 → OK (clamped later)\r
            }\r
        } else {\r
            bool safe_b2   = (bW == 0) || (bW <= type(uint256).max / bW);\r
            bool safe_a4   = (aW <= type(uint256).max / 4);\r
            bool safe_four = safe_a4 && (absC == 0 || ((aW << 2) <= type(uint256).max / absC));\r
            bool safe_den  = (aW <= type(uint256).max / 2);\r
\r
            if (safe_b2 && safe_four && safe_den) {\r
                uint256 b2;           unchecked { b2 = bW * bW; }\r
                uint256 four_a_abs_c; unchecked { four_a_abs_c = (aW << 2) * absC; }\r
\r
                uint256 disc;\r
                if (!negC) {\r
                    disc = (b2 >= four_a_abs_c) ? (b2 - four_a_abs_c) : 0;\r
                } else {\r
                    disc = (type(uint256).max - b2 < four_a_abs_c) ? type(uint256).max : (b2 + four_a_abs_c);\r
                }\r
\r
                uint256 s = _isqrt(disc);\r
\r
                if (s > bW) {\r
                    uint256 num; unchecked { num = s - bW; }\r
                    uint256 den; unchecked { den = aW << 1; }\r
                    tW = _mulDivUp(num, WAD, den);\r
                }\r
            } else {\r
                if (negC) {\r
                    tW = _mulDivUp(absC, WAD, bW);\r
                }\r
            }\r
        }\r
\r
        // Convert normalized t to MOON-in, ceil, and clamp to pending\r
        x = _mulDivUp(tW, M, WAD);\r
        if (x > P) x = P;\r
    }\r
\r
\r
\r
    /// @notice Internal router for MOON→token swaps on a verified V2 pair (self-call only).\r
    /// @dev\r
    /// - Transfers `amountIn` MOON into the pair, recomputes the *actual* input,\r
    ///   applies factory fee and the pair bonus, and routes output directly to the Vault.\r
    /// - Reverts on zero output to avoid no-op swaps.\r
    /// - Orientation-aware: if MOON is token0, outputs token1; otherwise token0.\r
    /// @param pair       V2 pair to swap against.\r
    /// @param thisZero   True if MOON is token0 in the pair.\r
    /// @param amountIn   Intended MOON input (ledger transfer).\r
    /// @param reserveIn  Pre-swap MOON reserve (orientation-correct).\r
    /// @param reserveOut Pre-swap other-token reserve (orientation-correct).\r
    function zz__swapWithPair(\r
        address pair,\r
        bool    thisZero,\r
        uint256 amountIn,\r
        uint256 reserveIn,\r
        uint256 reserveOut\r
    ) external {\r
        // Self-call only\r
        require(msg.sender == address(this), "Moon: self-call only");\r
\r
        // Disable swapLock\r
        if (pairs[pair].swapLock) {\r
            pairs[pair].swapLock = false;\r
        }\r
\r
        // Router-style ledger move: push MOON to the pair\r
        _transferExempt(address(this), pair, amountIn);\r
\r
        // Compute the actual input observed by the pair\r
        uint256 realIn = _satSub(balances[pair], reserveIn);\r
\r
        // V2 x*y=k with factory fee\r
        uint256 inWithFee   = realIn * uint256(feeMul);\r
        uint256 numerator   = inWithFee * reserveOut;\r
        uint256 denominator = reserveIn * FEE_DENOMINATOR + inWithFee;\r
        uint256 amountOut   = (denominator == 0) ? 0 : (numerator / denominator);\r
\r
        // Apply pair bonus (leave a fraction in the pool)\r
        amountOut = amountOut * (1e18 - PAIR_BONUS) / 1e18;\r
        require(amountOut != 0);\r
\r
        // Execute the swap; send proceeds to the Vault\r
        if (thisZero) {\r
            IUniswapV2Pair(pair).swap(0, amountOut, vault, new bytes(0));\r
        } else {\r
            IUniswapV2Pair(pair).swap(amountOut, 0, vault, new bytes(0));\r
        }\r
    }\r
\r
    /*//////////////////////////////////////////////////////////////////////////\r
                            LIGHT ENGINE (RADIATE/EMIT)\r
    //////////////////////////////////////////////////////////////////////////*/\r
\r
    /// @notice Processes active SUN members within a fixed gas stipend and advances payouts.\r
    /// @dev\r
    /// - Round‑robin over `activeMembers` from `activeMembersCursor`.\r
    /// - Removes stale entries (no longer active)\r
    /// - Calls {_emitRay} for active entries, then persists the new cursor.\r
    function _radiate(GlobalMemory memory g)\r
        internal\r
        returns (GlobalMemory memory)\r
    {\r
        // Open gas window and snapshot cursor (monotonic measure: start - gasleft() increases)\r
        uint256 start = gasleft();\r
        uint256 i = activeMembersCursor;\r
\r
        Ray memory r;\r
        Member memory m;\r
\r
        // Iterate while we have gas budget\r
        while (start - gasleft() < RADIATE_GAS_LIMIT) {\r
            uint256 lenNow = activeMembers.length;\r
            if (lenNow == 0) break;             // nothing to do\r
            if (i >= lenNow) i = 0;             // wrap if list shrank\r
\r
            // Load member snapshot\r
            m.self = activeMembers[i];\r
            (m.pastIndex, m.uncollected, m.class, m.status) = readMember(m.self);\r
\r
            if (m.status != 2) {\r
                // Remove from rotation (swap‑and‑pop); do not advance i (new element s

Tags:
ERC20, Multisig, Burnable, Swap, Liquidity, Yield, Upgradeable, Multi-Signature, Factory|addr:0xfffffd0a212b949d1d2bfac79ecbce9c9f11ffff|verified:true|block:23686928|tx:0xb8cb20d161285817233239ef02e54c03d621e03c540ec76f719850ea23f461a4|first_check:1761823468

Submitted on: 2025-10-30 12:24:30

Comments

Log in to comment.

No comments yet.