// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @title CurrencyValidation * @notice Library for validating currency codes and types according to ISO 4217 compliance * @dev Ensures all currency references are either ISO 4217 compliant or explicitly identified as non-ISO */ library CurrencyValidation { /** * @notice Currency type enumeration */ enum CurrencyType { ISO4217_FIAT, // Standard ISO 4217 fiat currency (USD, EUR, etc.) ISO4217_CRYPTO, // ISO 4217 cryptocurrency code (if applicable) NON_ISO_SYNTHETIC, // Non-ISO synthetic unit of account (e.g., GRU) NON_ISO_INTERNAL, // Non-ISO internal accounting unit COMMODITY // Commodity code (XAU, XAG, etc.) } /** * @notice Validate ISO 4217 currency code format * @dev ISO 4217 codes are exactly 3 uppercase letters * @param code Currency code to validate * @return isValid True if code matches ISO 4217 format */ function isValidISO4217Format(string memory code) internal pure returns (bool isValid) { bytes memory codeBytes = bytes(code); if (codeBytes.length != 3) { return false; } for (uint256 i = 0; i < 3; i++) { uint8 char = uint8(codeBytes[i]); if (char < 65 || char > 90) { // Not A-Z return false; } } return true; } /** * @notice Check if currency code is a recognized ISO 4217 code * @dev This is a simplified check - in production, maintain a full registry * @param code Currency code * @return isISO4217 True if code is recognized ISO 4217 */ function isISO4217Currency(string memory code) internal pure returns (bool isISO4217) { if (!isValidISO4217Format(code)) { return false; } // Common ISO 4217 codes (extend as needed) bytes32 codeHash = keccak256(bytes(code)); // Major currencies if (codeHash == keccak256("USD") || // US Dollar codeHash == keccak256("EUR") || // Euro codeHash == keccak256("GBP") || // British Pound codeHash == keccak256("JPY") || // Japanese Yen codeHash == keccak256("CNY") || // Chinese Yuan codeHash == keccak256("CHF") || // Swiss Franc codeHash == keccak256("CAD") || // Canadian Dollar codeHash == keccak256("AUD") || // Australian Dollar codeHash == keccak256("NZD") || // New Zealand Dollar codeHash == keccak256("SGD")) { // Singapore Dollar return true; } // In production, maintain a full registry or use oracle/external validation return false; } /** * @notice Check if code is GRU (Global Reserve Unit) * @dev GRU is a non-ISO 4217 synthetic unit of account * @param code Currency code * @return isGRU True if code is GRU */ function isGRU(string memory code) internal pure returns (bool isGRU) { bytes32 codeHash = keccak256(bytes(code)); return codeHash == keccak256("GRU") || codeHash == keccak256("M00") || codeHash == keccak256("M0") || codeHash == keccak256("M1"); } /** * @notice Check if code is XAU (Gold) * @dev XAU is the ISO 4217 commodity code for gold * @param code Currency code * @return isXAU True if code is XAU */ function isXAU(string memory code) internal pure returns (bool isXAU) { return keccak256(bytes(code)) == keccak256("XAU"); } /** * @notice Get currency type * @param code Currency code * @return currencyType Type of currency */ function getCurrencyType(string memory code) internal pure returns (CurrencyType currencyType) { if (isXAU(code)) { return CurrencyType.COMMODITY; } if (isGRU(code)) { return CurrencyType.NON_ISO_SYNTHETIC; } if (isISO4217Currency(code)) { return CurrencyType.ISO4217_FIAT; } // If format is valid but not recognized, treat as potentially valid ISO 4217 if (isValidISO4217Format(code)) { return CurrencyType.ISO4217_FIAT; // Assume valid but not in our list } return CurrencyType.NON_ISO_INTERNAL; } /** * @notice Validate that currency is legal tender (ISO 4217 fiat) * @param code Currency code * @return isLegalTender True if currency is ISO 4217 legal tender */ function isLegalTender(string memory code) internal pure returns (bool isLegalTender) { CurrencyType currencyType = getCurrencyType(code); return currencyType == CurrencyType.ISO4217_FIAT; } /** * @notice Require currency to be legal tender or revert * @param code Currency code */ function requireLegalTender(string memory code) internal pure { require(isLegalTender(code), "CurrencyValidation: not legal tender - must be ISO 4217"); } /** * @notice Require currency to NOT be legal tender (for synthetic units) * @param code Currency code */ function requireNonLegalTender(string memory code) internal pure { require(!isLegalTender(code), "CurrencyValidation: must be non-legal tender"); } }