揭秘 Web3 隐私社交标杆:CocoCat 的核心架构与智能合约实现

前端

特此声明:本文仅做项目技术拆解,不做项目投资推荐,投资有风险,入市需谨慎 。在 Web3.0 浪潮中,社交赛道正经历从"数据垄断"到"主权回归"的范式转移。作为去中心化隐私社交应用的代表,CocoCat 通过独特的影子身份协议(Shadow Identity)与 RelayX 分布式中继网络,成功构建了一个既保护隐私又具备商业可持续性的社交生态。

本文将深入探讨 CocoCat 的核心技术点,并展示如何基于 Solidity 0.8.24OpenZeppelin V5 实现其核心业务流。

CocoCat项目相关梳理

概述 :CocoCat 是一个基于区块链的隐私社交平台,类"去中心化版的通讯软件"。

1. 它能做什么?

  • 私密聊天:聊天内容端到端加密,没有中央服务器,没人能监控。
  • 影子身份:用匿名哈希(Shadow ID)社交,不暴露真实钱包地址。
  • 赚取收益 :用户贡献带宽作为"中继节点"转发消息,赚取 CAT 代币
  • Web3 支付:内置钱包,聊天时直接转账、发红包。

2. 核心特点(黑科技)

  • 零服务器 (RelayX) :消息通过全球用户节点点对点传输,永不宕机,成本极低。
  • 三重隐私:身份、聊天数据、社交关系全部加密且去中心化存储。
  • 离线签名 (EIP-712) :聊天支付不走即时链上交易,省 Gas 费且速度快。

3. 项目风险

  • 用户量不足:P2P 网络依赖节点数量,人少会导致消息延迟或收不到。
  • 监管压力:极致隐私可能被用于非法用途,面临各国政策审查。
  • 代币风险:CAT 代币价值完全取决于生态热度,波动巨大。
  • 门槛高:对普通用户来说,理解和使用 Web3 社交软件有学习成本。

一、 CocoCat 的三大技术支柱

1. 影子身份协议 (Shadow Identity)

传统的社交软件通过手机号或中心化 ID 锚定用户,数据极易被追踪。CocoCat 引入了 "影子身份"

  • 链上锚定:用户的钱包地址仅作为身份的"担保人",真实社交活动使用隐匿的"影子公钥哈希"。
  • 隐私隔离:即使外部观察者追踪到钱包地址,也无法将其与 P2P 网络中的具体聊天行为关联。

2. RelayX 中继协议

为了解决去中心化网络中的通信效率与成本问题,CocoCat 采用了 RelayX 协议

  • 去服务器化:消息不经过中心化服务器,而是通过分布式的 P2P 节点进行中继。
  • 低成本运行:通过将通讯逻辑下放到中继节点,开发者可节省超过 90% 的传统运营成本。

3. 基于 EIP-712 的支付闭环

社交中继并非免费。CocoCat 巧妙地利用 EIP-712 类型化签名,实现了"链下授权、链上结算"的经济闭环。用户在发送消息时签署小额支付凭证,节点定期上链兑付,极大优化了 Gas 效率。


二、 核心合约实现:从锚定到结算

代币合约

typescript 复制代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";

contract CocoCatToken is ERC20, ERC20Burnable, AccessControl {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    constructor() ERC20("CocoCat Token", "CAT") {
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _grantRole(MINTER_ROLE, msg.sender);
    }

    function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
        _mint(to, amount);
    }
}

CocoCatCore合约:它集成了身份注册、预存话费与 EIP-712 签名结算功能。

ini 复制代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract CocoCatCore is EIP712, ReentrancyGuard {
    using ECDSA for bytes32;

    IERC20 public immutable catToken;
    bytes32 private constant SETTLEMENT_TYPEHASH = 
        keccak256("Settlement(address node,uint256 amount,uint256 nonce)");

    // 1. 锚定逻辑:钱包地址 => 影子公钥哈希 (ShadowHash)
    mapping(address => bytes32) public shadowIdentities;
    
    // 2. 结算逻辑数据
    mapping(address => uint256) public userDeposits;
    mapping(address => uint256) public nonces;
    mapping(address => uint256) public nodeBalances;

    event IdentityAnchored(address indexed wallet, bytes32 shadowHash);
    event Settled(address indexed user, address indexed node, uint256 amount);

    constructor(address _catToken) EIP712("CocoCat_RelayX", "1") {
        catToken = IERC20(_catToken);
    }

    // --- 锚定阶段 (Anchoring) ---
    function registerShadowIdentity(bytes32 _shadowHash) external {
        require(shadowIdentities[msg.sender] == bytes32(0), "Already anchored");
        shadowIdentities[msg.sender] = _shadowHash;
        emit IdentityAnchored(msg.sender, _shadowHash);
    }

    // --- 发现阶段 (Discovery - View Only) ---
    function getShadowHash(address _wallet) external view returns (bytes32) {
        return shadowIdentities[_wallet];
    }

    // --- 结算阶段 (Settlement) ---
    function deposit(uint256 _amount) external nonReentrant {
        require(catToken.transferFrom(msg.sender, address(this), _amount), "Transfer failed");
        userDeposits[msg.sender] += _amount;
    }

    function settleWithSignature(
        address _user,
        uint256 _amount,
        uint256 _nonce,
        bytes calldata _signature
    ) external nonReentrant {
        require(_nonce == nonces[_user], "Invalid nonce");
        require(userDeposits[_user] >= _amount, "Insufficient user funds");

        // EIP-712 验证
        bytes32 structHash = keccak256(abi.encode(SETTLEMENT_TYPEHASH, msg.sender, _amount, _nonce));
        bytes32 hash = _hashTypedDataV4(structHash);
        address signer = hash.recover(_signature);
        
        require(signer == _user, "Invalid service signature");

        // 状态更新
        nonces[_user]++;
        userDeposits[_user] -= _amount;
        nodeBalances[msg.sender] += _amount;

        emit Settled(_user, msg.sender, _amount);
    }

    function withdrawEarnings() external nonReentrant {
        uint256 amount = nodeBalances[msg.sender];
        require(amount > 0, "No earnings");
        nodeBalances[msg.sender] = 0;
        require(catToken.transfer(msg.sender, amount), "Withdrawal failed");
    }
}

三、 自动化测试与安全性验证

测试用例:

1. 业务流程全路径验证

通过模拟 "生成 -> 锚定 -> 发现 -> 签名 -> 结算" ,确保整个逻辑闭环。测试结果显示,用户可以在不频繁操作区块链的情况下,通过离线签名完成对中继服务的支付。

2. 安全边界测试

针对"影子身份被篡改"和"签名重放"进行了压力测试。例如,通过 assert.rejectssimulateContract 捕获合约回滚,确保一个地址无法绑定多个影子身份,保护了系统身份的一致性。

typescript 复制代码
import assert from "node:assert/strict";
import { describe, it, beforeEach } from "node:test";
import { network } from "hardhat"; 
import { parseEther, type Address, keccak256, toHex ,BaseError, ContractFunctionRevertedError} from "viem";

describe("CocoCat 业务全流程深度测试", function () {
    let catToken: any, cocoCore: any;
    let admin: any, userA: any, userB: any, relayNode: any;
    let vClient: any, pClient: any;

    beforeEach(async function () {
        const { viem } = await (network as any).connect();
        vClient = viem;
        [admin, userA, userB, relayNode] = await vClient.getWalletClients();
        pClient = await vClient.getPublicClient();

        // 1. 部署环境
        catToken = await vClient.deployContract("CocoCatToken"); // 假设已有 ERC20
        cocoCore = await vClient.deployContract("CocoCatCore", [catToken.address as Address]);

        // 2. 初始资金注入
        await catToken.write.mint([userA.account.address, parseEther("100")], { account: admin.account });
        await catToken.write.approve([cocoCore.address, parseEther("100")], { account: userA.account });
    });

    it("完整业务流验证:生成 -> 锚定 -> 发现 -> 通讯签名 -> 结算", async function () {
        // --- 1. 生成 (Generation) ---
        // 模拟客户端生成影子密钥对的哈希
        const shadowPubKeyHash = keccak256(toHex("Shadow_Key_For_UserA"));

        // --- 2. 锚定 (Anchoring) ---
        await cocoCore.write.registerShadowIdentity([shadowPubKeyHash], { account: userA.account });
        console.log("✅ UserA 已完成影子身份锚定");

        // --- 3. 发现 (Discovery) ---
        // UserB 通过 UserA 的钱包地址找到其影子哈希,用于路由通讯
        const foundHash = await cocoCore.read.getShadowHash([userA.account.address]);
        assert.strictEqual(foundHash, shadowPubKeyHash, "UserB 未能发现正确的影子身份");
        console.log("✅ UserB 成功发现 UserA 的影子哈希:", foundHash);

        // --- 4. 通讯与签名 (Communication & Signing) ---
        // 用户 A 预存话费
        const depositAmt = parseEther("10");
        await cocoCore.write.deposit([depositAmt], { account: userA.account });

        // 用户 A 在发送消息给 B 时,签署给中继节点的小额支付凭证
        const settleAmt = parseEther("0.1"); // 每条/批消息费用
        const nonce = 0n;
        const chainId = await pClient.getChainId();

        const signature = await userA.signTypedData({
            domain: { name: "CocoCat_RelayX", version: "1", chainId, verifyingContract: cocoCore.address },
            types: { Settlement: [{ name: 'node', type: 'address' }, { name: 'amount', type: 'uint256' }, { name: 'nonce', type: 'uint256' }] },
            primaryType: 'Settlement',
            message: { node: relayNode.account.address, amount: settleAmt, nonce: nonce }
        });
        console.log("✅ UserA 已签署通讯服务凭证");

        // --- 5. 结算 (Settlement) ---
        // 中继节点提交凭证换钱
        const txHash = await cocoCore.write.settleWithSignature(
            [userA.account.address, settleAmt, nonce, signature],
            { account: relayNode.account }
        );
        await pClient.waitForTransactionReceipt({ hash: txHash });

        // 最终检查
        const nodeEarnings = await cocoCore.read.nodeBalances([relayNode.account.address]);
        assert.strictEqual(nodeEarnings, settleAmt, "节点未收到结算 CAT");
        
        const userRemaining = await cocoCore.read.userDeposits([userA.account.address]);
        assert.strictEqual(userRemaining, depositAmt - settleAmt, "用户余额扣减错误");
        console.log("✅ 全业务流程结算成功!");
    });

it("安全性测试:篡改影子身份锚定应失败", async function () {
    const realHash = keccak256(toHex("Real"));
    const fakeHash = keccak256(toHex("Fake_Hash"));

    // 1. 第一次锚定
    await cocoCore.write.registerShadowIdentity([realHash], { account: userA.account });
    
    // 2. 验证重复锚定会触发 revert
    try {
        // 直接尝试写入交易,而不是模拟
        await cocoCore.write.registerShadowIdentity([fakeHash], { 
            account: userA.account 
        });
        
        assert.fail("应当触发 Already anchored 错误但交易成功了");
    } catch (err: any) {
        // 在 Hardhat 中,如果 write 失败,错误信息通常直接存在 err.message 或 err.details 中
        const fullMessage = (err.details || err.shortMessage || err.message || "").toLowerCase();
        
        // 打印一下,方便调试时观察实际捕获到了什么
        // console.log("Captured full message:", fullMessage);

        // 使用不区分大小写的匹配,增加鲁棒性
        const isMatched = /already anchored/i.test(fullMessage) || /reverted/i.test(fullMessage);
        
        assert.ok(
            isMatched, 
            `预期的错误信息应包含 'Already anchored',实际捕获内容为: ${fullMessage}`
        );
    }
    console.log("✅ 安全性测试:拦截重复锚定成功");
});

});

四、部署脚本

javascript 复制代码
// scripts/deploy.js
import { network, artifacts } from "hardhat";
async function main() {
  // 连接网络
  const { viem } = await network.connect({ network: network.name });//指定网络进行链接
  
  // 获取客户端
  const [deployer] = await viem.getWalletClients();
  const publicClient = await viem.getPublicClient();
 
  const deployerAddress = deployer.account.address;
   console.log("部署者的地址:", deployerAddress);
  // 加载合约
  const CocoCatTokenArtifact = await artifacts.readArtifact("CocoCatToken");
  const CocoCatCoreArtifact = await artifacts.readArtifact("CocoCatCore");
    const CocoCatTokenHash = await deployer.deployContract({
      abi: CocoCatTokenArtifact.abi,//获取abi
      bytecode: CocoCatTokenArtifact.bytecode,//硬编码
      args: [],//process.env.RECIPIENT, process.env.OWNER
    });
    const CocoCatTokenReceipt = await publicClient.waitForTransactionReceipt({ hash: CocoCatTokenHash });
    console.log("CocoCatToken合约地址:", CocoCatTokenReceipt.contractAddress);
  // 部署(构造函数参数:recipient, initialOwner)
  const CocoCatCoreHash = await deployer.deployContract({
    abi: CocoCatCoreArtifact.abi,//获取abi
    bytecode: CocoCatCoreArtifact.bytecode,//硬编码
    args: [CocoCatTokenReceipt.contractAddress],
  });

  // 等待确认并打印地址
  const CocoCatCoreReceipt = await publicClient.waitForTransactionReceipt({ hash: CocoCatCoreHash });
  console.log("CocoCatCore合约地址:", CocoCatCoreReceipt.contractAddress);
}

main().catch(console.error);

五、 结语

CocoCat 的核心竞争力在于它不仅仅是一个聊天工具,而是一套去中心化的社交基础设施。通过将隐私身份锚定在链上,而将高频交互放在链下的中继网络,它在隐私、效率与成本之间找到了完美的平衡点。

对于开发者而言,理解其"链上存证、链下通讯、签名结算"的模式,是构建下一代大规模 Web3 应用的关键参考。

相关推荐
木西1 天前
深度拆解 Grass 模式:基于 EIP-712 与 DePIN 架构的奖励分发系统实现
web3·智能合约·solidity
Black_mario3 天前
Web3 时代的“伯克希尔”时刻:解析 Jason Hitchcock 与 Greenlane 的 Berachain 主权财库之路
web3
China_Yanhy3 天前
入职 Web3 运维日记 · 第 14 日:铸造无形钥匙 —— OIDC 与 CI/CD 施工实录
运维·web3
木西5 天前
深度解析|Form Network:BNX 迁移模块化 L2 的全流程技术实践
web3·智能合约·solidity
devmoon5 天前
区块链 Indexer 全解析:为什么 Web3 应用离不开数据索引器?(Polkadot / Ethereum / Solana 对比与未来展望)
rust·web3·区块链·以太坊·polkadot·solana·indexer
木西7 天前
STEPN相关内容延续篇:基于OpenZeppelinV5与Solidity0.8.24的创新点拆解
web3·智能合约·solidity
Lao乾妈官方认证唯一女友:D8 天前
wagmi使用方法
react.js·web3·wagmi
Lao乾妈官方认证唯一女友:D8 天前
Ethers.js使用方法
javascript·web3
木西8 天前
深度实战:用 Solidity 0.8.24 + OpenZeppelin V5 还原 STEPN 核心机制
web3·智能合约·solidity