# a16z领投3000万美元的去中心化社交协议Farcaster教程

By [Greta](https://paragraph.com/@greta888) · 2022-07-13

---

### Step 1: 设置环境

在编写代码之前，您需要设置一个 Node.js 环境，推荐使用 [replit](http://replit.com) ，它是一个基于 IDE 进行编程的浏览器。

1.在 repli 上注册一个免费帐户并登录；

2.点击左上角的create创建；

![](https://storage.googleapis.com/papyrus_images/b1d2f1ece590629a72584459abd306b7c5fad4b499ffb7edb5fc11da1e062dbc.png)

3.出现提示时选择 Node.js，然后点击Create Repl。

![](https://storage.googleapis.com/papyrus_images/c674b504218b13e80c582a48a1bd184c6b9be4886588591c9bee624fe36ab665.png)

还需要一个以太坊节点来与 Facaster Registry 合约对话。 建议使用 [Alchemy](https://www.alchemy.com/) 。 如果您是第一次注册，以下步骤可能会略有不同：

1.注册 [Alchemy.com](http://www.alchemy.com) ，并登录。

![](https://storage.googleapis.com/papyrus_images/d57e67771a055b3d5e0224324837f5d379922ca09642f1aefe692cdea3ffd222.png)

2.选择以太坊作为区块链，点击get started。

![](https://storage.googleapis.com/papyrus_images/4cab2c6aeef2ef2c22a40174a5bb7eb6ec1a8c62f4c5bd49ebf79ccd19ec7041.png)

3.team name和app name随便取，网络选择Rinkeby，点击Create APP。

![](https://storage.googleapis.com/papyrus_images/1cc0275b4612d7bc7e6158e9ca18c2d73bb30dfe53191401fcdf4e34d7a45f4d.png)

4.选择第一个免费的，点击continue。

![](https://storage.googleapis.com/papyrus_images/464f5ef91aa25aa981a0ca692d0b5f2ed2f89f29dad227d9f8b1fb2138f8c8c9.png)

5.点击跳过。

![](https://storage.googleapis.com/papyrus_images/6b61a6402bba90ab39c99bbef87f2b61e82a8e3495b614546b3381042e1dd72b.png)

6.继续点击跳过。

![](https://storage.googleapis.com/papyrus_images/b2ed3db1afcdf893b3babe45d5d970cfd7bf97f5c93b6e172310545ff8f5de32.png)

7.点击continue。

![](https://storage.googleapis.com/papyrus_images/bc5d2c3eb4c3d7364b420d84a3403eda24440c348f552e8a67503497290a0cf3.png)

8.随便输入什么,点击let‘s go。

![](https://storage.googleapis.com/papyrus_images/ab8a79099121507812fb51c686f178b5f982c1f0a06bc4478e60941efed9adc1.png)

9.点击view details。

![](https://storage.googleapis.com/papyrus_images/dca2084adb7801f3cbae60278524e2521173ebe12db13e195324770fdb8062ee.png)

10.点击view key。

![](https://storage.googleapis.com/papyrus_images/5c134898931be1bc06e8041f96466be3ed624bfbaf55cdfeae61e6bc6d656640.png)

11.找到HTTP的URL，复制v2/后面那部分代码，将其保存在某个地方。

![](https://storage.googleapis.com/papyrus_images/d4c767969f7b9fd3f26f18e72494b50651fcc9afd3c647f7e4ea6bb8e43d569a.png)

12.切换回 Replit 并转到右侧窗格中的 Shell 选项卡并运行以下代码：

npm install ethers [got@11.8.2](mailto:got@11.8.2)

这将安装 [ethers](https://github.com/ethers-io/ethers.js) ，一个用于与 Ethereum 一起工作的库， [got](https://github.com/sindresorhus/got) ，一个用于发出 HTTP 请求的库。 您可能会看到一些关于缺少 package.json 的警告，您可以忽略这些警告。

![](https://storage.googleapis.com/papyrus_images/4d984a7450d42d3121a429eb49bf9b15116c962aafabaf548a047b8e1b8f61ea.png)

![](https://storage.googleapis.com/papyrus_images/0ac55c1291b2a01228e00dc5d0f99a4e1d8eb53d286ab053629dc3186b97275d.png)

### Step 2: 连接到以太坊节点

1.切换到 Replit 中心窗格中的 index.js 选项卡，然后复制下面的代码片段。 确保将那一堆×换成step1 的第11步保存的代码，点击run。

const { providers, Contract, utils } = require("ethers"); const got = require("got");

const doStuff = async () => { const ALCHEMY\_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // Replace with your secret const provider = new providers.AlchemyProvider('rinkeby', ALCHEMY\_SECRET);

    const block = await provider.getBlockNumber();
    

console.log("The latest Ethereum block is:", block); }

doStuff();

![](https://storage.googleapis.com/papyrus_images/1aab1334a3c0e0d709f649318fb169f2911a3addf988df877d9c6c8f277bea5e.png)

2.当您点击运行时，如果一切正常，您应该会看到如下内容：

The latest Ethereum block is: 10027943

后面那个数字大家会不一样。

我们刚刚编写的代码创建了一个 [Ethers Provider](https://docs.ethers.io/v5/api/providers/) ，这是一个我们可以调用以与 Ethereum 交互的接口。 提供者通过 Alchemy 节点连接到区块链。

### Step 3: 连接到Farcaster注册表

1.复制以下it代码并将其添加到底部 `doStuff`函数，就在最后一行的下方 `console.log("The latest Ethereum block is:", block);`. 所有后面的代码片段都应该以同样的方式添加到底部：

const REGISTRY\_CONTRACT\_ADDRESS = '0xe3Be01D99bAa8dB9905b33a3cA391238234B79D1' const REGISTRY\_ABI = \[ { name: 'getDirectoryUrl', inputs: \[{ internalType: 'bytes32', name: 'username', type: 'bytes32' }\], outputs: \[{ internalType: 'string', name: '', type: 'string'}\], stateMutability: 'view', type: 'function', }, { inputs: \[{ internalType: 'address', name: '', type: 'address' }\], name: 'addressToUsername', outputs: \[{ internalType: 'bytes32', name: '', type: 'bytes32' }\], stateMutability: 'view', type: 'function', }, \];

const registryContract = new Contract(REGISTRY\_CONTRACT\_ADDRESS, REGISTRY\_ABI, provider);

const username = 'v'; const byte32Name = utils.formatBytes32String(username); const directoryUrl = await registryContract.getDirectoryUrl(byte32Name); console.log(`${username}'s Host is located at: ${directoryUrl} \n`);

2.如果一切正常，你会看到以下内容：

v's Host is located at: [https://guardian.farcaster.xyz/origin/directory/0x012D3606bAe7aebF03a04F8802c561330eAce70A](https://guardian.farcaster.xyz/origin/directory/0x012D3606bAe7aebF03a04F8802c561330eAce70A)

![](https://storage.googleapis.com/papyrus_images/ce1ddaf499cfc9c452e70664f1087b5e0e6f52aaffdee2a09e4dc3875b6b9351.png)

### Step 4: 获取用户目录

1.将以下代码添加到底部 `doStuff`,像你刚才做的那样，然后再次运行它：

const directoryResponse = await got(directoryUrl); const directory = JSON.parse(directoryResponse.body); console.log(`${username}'s Directory is:` ); console.log(directory, '\\n');

2.如果一切正常，你会看到以下内容：

v's Directory is: { body: { addressActivityUrl: '[https://guardian.farcaster.xyz/origin/address\_activity/0x012D3606bAe7aebF03a04F8802c561330eAce70A](https://guardian.farcaster.xyz/origin/address_activity/0x012D3606bAe7aebF03a04F8802c561330eAce70A)', avatarUrl: '[https://lh3.googleusercontent.com/sYAr036bd0bRpj7OX6B-F-MqLGznVkK3--DSneL\_BT5GX4NZJ3Zu91PgjpD9-xuVJtHq0qirJfPZeMKrahz8Us2Tj\_X8qdNPYC-imqs](https://lh3.googleusercontent.com/sYAr036bd0bRpj7OX6B-F-MqLGznVkK3--DSneL_BT5GX4NZJ3Zu91PgjpD9-xuVJtHq0qirJfPZeMKrahz8Us2Tj_X8qdNPYC-imqs)', displayName: 'Varun Srinivasan', proofUrl: '[https://guardian.farcaster.xyz/origin/proof/0x012D3606bAe7aebF03a04F8802c561330eAce70A](https://guardian.farcaster.xyz/origin/proof/0x012D3606bAe7aebF03a04F8802c561330eAce70A)', timestamp: 1639029396497, version: 1 }, merkleRoot: '0xcccabedbe3267e21d80e959de72f2933a68c6cd4c29453aed81a78bc8d4d8521', signature: '0x3412be3e88bc49cd89a18890bcd8e116776ed649e270ac0a3955864bed1e2cd243407e2a478f66fa47cedb1668a8298c98e632d6607c0a6082b6589e8bf2a2501b' }

![](https://storage.googleapis.com/papyrus_images/53e2c07081afd8dd4f35057968f67ee477fd55cedc34c98f39736687b0df6128.png)

### Step 5: 从地址活动获取用户最近行为

1.将以下代码添加到底部 `doStuff`，就像你刚才做的那样，然后再次运行它：

const addressActivityUrl = directory.body.addressActivityUrl; const addressActivityResponse = await got(addressActivityUrl); const addressActivity = JSON.parse(addressActivityResponse.body); const cast = addressActivity\[0\]; console.log(`${username}'s most recent Cast was:` ) console.log(cast, '\\n')

2.如果一切正常，你会看到以下内容：

v's most recent Cast was: { body: { type: 'text-short', publishedAt: 1642720790424, sequence: 493, username: 'v', address: '0x012D3606bAe7aebF03a04F8802c561330eAce70A', data: { text: 'Is Maine meant to be an outlier? \\n\\nHard to tell without the legend', replyParentMerkleRoot: '0x647432bd51231b217f7c31f5d678e7acccf3d1b5f30ba72fc2cffa895927a5d1' }, prevMerkleRoot: '0x21570c8e24879010978a08339eb344898b22b7d21cc56ce3a176abe118cc5f61' }, merkleRoot: '0xa20c21aa020c2be7aa6f9577468a4bbf32701ae3d835e882d9a9fd25bdcb4e1e', signature: '0xca11e5d2e8e1b7259c1d7dd1a08f87275c16a0282e559eec7a77cfad2df1aa01234d01002637e096c208ebb491ed2de8229bbde5ccb2a4a71f194189820071161c' }

![](https://storage.googleapis.com/papyrus_images/f7535e0bcf222e5ce4558fbddb03a8c94c32d061c8f40429a23bbb90df90d4cd.png)

### Step 6: 验证签名

1.让我们再次复制粘贴代码：

const stringifiedCastBody = JSON.stringify(cast.body); const calculatedHash = utils.keccak256(utils.toUtf8Bytes(stringifiedCastBody)); const expectedHash = cast.merkleRoot;

if (calculatedHash !== expectedHash) { console.log(`FAILED: the calculated hash ${calculatedHash} does not match the one in the cast: ${expectedHash}`); } else { console.log(`PASSED: the calculated hash ${calculatedHash} matches the one in the cast`); }

const recoveredAddress = utils.verifyMessage(cast.merkleRoot, cast.signature); const expectedAddress = cast.body.address;

if (recoveredAddress !== expectedAddress) { console.log( `Failed: the recovered address ${recoveredAddress} does not match the address provided in the cast ${expectedAddress}` ); } else { console.log(`PASSED: the recovered address ${recoveredAddress} matches the one in the cast`); }

2.如果一切正常，你会看到以下内容：

PASSED: the calculated hash 0xa20c21aa020c2be7aa6f9577468a4bbf32701ae3d835e882d9a9fd25bdcb4e1e matches the one in the cast PASSED: the recovered address 0x012D3606bAe7aebF03a04F8802c561330eAce70A matches the one in the cast

![](https://storage.googleapis.com/papyrus_images/ffdf98986ea077330289e0302767279e699ed254f39c9176465da415a63890ed.png)

### Step 7: 验证有用户名V的地址

1.最后，我们需要回到区块链并检查执行签名的地址是否与拥有 `v`用户名的地址相同. 复制并运行底部的以下代码 `doStuff`:

const encodedUsername = await registryContract.addressToUsername(expectedAddress); const expectedUsername = utils.parseBytes32String(encodedUsername); const castUsername = cast.body.username;

if (expectedUsername !== castUsername) { console.log(`FAILED: ${expectedAddress} does not own ${castUsername}, it owns ${expectedUsername}`); } else { console.log(`PASSED: ${expectedAddress} owns ${castUsername}`); }

2.如果这成功完成，您会看到如下消息：

PASSED: 0x012D3606bAe7aebF03a04F8802c561330eAce70A owns v

![](https://storage.googleapis.com/papyrus_images/4cd2fb46e17e8f92044c0c8c6f96daa892235d712a95ae7295b278509aaf4842.png)

**恭喜 - 你已经在 Farcaster 上构建了你的第一个可以读取用户消息的应用程序！ 您还学习了如何验证签名，以便您可以安全地接收来自网络上任何用户的消息！**

---

*Originally published on [Greta](https://paragraph.com/@greta888/a16z-3000-farcaster)*
