Background and motivation
Right now the protocol requires embeds to be strings and cast parents and reaction targets to be cast IDs. However, all three of these should support many types—web URLs, on-chain URIs, and casts. Here are examples of targets we want to embed, reply to, or react to:
Hubs benefit from having a structured CastId
, because it enables indexing (i.e. GetCastsByParent
or GetReactionsByCast
methods). One option would be to continue this pattern and write protobufs for all types of URIs, however that would slow down product development—Farcaster clients would have to wait for protocol upgrades to use new types of targets. Instead, hubs should have two types of targets (strings and cast IDs) and clients should share rules for parsing the string targets.
Implementation
There are a few parts to the implementation:
- Upgrading the message.proto file to include both types for embeds, parents, and reaction targets
- Adding validation to the string targets
- Deciding on a collection of URI formats for the protocol to initially include
1. Protobufs upgrade
Embeds
Right now embeds
are only strings, so we should add a new field in CastAddBody
that is a list of targets of mixed type:
message Embed {
oneof embed {
string embed_url = 1;
CastId embed_cast_id = 2;
}
}
message CastAddBody {
repeated string url_embeds = 1; // To be deprecated
repeated Embed embeds = 6;
...
}
Once we make this upgrade, historical casts will still include string embeds at field number 1. So as of the protocol version where we add the Embed
message, we should reject new messages that include embeds in the old format with a timestamp after the prior version expires. For example, if our current protocol version is 2023.3.1
and we upgrade to 2023.4.12
, then casts can use the old embeds format until 4/27 when version 2023.3.1
expires. We can then wait and let the casts using the old embeds format get pruned over time.
Cast parent
Cast parent should include both strings and cast IDs:
message CastAddBody {
...
oneof parent {
CastId parent_cast_id = 3;
string parent_url = 7;
};
...
}
The GetCastsByParent
rpc method and cast indices will have to change to support string parents.
Reaction target
Reaction targets will need to be updated to include both strings and cast IDs:
message ReactionBody {
...
oneof target {
CastId target_cast_id = 2;
string target_url = 3;
}
}
We should change the GetReactionsByCast
rpc method to GetReactionsByTarget
and allow requests with both kinds of targets.
2. Validation
While hubs should not worry about validating the format of the string targets, they should implement length constraints, like we already have with string embeds. I propose adding the same 1-256 byte requirement on the length of each target string.
3. Supported target formats
Ultimately, there's nothing stopping a client from submitting messages with malformed targets, and it's up to clients to build UIs for each target format. That being said, the Farcaster protocol can encourage usage of shared target formats to enable cross-client experiences for users.
Similarly, targets should be as generic as possible. For instance, clients should try to reference NFTs or other on-chain assets using URIs rather than Etherscan, OpenSea, or other registry links. Those websites may change their URL formats or may cease to exist all together, so URIs that can be turned into app-specific URLs are better.
One idea is to follow the CAIP-19 standard as much as possible for on-chain assets. Here are examples:
- Ethereum mainnet NFT:
eip155:1/erc721:0xa723a8a69d9b8cf0bc93b92f9cb41532c1a27f8f/11
- Tezos NFT:
tezos/nft:KT1KEa8z6vWXDJrVqtMrAeDVzsvxat3kHaCE/145979
For NFTs specifically, users should be able to target the NFT itself but also transactions related to it. Here's an example URI for the minting transaction of an Ethereum NFT: eip155:1/erc721:0xa723a8a69d9b8cf0bc93b92f9cb41532c1a27f8f/11/0xfa2bead71e628b6fcbcb45530b1197b52092981860e653dc5285f79a27a0b92a
.
Here is an initial list of supported formats to include in the Farcaster protocol docs to encourage clients to implement:
- Generic URL:
https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]+\.[a-zA-Z0-9()]{1,6}([-a-zA-Z0-9()@:%_\+.~#?&//=])*
- Ethereum NFT URI: CAIP-19 with additional (optional) transaction hash (i.e.
eip155:<chain ID>/<token standard>:<token address>/<token id>/<optional transaction hash>
)
Assets from other blockchains can be supported in future versions.