前端特此声明:本文仅做项目技术拆解,不做项目投资推荐,投资有风险,入市需谨慎。在Web3.0浪潮中,社交赛道正经历从“数据垄断”到“主权回归”的范式转移。作为去中心化隐私社交应用的代表,CocoCat通过独特的影子身份协议(ShadowIdentity)与RelayX分布式中继网络,
特此声明:本文仅做项目技术拆解,不做项目投资推荐,投资有风险,入市需谨慎。在 Web3.0 浪潮中,社交赛道正经历从“数据垄断”到“主权回归”的范式转移。作为去中心化隐私社交应用的代表,CocoCat 通过独特的影子身份协议(Shadow Identity)与 RelayX 分布式中继网络,成功构建了一个既保护隐私又具备商业可持续性的社交生态。
本文将深入探讨 CocoCat 的核心技术点,并展示如何基于 Solidity 0.8.24 与 OpenZeppelin V5 实现其核心业务流。
CocoCat项目相关梳理
概述:CocoCat 是一个基于区块链的隐私社交平台,类“去中心化版的通讯软件”。
1. 它能做什么?
2. 核心特点(黑科技)
3. 项目风险
传统的社交软件通过手机号或中心化 ID 锚定用户,数据极易被追踪。CocoCat 引入了 “影子身份” :
为了解决去中心化网络中的通信效率与成本问题,CocoCat 采用了 RelayX 协议:
社交中继并非免费。CocoCat 巧妙地利用 EIP-712 类型化签名,实现了“链下授权、链上结算”的经济闭环。用户在发送消息时签署小额支付凭证,节点定期上链兑付,极大优化了 Gas 效率。
// 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);
}
}
// 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.rejects 和 simulateContract 捕获合约回滚,确保一个地址无法绑定多个影子身份,保护了系统身份的一致性。
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("✅ 安全性测试:拦截重复锚定成功");
});
});
// 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 应用的关键参考。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!