Use Case

Farcaster is a social media platform that allows users to post messages to a decentralized network. In a free to use platform like Farcaster, it is important to make sure that it’s not possible to DoS the platform.

Explanation

Check that rate limits are respected.

Code Example

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {Assertion} from "../../lib/credible-std/src/Assertion.sol";
import {PhEvm} from "../../lib/credible-std/src/PhEvm.sol";

interface IFarcaster {
    function getLastPostTimestamp(address user) external view returns (uint256);
    function getUserPostCount(address user, uint256 timeWindow) external view returns (uint256);
    function postMessage(address user, string calldata content) external;
}

contract FarcasterRateLimitAssertion is Assertion {
    IFarcaster public farcaster = IFarcaster(address(0xbeef));

    // Rate limit constants
    uint256 constant POST_COOLDOWN = 1 minutes;
    uint256 constant MAX_POSTS_PER_HOUR = 60;
    uint256 constant HOUR = 1 hours;

    function fnSelectors() external pure override returns (bytes4[] memory assertions) {
        assertions = new bytes4[](1);
        assertions[0] = this.assertRateLimit.selector;
    }

    function assertRateLimit() external {
        PhEvm.CallInputs[] memory callInputs = ph.getCallInputs(address(farcaster), farcaster.postMessage.selector);
        if (callInputs.length == 0) {
            return;
        }

        for (uint256 i = 0; i < callInputs.length; i++) {
            bytes memory data = callInputs[i].input;
            address user = abi.decode(stripSelector(data), (address));

            ph.forkPreState();

            // Check cooldown between posts
            uint256 lastPostTime = farcaster.getLastPostTimestamp(user);
            require(block.timestamp >= lastPostTime + POST_COOLDOWN, "Posting too quickly");

            // Check hourly post limit
            uint256 hourlyPosts = farcaster.getUserPostCount(user, HOUR);
            require(hourlyPosts < MAX_POSTS_PER_HOUR, "Exceeded hourly post limit");
        }
    }

    function stripSelector(bytes memory input) internal pure returns (bytes memory) {
        bytes memory paramData = new bytes(32);
        for (uint256 i = 4; i < input.length; i++) {
            paramData[i - 4] = input[i];
        }
        return paramData;
    }
}