// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.30; /// @notice AN01-F01 development contract. Publishes commitments, not consent. contract ASCheckpointAnchor { error UnauthorizedPublisher(); error UnauthorizedGuardian(); error Halted(); error InvalidSequence(); error ConflictingCheckpoint(); error InvalidCommitment(); event ASCheckpointAnchored( bytes32 indexed identityCommitment, uint64 indexed sequence, bytes32 indexed checkpointCommitment, bytes32 previousCheckpointCommitment, bytes32 asGenesisCommitment, bytes32 anchorId, address publisher ); event ASHalted(address indexed guardian); bytes32 public immutable asGenesisCommitment; bytes32 public immutable anchorIntentCommitment; bytes32 public immutable identityCommitment; address public immutable publisher; address public immutable guardian; bool public halted; struct Checkpoint { bytes32 commitment; bytes32 previous; bytes32 anchorId; } mapping(uint64 => Checkpoint) private checkpoints; uint64 private headSequence; bytes32 private headCommitment; constructor(bytes32 asGenesisCommitment_, bytes32 anchorIntentCommitment_, bytes32 identityCommitment_, address publisher_, address guardian_) { if (asGenesisCommitment_ == bytes32(0) || anchorIntentCommitment_ == bytes32(0) || identityCommitment_ == bytes32(0) || publisher_ == address(0) || guardian_ == address(0) || publisher_ == guardian_) revert InvalidCommitment(); asGenesisCommitment = asGenesisCommitment_; anchorIntentCommitment = anchorIntentCommitment_; identityCommitment = identityCommitment_; publisher = publisher_; guardian = guardian_; } function head() external view returns (uint64 sequence, bytes32 checkpointCommitment) { return (headSequence, headCommitment); } function checkpointAt(uint64 sequence) external view returns ( bytes32 checkpointCommitment, bytes32 previousCheckpointCommitment, bytes32 anchorId ) { Checkpoint storage c = checkpoints[sequence]; return (c.commitment, c.previous, c.anchorId); } function anchor(uint64 sequence, bytes32 checkpointCommitment, bytes32 previousCheckpointCommitment) external returns (bytes32 anchorId) { if (msg.sender != publisher) revert UnauthorizedPublisher(); if (halted) revert Halted(); if (sequence == 0 || sequence > 9007199254740991) revert InvalidSequence(); if (checkpointCommitment == bytes32(0)) revert InvalidCommitment(); if (sequence <= headSequence) { Checkpoint storage saved = checkpoints[sequence]; if (saved.commitment != checkpointCommitment || saved.previous != previousCheckpointCommitment) revert ConflictingCheckpoint(); return saved.anchorId; } if (sequence != headSequence + 1 || previousCheckpointCommitment != headCommitment) revert InvalidSequence(); anchorId = keccak256(abi.encode( keccak256("XCIM_AS01_EVM_ANCHOR_V1"), block.chainid, address(this), anchorIntentCommitment, identityCommitment, asGenesisCommitment, sequence, checkpointCommitment, previousCheckpointCommitment )); checkpoints[sequence] = Checkpoint(checkpointCommitment, previousCheckpointCommitment, anchorId); headSequence = sequence; headCommitment = checkpointCommitment; emit ASCheckpointAnchored(identityCommitment, sequence, checkpointCommitment, previousCheckpointCommitment, asGenesisCommitment, anchorId, publisher); } function halt() external { if (msg.sender != guardian) revert UnauthorizedGuardian(); if (!halted) { halted = true; emit ASHalted(guardian); } } }