pragma solidity ^0.8.13; contract AckAttestation { mapping(address => uint256) private _nonces; event Attested(bytes32 indexed payloadHash, address indexed signer, uint256 blockNumber, uint256 nonce); function attest( bytes32 payloadHash, uint256 nonce, uint8 v, bytes32 r, bytes32 s ) external returns (address signer) { require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0); bytes32 digest = keccak256(abi.encodePacked(payloadHash, nonce, block.chainid, address(this))); signer = ecrecover(digest, v, r, s); require(signer != address(0) && nonce == _nonces[signer]); _nonces[signer]++; emit Attested(payloadHash, signer, block.number, nonce); } function nonceOf(address signer) external view returns (uint256) { return _nonces[signer]; } }