Agent Liveness Death Certificate

agent-liveness-death-certificate · receipt-attestation · 1971 B runtime · registry-info

scores

source

pragma solidity ^0.8.13;

contract AgentLivenessDeathCertificate {
    struct AgentLiveness {
        uint40 deadline;
        uint32 interval;
        uint40 beats;
        uint128 bond;
        bool dead;
    }

    mapping(address => AgentLiveness) public agents;
    mapping(uint256 => address) public ownerOf;

    event Ping(address indexed agent, uint40 deadline, uint40 beats);
    event CertificateIssued(address indexed agent, uint256 indexed tokenId, address indexed challenger, uint256 bounty);
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    error Dead();
    error Exists();
    error NotFound();
    error BondRequired();
    error BondTooLarge();
    error InvalidInterval();
    error Missed();
    error Alive();
    error AlreadyCertified();
    error TransferFailed();

    function startLiveness(uint32 intervalSeconds) external payable {
        AgentLiveness storage a = agents[msg.sender];
        if (a.dead) revert Dead();
        if (a.bond != 0) revert Exists();
        if (msg.value == 0) revert BondRequired();
        if (msg.value > type(uint128).max) revert BondTooLarge();
        if (intervalSeconds == 0) revert InvalidInterval();

        a.deadline = uint40(block.timestamp + intervalSeconds);
        a.interval = intervalSeconds;
        a.bond = uint128(msg.value);
        a.beats = 1;
        emit Ping(msg.sender, a.deadline, a.beats);
    }

    function ping() external {
        AgentLiveness storage a = agents[msg.sender];
        if (a.dead) revert Dead();
        if (a.bond == 0) revert NotFound();
        if (block.timestamp >= uint256(a.deadline)) revert Missed();

        a.deadline = uint40(block.timestamp + uint256(a.interval));
        a.beats += 1;
        emit Ping(msg.sender, a.deadline, a.beats);
    }

    function challenge(address agent) external {
        AgentLiveness storage a = agents[agent];
        if (a.bond == 0) revert NotFound();
        if (a.dead) revert AlreadyCertified();
        if (block.timestamp < uint256(a.deadline)) revert Alive();

        a.dead = true;
        uint256 bounty = a.bond;
        a.bond = 0;

        uint256 tokenId = uint256(uint160(agent));
        if (ownerOf[tokenId] != address(0)) revert AlreadyCertified();
        ownerOf[tokenId] = msg.sender;

        emit Transfer(address(0), msg.sender, tokenId);
        emit CertificateIssued(agent, tokenId, msg.sender, bounty);

        (bool ok, ) = payable(msg.sender).call{value: bounty}("");
        if (!ok) revert TransferFailed();
    }
}

published

published on mainnet · 0xfc2BCB64C47C13d07679514216716B2d804F98E4 · tx 0xb2fa97eda44f088f… · base (8453) · mainnet · source as deployed

published on testnet · 0xa889C1B0438E12F0EC7D4262BcB1DBCfC5174B10 · tx 0xda3687ec564366b0… · base (84532) · testnet · source as deployed