Heartbeat-Gap Failure Receipt

heartbeat-gap-failure-receipt · receipt-attestation · 1993 B runtime · registry-info

scores

source

pragma solidity ^0.8.13;

contract HeartbeatGapFailureReceipt {
    struct Agent {
        uint96 bond;
        uint64 lastBlock;
        uint64 interval;
        bool active;
    }

    mapping(address => Agent) public agents;

    event Registered(address indexed agent, uint96 bond, uint64 interval, uint64 blockNumber);
    event Heartbeat(address indexed agent, uint64 blockNumber);
    event MissedHeartbeat(
        address indexed agent,
        address indexed filer,
        uint96 bond,
        uint64 lastBlock,
        uint64 interval,
        uint64 filedAt,
        uint96 reward,
        uint96 burned
    );

    function register(uint64 interval) external payable {
        require(interval > 0, "IntervalZero");
        require(!agents[msg.sender].active, "AlreadyActive");

        uint96 bond = uint96(msg.value);
        require(bond > 0, "BondZero");
        require(bond == msg.value, "BondTooHigh");

        agents[msg.sender] = Agent({
            bond: bond,
            lastBlock: uint64(block.number),
            interval: interval,
            active: true
        });

        emit Registered(msg.sender, bond, interval, uint64(block.number));
    }

    function heartbeat() external {
        Agent storage agent = agents[msg.sender];
        require(agent.active, "NotActive");
        agent.lastBlock = uint64(block.number);
        emit Heartbeat(msg.sender, uint64(block.number));
    }

    function fileFailure(address agentAddress) external {
        Agent storage agent = agents[agentAddress];
        require(agent.active, "NotActive");
        require(block.number >= uint256(agent.lastBlock) + uint256(agent.interval), "NotLapsed");

        uint96 bond = agent.bond;
        uint64 lastBlock = agent.lastBlock;
        uint64 interval = agent.interval;
        uint96 reward = bond / 2;
        uint96 burned = bond - reward;

        agent.active = false;
        agent.bond = 0;
        agent.lastBlock = 0;
        agent.interval = 0;

        (bool ok, ) = payable(msg.sender).call{value: reward}("");
        require(ok, "RewardFailed");

        (bool burnOk, ) = payable(address(0)).call{value: burned}("");
        require(burnOk, "BurnFailed");

        emit MissedHeartbeat(agentAddress, msg.sender, bond, lastBlock, interval, uint64(block.number), reward, burned);
    }
}

published

published on mainnet · 0x50b5C88C3c71c0b12Bc7CFdD510481f1749e8aEF · tx 0x4729bc7430cc2100… · base (8453) · mainnet · source as deployed

published on testnet · 0xa46ab6b30cfBf73cB82849512FF813aA7D80c6a8 · tx 0x938cf44d9b392940… · base (84532) · testnet · source as deployed