MANIFEST_HEARTBEAT_CHAIN

manifest-heartbeat-chain · discovery-registry · 1186 B runtime · registry-info

scores

source

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract ManifestHeartbeatChain {
    error AlreadyRegistered();
    error NotFound();
    error ExpiredEntry();
    error NotExpired();

    struct Entry {
        bytes32 head;
        uint256 lastBeat;
    }

    mapping(address => Entry) public entries;
    uint256 private constant TTL = 1 days;

    event Registered(address indexed agent, bytes32 manifestRoot, bytes32 head, uint256 timestamp);
    event Updated(address indexed agent, bytes32 manifestRoot, bytes32 newHead, uint256 timestamp);
    event Beat(address indexed agent, uint256 timestamp);
    event Expired(address indexed agent);

    function register(bytes32 manifestRoot) external {
        if (entries[msg.sender].lastBeat != 0) revert AlreadyRegistered();
        bytes32 head = keccak256(abi.encodePacked(bytes32(0), manifestRoot, block.timestamp));
        entries[msg.sender] = Entry(head, block.timestamp);
        emit Registered(msg.sender, manifestRoot, head, block.timestamp);
    }

    function update(bytes32 manifestRoot) external {
        Entry storage e = entries[msg.sender];
        if (e.lastBeat == 0) revert NotFound();
        uint256 ts = block.timestamp;
        if (ts > e.lastBeat + TTL) revert ExpiredEntry();
        e.lastBeat = ts;
        e.head = keccak256(abi.encodePacked(e.head, manifestRoot, ts));
        emit Updated(msg.sender, manifestRoot, e.head, ts);
    }

    function beat() external {
        Entry storage e = entries[msg.sender];
        if (e.lastBeat == 0) revert NotFound();
        if (block.timestamp > e.lastBeat + TTL) revert ExpiredEntry();
        e.lastBeat = block.timestamp;
        emit Beat(msg.sender, block.timestamp);
    }

    function expire(address agent) external {
        Entry storage e = entries[agent];
        if (e.lastBeat == 0) revert NotFound();
        if (block.timestamp <= e.lastBeat + TTL) revert NotExpired();
        delete entries[agent];
        emit Expired(agent);
    }
}

published

published on mainnet · 0xb36f550e6802074EF02AFF22b9771FC1D38307C7 · tx 0x88e6b1143f971b0e… · base (8453) · mainnet · source as deployed

published on testnet · 0x21665D25A7beae0A5554De565bAAAcC54ae2Aac6 · tx 0x3ddcb99aa993929f… · base (84532) · testnet · source as deployed