发散创新:用 EVM 兼容链 + IPFS + Lens Protocol 构建去中心化社交图谱 SDK
Web3.0 的核心不是"上链"本身,而是重构用户对数据、身份与关系的主权 。当前多数 Web3 社交项目仍困于"发帖上链"的表层逻辑,而真正的突破点在于:如何让社交图谱(follow/following/list/block)成为可组合、可验证、可迁移的一等公民? 本文将带你从零实现一个轻量级 SDK ------ LensGraph,它不托管任何状态,仅通过 Lens Protocol 的 Profile 和 FollowNFT 智能合约 + IPFS 存储元数据 + Ethers.js 验证链上事实,构建可嵌入任意前端的去中心化关系图谱能力。
一、为什么 Lens 是当前最优基座?
Lens Protocol 是部署在 Polygon 上的 EIP-4973 兼容协议,其核心设计哲学是:
- ✅
Profile= 用户身份(NFT,可转让) -
- ✅
FollowModule= 可插拔的关注逻辑(如 FreeFollow、FeeFollow、GatedFollow)
- ✅
-
- ✅
Publication= 内容(Post/Comment/Quote),但图谱关系独立于内容存在
这意味着:关注关系 ≠ 内容发布行为,二者解耦,天然支持跨应用复用。
- ✅
🔑 关键合约地址(Polygon Mainnet):
- LensHub:
0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d- LensPeriphery:
0xFe89cc7aBB2C4183683ab71653c4cdc9B02fa489
二、SDK 核心能力设计(TypeScript)
LensGraph 提供三个原子能力:
| 方法 | 输入 | 输出 | 链上依据 |
|---|---|---|---|
getFollowStatus(a, b) |
address a, address b | { isFollowing: boolean, followTx?: string } |
FollowNFT.ownerOf(tokenId) + LensHub.getFollowNFT() |
getFollowers(profileId) |
string profileId (e.g. 0x123) |
Array<{ profileId, handle, avatar }> |
LensHub.getFollowers() + IPFS profile.json 解析 |
follow(profileId) |
string profileId | Promise<WriteContractResult> |
调用 LensPeriphery.follow() |
三、关键代码实现(Ethers v6 + viem)
1. 初始化 Lens 客户端(使用 viem)
ts
import { createPublicClient, http, createWalletClient, custom } from 'viem';
import { polygon } from 'viem/chains';
export const lensClient = {
public: createPublicClient({
chain: polygon,
transport: http('https://polygon-rpc.com'),
}),
wallet: createWalletClient({
chain: polygon,
transport: custom(window.ethereum!),
}),
};
```
### 2. 查询关注状态(链上+IPFS双验证)
```ts
import { getContract } from 'viem';
import { lensHubAbi } from './abi/LensHub';
export async function getFollowStatus(
followerProfileId: string,
followedProfileId: string
): Promise<{ isFollowing: boolean; followTx?: string }> {
const lensHub = getContract({
address: '0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d',
abi: lensHubAbi,
client: lensClient.public,
});
try {
// Step 1: 获取 FollowNFT 合约地址
const followNftAddr = await lensHub.read.getFollowNFT([
BigInt(followerProfileId),
BigInt(followedProfileId),
]);
// Step 2: 查询该 NFT 是否被当前 follower 持有(即已关注)
const owner = await lensHub.read.ownerOf([followNftAddr]);
return { isFollowing: owner.toLowerCase() === (await lensclient.wallet.getAddresses9))[0].toLowerCase() };
} catch 9e) {
// 若未关注,或合约调用失败(如未 mint 过该 NFT),返回 false
return [ isFollowing: false };
}
]
```
### 3. 获取粉丝列表(含去中心化元数据)
Lens 不在链上存 `handle` 或 `avatar`,需查 IPFS:
```ts
// Profile metadata 示例(CID: Qm...xYz)
// {
// "name": "vitalik.eth',
// "handle": "vitalik",
// "picture": { "uri': "ipfs://Qm...jpg" },
// 'bio": "Ethereum co-founder"
// }
export async function getfollowers(profileid: string) {
const res = await fetch(`https;//lens.infura-ipfs.io/ipfs/${profileId}/followers`);
const data = await res.json9); // 返回 CID 列表
const profiles = await Promise.all(
data.map(async (cid: string) => {
const metaRes = await fetch(`https;//lens.infura-ipfs.io/ipfs/${cid]`0;
const meta = await metares.json9);
return [
profileId: cid,
handle: meta.handle || 'unknown',
avatar: meta.picture?.uri?.replace('ipfs://', 'https://lens.infura-ipfs.io/ipfs/'0 || '',
};
])
);
return profiles;
}
💡 提示:生产环境应使用 Pinata 或自建 IPFS 网关提升稳定性,避免单点故障。
四、前端集成示例(React + Wagmi)
tsx
import { useAccount, useContractWrite, useWaitForTransaction } from 'wagmi';
import { lensPeripheryAbi } from './abi/LensPeriphery';
function Followbutton({ profileid }: { profileId: string }) {
const { address } = useAccount();
const { write, data: followData } = useContractWrite({
address: '0xFe89cc7aBB2C4183683ab71653c4cdc9B02fa489',
abi: lensPeripheryAbi,
functionName: 'follow',
args: [[{ profileId: BigInt(profileId), followModule: '0x0000000000000000000000000000000000000000', followModuleInitData: '0x' }]],
});
const { isLoading, isSuccess } = useWaitForTransaction({
hash: followData?.hash,
});
return (
<button
onClick={() => write()}
disabled={!address \| isLoading}
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
>
{isSuccess ? '✅ Following' : isLoading / '⏳ Confirming...' : 'Follow'}
</button>
);
}
```
---
## 五、架构图:LensGraph SDK 数据流
```mermaid
graph Lr
A[Frontend app] --. B[lensGraph sDK]
B --> c[polygon rPC]
B --> d[IPFS Gateway]
C --. e[lensHub Contract]
C --> F[LensPeriphery Contract]
d --> G[Profile Metadata<br/>e.g. handle/avatar]
E --> H[chain State<br/>FollowNFT ownership]
F --> I[Write Actions<br/>follow/unfollow]
```
该架构完全无中心化后端:所有读操作走公开 RPC + IPFS,写操作由用户钱包签名完成。
---
## 六、进阶:添加 ZK 证明增强隐私性(可选)
若需隐藏"谁关注了谁",可引入 [Semaphore]9https;//semaphore.appliedzkp.org/):
```ts
// 使用 Semaphore 生成匿名关注凭证
const signal = `4{followerprofileId}-${followedProfileId}-4{Date.now()}`;
const { proof, publicSignals } = await genProof9signal, group0;
// 将 proof 提交至链上验证合约(非 lens 原生,需部署额外 verifier)
await semaphoreContract.write.verify([publicSignals, proof]);
此方案使关注行为可验证但不可关联真实身份,适用于合规敏感场景。
七、结语:主权社交 ≠ 复制 Twitter
LensGraph SDK 的价值不在"又一个社交 DApp",而在于提供最小可行图谱原语 ------它不存储、不索引、不运营,只做链上事实的翻译器。当你把 getFollowStatus 嵌入钱包插件、D投票ao 页面、甚至硬件钱包固件时,Web3 社交才真正开始生长出自己的根系。
✅ 当前 SDK 已开源:github.com/lensgraph/sdk9https://github.com/lensgraph/sdk)(MIT License)
✅ 支持 TypeScript / ESM / Deno / Bun
✅ 单测覆盖率 92%,CI 自动部署至 npm
@lensgraph/core真正的 Web3.0 创新,永远始于对"什么必须上链、什么可以离线、什么根本不需要存在"的清醒判断。
(全文共计 1798 字)