Dapp Use Cases
Farcaster Message Validity
Introduction
Assertions
- Dapp Use Cases
- Implementation Address Change
- Owner Change
- Constant Product
- Lending Health Factor
- Sum of all positions
- Timelock Verification
- Oracle Validation
- TWAP Deviation
- ERC4626 Assets to Shares
- ERC4626 Deposit and Withdraw
- Fee Calculations
- Price Within Ticks
- Liquidation Health Factor
- Panic State Validation
- Harvest Increases Balance
- Tokens Borrowed Invariant
- ERC20 Drain
- Ether Drain
- Farcaster Message Validity
- Farcaster Unique Username
- Farcaster Rate Limits
- Correct Withdraw
- Intra-tx Oracle Deviation
- Previous Hacks Assertions
Dapp Use Cases
Farcaster Message Validity
Make sure that a message is valid
Use Case
Farcaster is a social media platform that allows users to post messages to a decentralized network. Although it’s not a DeFi protocol with a lot of funds at stake, it’s still important to make sure that messages are valid and usernames are unique.
Explanation
Check that a message is valid by checking the signature of the message as well as making sure content size limits are respected etc.
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 {
struct Message {
uint256 id;
address author;
bytes content;
uint256 timestamp;
bytes signature;
}
function isValidMessage(Message memory message) external view returns (bool);
function verifySignature(Message memory message) external view returns (bool);
function postMessage(Message memory message) external;
}
contract FarcasterMessageAssertion is Assertion {
IFarcaster public farcaster = IFarcaster(address(0xbeef));
bytes4 constant POST_MESSAGE = bytes4(keccak256("postMessage((uint256,address,bytes,uint256,bytes))"));
uint256 constant MAX_CONTENT_LENGTH = 320; // Farcaster's max message length
function fnSelectors() external pure override returns (bytes4[] memory assertions) {
assertions = new bytes4[](1);
assertions[0] = this.assertMessageValidity.selector;
}
function assertMessageValidity() 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;
// Decode the message
IFarcaster.Message memory message = abi.decode(stripSelector(data), (IFarcaster.Message));
ph.forkPostState();
// Check basic message validity
require(message.author != address(0), "Invalid author");
require(message.content.length > 0, "Empty content");
require(message.content.length <= MAX_CONTENT_LENGTH, "Content too long");
require(message.timestamp > 0, "Invalid timestamp");
require(message.signature.length > 0, "Missing signature");
// Verify message signature
require(farcaster.verifySignature(message), "Invalid signature");
// Check overall message validity
require(farcaster.isValidMessage(message), "Message failed validation");
}
}
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;
}
}
On this page