// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @title MonetaryFormulas * @notice Classical + GRU monetary formulas (canonical library — promoted from archive). * @dev Formulas MUST match vault COMPLIANCE_REQUIREMENTS.md and GRU_Formulas.md crosswalk. * * Classical: * - M = C + D; M = MB × m * - V = PQ / M * - m = 1 / r; m = (1 + c) / (r + c) * * GRU layer fan-out (policy): 1 M00 = 5 M0 = 25 M1 face units */ library MonetaryFormulas { uint256 internal constant BP = 10_000; uint256 internal constant WAD = 1e18; /// @notice M = C + D function moneySupplyCD(uint256 currency, uint256 deposits) internal pure returns (uint256) { return currency + deposits; } /// @notice M = MB × m (m in 18 decimals) function moneySupplyFromBase(uint256 monetaryBase, uint256 moneyMultiplierWad) internal pure returns (uint256) { return (monetaryBase * moneyMultiplierWad) / WAD; } /// @notice V = PQ / M function velocityPQOverM(uint256 priceLevel, uint256 quantity, uint256 moneySupply) internal pure returns (uint256) { if (moneySupply == 0) return 0; return (priceLevel * quantity) / moneySupply; } /// @notice m = 1 / r (r in basis points) function simpleMultiplier(uint256 reserveRatioBps) internal pure returns (uint256) { require(reserveRatioBps > 0 && reserveRatioBps <= BP, "MonetaryFormulas: r"); return (WAD * BP) / reserveRatioBps; } /// @notice m = (1 + c) / (r + c) function multiplierWithCurrency(uint256 reserveRatioBps, uint256 currencyRatioBps) internal pure returns (uint256) { require(reserveRatioBps > 0 && reserveRatioBps <= BP, "MonetaryFormulas: r"); require(currencyRatioBps <= BP, "MonetaryFormulas: c"); uint256 num = WAD * (BP + currencyRatioBps); uint256 den = reserveRatioBps + currencyRatioBps; require(den > 0, "MonetaryFormulas: den"); return num / den; } /// @notice Coverage ratio in bps: reserveValue / circulatingValue function coverageRatioBps(uint256 reserveValue, uint256 circulatingValue) internal pure returns (uint256) { if (circulatingValue == 0) return type(uint256).max; return (reserveValue * BP) / circulatingValue; } /// @notice Effective GRU layer multiplier M00→M1 (25 face units per M00) function gruM00ToM1Fanout() internal pure returns (uint256) { return 25; } /// @notice 7:10 atomic issuance factor as WAD (10/7) function gruAtomicIssuanceFactorWad() internal pure returns (uint256) { return (10 * WAD) / 7; } /// @notice v_cov = v_adj × (coverageBps / 12000) function coverageWeightedVelocity(uint256 vAdjWad, uint256 coverageBps) internal pure returns (uint256) { return (vAdjWad * coverageBps) / 12_000; } }