// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; /** * @title ReserveAttestationOracle * @notice Production-Grade Proof of Reserve (PoR) Attestation Oracle * @dev Enforces multi-attestor thresholding, hard expiration (staleness cutoff), * multi-chain liability netting, and mandatory risk buffering before any stablecoin minting. */ interface IReserveAttestationOracle { function verifyMintFeasibility(uint256 currentSupply, uint256 mintAmount) external view returns (bool, uint256); function isAttestationFresh() external view returns (bool); function getLatestAttestation() external view returns ( uint256 attestedReservesUsd, uint256 attestedLiabilitiesUsd, uint256 attestationTimestamp, uint256 validUntil, bytes32 attestationHash, bool isPaused ); } contract ReserveAttestationOracle is IReserveAttestationOracle { string public constant name = "UnyKorn Institutional Reserve Attestation Oracle"; // Governance & Security Roles address public governanceMultisig; address public emergencyPauser; // Attestor Threshold Set (Independent CPAs, Qualified Custodians) mapping(address => bool) public isAuthorizedAttestor; address[] public attestors; uint256 public signatureThreshold; // e.g. 2 of 3 required // Core Attestation State uint256 public attestedReservesUsd; // 6 decimals (USDC/USD normalized) uint256 public attestedLiabilitiesUsd; // Global cross-chain liabilities uint256 public attestationTimestamp; uint256 public validUntil; // Hard expiration (Max 24 hours) bytes32 public attestationHash; // Merkle/SHA-256 evidence package // Risk Management Parameters uint256 public riskBufferBps; // e.g. 500 = 5.00% safety buffer uint256 public constant MAX_STALENESS = 24 hours; bool public emergencyPaused; // Nonce tracking for attestation reports uint256 public attestationNonce; // Events event AttestationUpdated( uint256 indexed nonce, uint256 reservesUsd, uint256 liabilitiesUsd, uint256 validUntil, bytes32 attestationHash ); event EmergencyPauseToggled(bool isPaused); event RiskBufferUpdated(uint256 newBufferBps); event AttestorConfigured(address indexed attestor, bool active); modifier onlyGovernance() { require(msg.sender == governanceMultisig, "Oracle: caller is not governance multisig"); _; } modifier whenNotEmergencyPaused() { require(!emergencyPaused, "Oracle: emergency paused"); _; } constructor( address _governanceMultisig, address _emergencyPauser, address[] memory _initialAttestors, uint256 _threshold, uint256 _riskBufferBps ) { require(_governanceMultisig != address(0), "Zero governance"); require(_initialAttestors.length >= _threshold && _threshold > 0, "Invalid threshold"); governanceMultisig = _governanceMultisig; emergencyPauser = _emergencyPauser; signatureThreshold = _threshold; riskBufferBps = _riskBufferBps; for (uint256 i = 0; i < _initialAttestors.length; i++) { address att = _initialAttestors[i]; require(att != address(0), "Zero attestor"); isAuthorizedAttestor[att] = true; attestors.push(att); emit AttestorConfigured(att, true); } } /** * @notice Publishes an independently verified reserve attestation with threshold signatures * @param _reservesUsd Verified liquid & eligible collateral (6 decimals) * @param _liabilitiesUsd Total liabilities across all chains * @param _validUntil Exact expiration unix timestamp signed by attestors (Max 24h in future) * @param _evidenceHash SHA-256/Merkle hash of audit evidence dossier * @param _signatures Packed 65-byte signatures from authorized attestors */ function publishAttestation( uint256 _reservesUsd, uint256 _liabilitiesUsd, uint256 _validUntil, bytes32 _evidenceHash, bytes[] calldata _signatures ) external whenNotEmergencyPaused { require(_validUntil > block.timestamp, "Attestation already expired"); require(_validUntil <= block.timestamp + MAX_STALENESS, "Validity exceeds max 24h window"); require(_signatures.length >= signatureThreshold, "Insufficient signatures for threshold"); // Construct attestation digest bytes32 digest = keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n32", keccak256( abi.encode( block.chainid, address(this), attestationNonce + 1, _reservesUsd, _liabilitiesUsd, _evidenceHash, _validUntil ) ) ) ); // Verify unique signatures from authorized attestor set address lastSigner = address(0); for (uint256 i = 0; i < signatureThreshold; i++) { address signer = recoverSigner(digest, _signatures[i]); require(isAuthorizedAttestor[signer], "Signer not authorized attestor"); require(signer > lastSigner, "Duplicate or unsorted signatures"); lastSigner = signer; } attestationNonce++; attestedReservesUsd = _reservesUsd; attestedLiabilitiesUsd = _liabilitiesUsd; attestationTimestamp = block.timestamp; validUntil = _validUntil; attestationHash = _evidenceHash; emit AttestationUpdated( attestationNonce, _reservesUsd, _liabilitiesUsd, validUntil, _evidenceHash ); } /** * @notice Validates whether a proposed mint operation is mathematically and temporally eligible * @dev Enforces: * 1. Non-emergency paused * 2. Fresh attestation (not expired / stale) * 3. currentSupply + mintAmount <= (reserves - liabilities - riskBuffer) */ function verifyMintFeasibility(uint256 currentSupply, uint256 mintAmount) external view override returns (bool isApproved, uint256 maxPermittedSupply) { if (emergencyPaused) return (false, 0); if (block.timestamp > validUntil || validUntil == 0) return (false, 0); if (attestedReservesUsd <= attestedLiabilitiesUsd) return (false, 0); uint256 netEligible = attestedReservesUsd - attestedLiabilitiesUsd; uint256 requiredBuffer = (attestedReservesUsd * riskBufferBps) / 10000; if (netEligible <= requiredBuffer) return (false, 0); maxPermittedSupply = netEligible - requiredBuffer; if (currentSupply + mintAmount <= maxPermittedSupply) { return (true, maxPermittedSupply); } else { return (false, maxPermittedSupply); } } function isAttestationFresh() external view override returns (bool) { return (!emergencyPaused && block.timestamp <= validUntil && validUntil > 0); } function getLatestAttestation() external view override returns ( uint256, uint256, uint256, uint256, bytes32, bool ) { return ( attestedReservesUsd, attestedLiabilitiesUsd, attestationTimestamp, validUntil, attestationHash, emergencyPaused ); } function setEmergencyPause(bool _paused) external { require(msg.sender == emergencyPauser || msg.sender == governanceMultisig, "Unauthorized pauser"); emergencyPaused = _paused; emit EmergencyPauseToggled(_paused); } function setRiskBuffer(uint256 _newBufferBps) external onlyGovernance { require(_newBufferBps <= 2000, "Buffer cannot exceed 20%"); riskBufferBps = _newBufferBps; emit RiskBufferUpdated(_newBufferBps); } function recoverSigner(bytes32 _digest, bytes memory _sig) internal pure returns (address) { require(_sig.length == 65, "Malformed signature length"); bytes32 r; bytes32 s; uint8 v; assembly { r := mload(add(_sig, 32)) s := mload(add(_sig, 64)) v := byte(0, mload(add(_sig, 96))) } if (v < 27) v += 27; return ecrecover(_digest, v, r, s); } }