Skip to content

Commit aa22cca

Browse files
authored
docs: add fip-4, bump to 2023.7.12 (#105)
1 parent ad18aa2 commit aa22cca

2 files changed

Lines changed: 183 additions & 6 deletions

File tree

docs/PROPOSALS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@
22

33
Many design choices have nuances and tradeoffs that are difficult to express tersely in the protocol docs. Long form proposal documents are usually produced to discuss these decisions which cover such details. This section includes links to such proposals whose design decisions are relevant to the current protocol state.
44

5+
#### May 2023
6+
7+
- [FIP-4: ENS Usernames](https://github.com/farcasterxyz/protocol/discussions/90)
8+
59
#### April 2023
610

711
- [A Turing Complete Social Protocol](https://hackmd.io/3uAhr3bgRIOSlV8Nfv5mYA)
812
- [Farcaster Wallets](https://hackmd.io/ObCWFizyQrivDp4cnzxlow)
913
- [FIP-1: Canonical URIs](https://github.com/farcasterxyz/protocol/discussions/72)
1014
- [FIP-2: Arbitrary Targets](https://github.com/farcasterxyz/protocol/discussions/71)
15+
- [FIP-3: Links](https://github.com/farcasterxyz/protocol/discussions/85)
1116

1217
#### March 2023
1318

docs/SPECIFICATION.md

Lines changed: 178 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22

33
Requirements to implement a functional version of the Farcaster protocol.
44

5-
Version: `2023.5.31`
5+
Version: `2023.7.12`
66

77
## Table of Contents
88

99
1. [Message Specifications](#1-message-specifications)
1010
2. [CRDT Specifications](#2-message-graph-specifications)
1111
3. [Hub Specifications](#3-hub-specifications)
12-
4. [Versioning](#4-versioning)
12+
4. [Fname Specifications](#4-fname-specifications)
13+
5. [Versioning](#5-versioning)
1314

1415
# 1. Message Specifications
1516

@@ -101,6 +102,7 @@ message MessageData {
101102
CastAddBody cast_add_body = 5;
102103
CastRemoveBody cast_remove_body = 6;
103104
ReactionBody reaction_body = 7;
105+
UserNameProofBody proof_body = 8;
104106
VerificationAddEthAddressBody verification_add_eth_address_body = 9;
105107
VerificationRemoveBody verification_remove_body = 10;
106108
SignerAddBody signer_add_body = 11;
@@ -137,6 +139,7 @@ enum MessageType {
137139
MESSAGE_TYPE_SIGNER_ADD = 9; // Add a key pair that signs messages for a user
138140
MESSAGE_TYPE_SIGNER_REMOVE = 10; // Remove a previously added key pair
139141
MESSAGE_TYPE_USER_DATA_ADD = 11; // Add metadata about a user
142+
MESSAGE_TYPE_USERNAME_PROOF = 12; // Prove ownership of a username
140143
}
141144
```
142145

@@ -215,7 +218,7 @@ enum UserDataType {
215218
USER_DATA_TYPE_DISPLAY = 2; // Display Name
216219
USER_DATA_TYPE_BIO = 3; // Bio
217220
USER_DATA_TYPE_URL = 5; // Homepage URL
218-
USER_DATA_TYPE_FNAME = 6; // Preferred Fname
221+
USER_DATA_TYPE_USERNAME = 6; // Preferred Fname
219222
}
220223
```
221224

@@ -228,7 +231,7 @@ A UserDataAddBody in a Message `m` is valid only if it passes these validations:
228231
5. If `m.data.body.type` is `USER_DATA_TYPE_DISPLAY`, value must be <= 32 bytes
229232
6. If `m.data.body.type` is `USER_DATA_TYPE_BIO`, value must be <= 256 bytes
230233
7. If `m.data.body.type` is `USER_DATA_TYPE_URL`, value must be <= 256 bytes
231-
8. If `m.data.body.type` is `USER_DATA_TYPE_FNAME`, value must map to a valid fname.
234+
8. If `m.data.body.type` is `USER_DATA_TYPE_USERNAME`, value must map to a valid fname.
232235
9. `m.data.body.value` must be a valid utf-8 string
233236

234237
An fname is considered valid only if the most recent event for the fid `Transfer` event with the custody address in the `to` property. If a valid fname for a given fid becomes invalid, and there is a UserDataAdd message for that fid with the fname as its value, it must be revoked.
@@ -424,6 +427,48 @@ A LinkRemove in a message `m` is valid only if it passes these validations:
424427

425428
1. `m.data.type` must be `MESSAGE_TYPE_LINK_REMOVE`
426429

430+
## 1.7 Username Proof
431+
432+
```protobuf
433+
enum UserNameType {
434+
USERNAME_TYPE_NONE = 0;
435+
USERNAME_TYPE_ENS_FNAME = 1;
436+
USERNAME_TYPE_ENS_L1 = 2;
437+
}
438+
439+
message UserNameProofBody {
440+
uint64 timestamp = 1;
441+
bytes name = 2;
442+
bytes owner = 3;
443+
bytes signature = 4;
444+
uint64 fid = 5;
445+
UserNameType type = 6;
446+
}
447+
```
448+
449+
A UsernameProof message `m` must pass these validations:
450+
451+
1. `m.signature_scheme` must be `SIGNATURE_SCHEME_ED25519`.
452+
2. `m.data.body` must be `UserNameProofBody`.
453+
3. `m.data.body.timestamp` must be ≤ 10 mins ahead of current timestamp.
454+
4. `m.data.body.fid` must be a known fid.
455+
456+
A UsernameProof message `m` of type `USERNAME_TYPE_ENS_FNAME` must also pass these validations:
457+
458+
1. `m.data.body.name` name must match the regular expression `/^[a-z0-9][a-z0-9-]{0,15}$/`.
459+
2. `m.data.body.owner` must be the custody address of the fid.
460+
3. `m.data.body.signature` must be a valid ECDSA signature on the EIP-712 Username Proof message from the owner or the public key of the fname server.
461+
462+
A UsernameProof message `m` of type `USERNAME_TYPE_ENS_L1` must also pass these validations:
463+
464+
1. `m.data.body.name` name must:
465+
1. be a valid, unexpired ENS name
466+
2. match the regular expression `/^[a-z0-9][a-z0-9-]{0,15}\.eth$/`
467+
2. `m.data.body.owner` must:
468+
1. be the custody address or an address that the fid has a valid VerificationMessage for.
469+
2. be the address that the ENS names resolves to.
470+
3. `m.data.body.signature` must be a valid ECDSA signature on the EIP-712 Username Proof message from the owner of the ENS name.
471+
427472
# 2. Message-Graph Specifications
428473

429474
A message-graph is a data structure that allows state to be updated concurrently without requiring a central authority to resolve conflicts. It consists of a series of anonymous Δ-state CRDT's, each of which govern a data type and how it can be updated. The message-graph is idempotent but because of its dependency on state, it is not commutative or associative.
@@ -526,6 +571,19 @@ A conflict occurs if there are two messages with the same values for `m.data.fid
526571

527572
The Link CRDT has a per-user size limit of 2500.
528573

574+
### 2.1.8 UsernameProof CRDT
575+
576+
The UsernameProof CRDT validates and accepts UsernameProof messages. It must also continuously re-validate ownership of the username by running a job at 2am UTC to verify ownership of all fnames and ENS Proofs. The CRDT also ensures that a UsernameProof message m passes these validations:
577+
578+
1 `m.signer` must be a valid Signer in the add-set of the Signer CRDT for `message.fid`
579+
580+
A conflict occurs if two messages that have the same value for `m.name`. Conflicts are resolved with the following rules:
581+
582+
1. If m.data.timestamp values are distinct, discard the message with the lower timestamp.
583+
2. If m.data.timestamp values are identical, discard the message with the lower fid
584+
585+
The UsernameProof CRDT has a per-user size limit of 10.
586+
529587
# 3. Hub Specifications
530588

531589
A Hub is a node in the Farcaster network that provides an eventually consistent view of network state.
@@ -793,6 +851,10 @@ service HubService {
793851
rpc GetIdRegistryEventByAddress(IdRegistryEventByAddressRequest) returns (IdRegistryEvent);
794852
rpc GetFids(FidsRequest) returns (FidsResponse);
795853
854+
// Username Proofs
855+
rpc GetUserNameProof(UserNameProofRequest) returns (UserNameProof);
856+
rpc GetUserNameProofsByFid(FidRequest) returns (UserNameProofsResponse);
857+
796858
// Bulk Methods
797859
rpc GetAllCastMessagesByFid(FidRequest) returns (MessagesResponse);
798860
rpc GetAllReactionMessagesByFid(FidRequest) returns (MessagesResponse);
@@ -897,6 +959,14 @@ message LinksByTargetRequest {
897959
optional bool reverse = 5;
898960
}
899961
962+
message UserNameProofRequest {
963+
bytes name = 1;
964+
}
965+
966+
message UserNameProofsResponse {
967+
repeated UserNameProofBody usernameProofs = 1;
968+
}
969+
900970
message UserDataRequest {
901971
uint64 fid = 1;
902972
UserDataType user_data_type = 2;
@@ -925,13 +995,115 @@ message IdRegistryEventByAddressRequest {
925995
}
926996
```
927997

928-
# 4. Versioning
998+
# 4. Fname Specifications
999+
1000+
### ENS CCIP Contract
1001+
1002+
A CCIP [ENSIP-10](https://docs.ens.domains/ens-improvement-proposals/ensip-10-wildcard-resolution) contract will be deployed on L1 which resolves \*.fcast.id names to owner addresses. It stores the URL of the nameserver and validates signatures provided by the nameserver. This resolver will support addr record lookups only. The address of the contract is **\_\_** (to be filled on deployment).
1003+
1004+
### **Name Server**
1005+
1006+
The server which resolves `*.fcast.id` names lives at `fnames.facaster.xyz`. Fnames can be claimed by submitting an EIP-712 signed message that proves ownership of an fid that does not yet have an fname. The server also provides a method to transfer fnames to other fids by proving ownership of the fname.
1007+
1008+
Usernames are also valid subdomains (e.g. [foo.fcast.id](http://foo.fcast.id) ) though they do not currently resolve to anything. A future upgrade to the nameserver may allow the owner to set a redirect record here. The following usernames are not available for registration, since they collide with existing subdomains — `www`, `fnames`
1009+
1010+
**Managing Fname Ownership**
1011+
1012+
A POST request to the `/transfers` endpoint can be made register, move or deregister a username. The request body must contain :
1013+
1014+
```jsx
1015+
{
1016+
"from": <fid>" // 0 for registering a new fname
1017+
"to": <fid> // 0 for unregistering an existing fname
1018+
"name": "<username>", // fname
1019+
"timestamp": <current_timestamp> // Second resolution
1020+
"owner": "<address>" // ETH custody address of the non-zero "from"/"to" fid as of timestamp
1021+
"signature": "" // hex EIP-712 signature signed by the "owner" address
1022+
}
1023+
```
1024+
1025+
The request is rejected unless it meets the following criteria:
1026+
1027+
1. The fname is owned by the “from” fid or is not owned by anyone.
1028+
2. The “to” fid does not currently own a username.
1029+
3. The name matches the regular expression `/^[a-z0-9][a-z0-9-]{0,15}$/`.
1030+
4. The timestamp is ≤ current time + 1 minute (for clock skew).
1031+
5. The owner must be
1032+
1. the address that owns the “from” fid, if the “from” fid is not 0.
1033+
2. the address that owns the “to” fid, if the “from” fid is 0.
1034+
3. a privileged admin address
1035+
6. The signature is a valid EIP-712 message from the “owner” which contains the name, timestamp and owner properties.
1036+
7. If there exists an existing proof for the fid, the timestamp of this message must be `2419200` seconds (28 days) ahead of that timestamp to prevent abuse. i.e. an fid can only change their name once every 28 days
1037+
1038+
The domain and types for the EIP-712 signature are described below:
1039+
1040+
```jsx
1041+
const domain = {
1042+
name: 'Farcaster name verification',
1043+
version: '1',
1044+
chainId: 1,
1045+
verifyingContract: '0xe3be01d99baa8db9905b33a3ca391238234b79d1', // name registry contract, will be the farcaster ENS CCIP contract later
1046+
};
1047+
1048+
const types = {
1049+
UserNameProof: [
1050+
{ name: 'name', type: 'string' },
1051+
{ name: 'timestamp', type: 'uint256' },
1052+
{ name: 'owner', type: 'address' },
1053+
],
1054+
};
1055+
```
1056+
1057+
**Verifying Fname Ownership**
1058+
1059+
Anyone can verify that a user requested verification of a name by making a call to the server. usrs can make a GET request to `/transfers` which returns a paginated list of events with the following schema:
1060+
1061+
```jsx
1062+
{
1063+
"transfers": [
1064+
{
1065+
"id": 1,
1066+
"from": 0,
1067+
"to": 1,
1068+
"username": "test",
1069+
"timestamp": 1686680932,
1070+
"owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
1071+
// EIP-712 signature signed by the server's key
1072+
"server_signature": "0x68a1a565f603b9966f228a38d918c12f166650749359fe41e2755fabe016026b361dd7d5f917c6f8a09241b29085fbaefffb75e443a3851be85c8b53b",
1073+
// Original user provided signature
1074+
"user_signature": "0xf603b9966f228a38d918c12f166650749359fe41e2755fabe016026b361dd7d5f917c6f8a09241b29085fbaefffb75e443a3851be85c8b53b691536d1c",
1075+
},
1076+
// ...
1077+
]
1078+
}
1079+
```
1080+
1081+
Results can be filtered with these query string parameters:
1082+
1083+
```jsx
1084+
from_id=<id> // minimum id
1085+
from_ts=<timestamp> // minumum timestamp
1086+
fid=<fid> // filter events by a particular fid
1087+
name=<username> // filter events for a particular name
1088+
```
1089+
1090+
**Nameserver Keypair**
1091+
1092+
The nameserver maintains its own ECDSA keypair to counter-sign messages or perform administrative actions. The `server_signature` will be signed by this key. The public key used to perform these signers can be fetched by performing a GET on `/signer` which returns:
1093+
1094+
```jsx
1095+
{
1096+
"address": "<addr>" // Public address for the server's signer
1097+
}
1098+
```
1099+
1100+
# 5. Versioning
9291101
9301102
Farcaster is a long-lived protocol built on the idea of [stability without stagnation](https://doc.rust-lang.org/1.30.0/book/second-edition/appendix-07-nightly-rust.html). Upgrades are designed to be regular and painless, bringing continual improvements for users and developers.
9311103
9321104
The protocol specification is date versioned with a non-zero leading `YYYY.MM.DD` format like `2021.3.1`. A new version of the protocol specification must be released every 6 weeks. Hot-fix releases are permitted in-between regular if necessary.
9331105
934-
## 4.1 Upgrade Process
1106+
## 5.1 Upgrade Process
9351107
9361108
Hubs implement a specific version of the protocol, which is advertised in their `HubInfoResponse`.
9371109

0 commit comments

Comments
 (0)