@cgentai/cgent-contracts
v1.0.0
Published
SDK for interacting with Cgent.AI Solidity contracts
Maintainers
Readme
P2P Escrow SDK 文档
本仓库提供一个用于点对点电商场景的资金托管合约 P2PEscrow.sol 以及与之配套的 TypeScript SDK,帮助买卖双方在交易过程中安全地锁定和释放资金。本文档覆盖以下内容:
- 合约设计概览与角色职责
- 订单生命周期及状态机
- 合约公开方法与事件说明
- 常量、费用与错误类型
- SDK 安装、初始化及常用调用示例
- 浏览器环境辅助方法
合约源码位置:
contracts/P2PEscrow.solSDK 入口:
src/index.ts(导出常量、类型与P2PEscrowClient)
1. 合约概览
P2PEscrow 合约主要面向买家(buyer)、卖家(seller)与仲裁者(arbitrator)三个角色:
- 买家:发起订单并预付代币;在没有争议时可以确认收货或撤回资金。
- 卖家:在确认收到款项后锁定订单;可在必要时退款或在锁定期后请求释放资金。
- 仲裁者:当订单进入争议流程时,负责裁定资金归属。
- 合约拥有者(owner):配置手续费接收地址、仲裁者和可用代币列表。
资金在订单创建时从买家转入合约,直至订单根据流程释放或退款。合约支持多个 ERC-20 代币,通过白名单管理支持的代币地址。
手续费设定为 1%(FEE_BPS = 100,基础为 10_000)。手续费统一转入 feeRecipient 地址,其余金额发放给卖家。
2. 订单状态机
合约使用 OrderStatus 枚举区分订单生命周期:
| 数值 | 状态名 | 说明 |
| --- | --- | --- |
| 0 | None | 默认状态(订单不存在)。 |
| 1 | BuyerPaid | 买家支付成功,订单已在合约中锁仓。 |
| 2 | SellerLocked | 卖家确认并锁定订单,开始计算锁定期(30 天)。 |
| 3 | SellerRefunded | 卖家将资金原路退回买家。 |
| 4 | SellerReleased | 订单释放给卖家(扣除手续费)。 |
| 5 | BuyerWithdrawn | 买家在卖家锁定前撤回资金。 |
| 6 | ArbitrationPending | 仲裁者介入,等待裁决。 |
| 7 | ArbitrationBuyer | 仲裁判定资金退回买家。 |
| 8 | ArbitrationSeller | 仲裁判定资金释放给卖家(扣除手续费)。 |
锁定期(LOCK_DURATION = 30 days)从卖家调用 lockOrder 时开始计算。锁定期届满后,卖家可调用 sellerRelease 将资金解锁给自己。
3. 合约方法
3.1 配置与查看
feeRecipient() -> address:查看手续费接收地址。arbitrator() -> address:查看当前仲裁者地址。owner() -> address:查看合约拥有者。supportedTokens(address token) -> bool:查询代币是否在支持列表。getOrderId(address buyer, address seller, uint256 orderId) -> bytes32:计算订单唯一 key。getOrder(address buyer, address seller, uint256 orderId) -> Order:获取订单结构体。orders(bytes32 orderKey) -> Order:通过订单 key 读取原始存储。
3.2 订单生命周期
createOrder(address buyer, address seller, uint256 orderId, uint256 amount, address token)- 仅买家调用;检查代币是否支持、金额>0、卖家非零地址;将
amount转入合约并创建订单。
- 仅买家调用;检查代币是否支持、金额>0、卖家非零地址;将
lockOrder(address buyer, uint256 orderId)- 仅卖家调用;要求状态为
BuyerPaid;锁定期开始计时,状态改为SellerLocked。
- 仅卖家调用;要求状态为
buyerWithdraw(address seller, uint256 orderId)- 买家在卖家锁定前随时撤回资金,状态变为
BuyerWithdrawn。
- 买家在卖家锁定前随时撤回资金,状态变为
sellerRefund(address buyer, uint256 orderId)- 卖家在
BuyerPaid或SellerLocked状态下可主动退款给买家,状态为SellerRefunded。
- 卖家在
buyerConfirmReceipt(address seller, uint256 orderId)- 买家在订单锁定后确认收货,触发
_releaseToSeller,将金额按费率拆分给卖家和手续费地址,状态变为SellerReleased。
- 买家在订单锁定后确认收货,触发
sellerRelease(address buyer, uint256 orderId)- 卖家在锁定期已结束后自助释放资金给自己;状态要求
SellerLocked且当前时间超过lockedUntil。
- 卖家在锁定期已结束后自助释放资金给自己;状态要求
3.3 仲裁流程
setArbitrationPending(address buyer, address seller, uint256 orderId)- 仅仲裁者调用;在
BuyerPaid或SellerLocked状态下进入仲裁,记录上一个状态。
- 仅仲裁者调用;在
cancelArbitration(address buyer, address seller, uint256 orderId)- 仲裁者撤消仲裁,将状态还原至进入仲裁前的状态。
arbitrate(address buyer, address seller, uint256 orderId, bool releaseToSeller)- 仲裁者最终裁决。
releaseToSeller = true时拆分手续费后转给卖家;否则原额退回买家。状态分别变更为ArbitrationSeller或ArbitrationBuyer。
- 仲裁者最终裁决。
3.4 管理员操作
setFeeRecipient(address newRecipient):合约拥有者更新手续费地址。setArbitrator(address newArbitrator):合约拥有者更新仲裁者。addSupportedToken(address token)/removeSupportedToken(address token):增删支持代币。transferOwnership(address newOwner)/renounceOwnership():标准 Ownable 权限管理。
3.5 内部逻辑
_releaseToSeller(Order storage order, bytes32 orderKey):私有函数,用于统一执行释放逻辑,计算手续费并发放资金。
4. 事件
合约定义的主要事件如下:
OrderCreated(orderKey, buyer, seller, orderId, token, amount)OrderLocked(orderKey, lockedUntil)BuyerWithdrawn(orderKey)SellerRefunded(orderKey)SellerReleased(orderKey, sellerAmount, feeAmount)ArbitrationPendingSet(orderKey)ArbitrationResolved(orderKey, releasedToSeller, amount, feeAmount)ArbitrationCancelled(orderKey, restoredStatus)FeeRecipientUpdated(newRecipient)ArbitratorUpdated(newArbitrator)SupportedTokenAdded(token)/SupportedTokenRemoved(token)
SDK 提供的 P2PEscrowClient 支持通过 on/once/off/removeAllListeners 订阅这些事件。
5. 常量与错误
LOCK_DURATION_SECONDS = 30 * 24 * 60 * 60:卖家锁定后需等待的秒数。FEE_BPS = 100 (1%),BPS_DENOMINATOR = 10_000:手续费计算使用amount * FEE_BPS / BPS_DENOMINATOR。- 关键错误:
InvalidToken(address):代币或地址无效。InvalidAmount():金额为零。OrderAlreadyExists():同一订单重复创建。Unauthorized():调用方角色不匹配。InvalidStatus():当前订单状态不允许执行操作。LockPeriodActive(uint256):卖家释放时锁定期尚未到期。NothingToRelease():订单金额为零。
6. SDK 使用指南
SDK 基于 ethers@^6,在 Node.js、浏览器或任意支持 ESM/CJS 的环境中均可使用。
6.1 安装
npm install @cgentai/cgent-contracts ethers
# 或者使用 pnpm / yarn6.2 初始化客户端
import { JsonRpcProvider } from "ethers";
import { P2PEscrowClient } from "@cgentai/cgent-contracts";
const provider = new JsonRpcProvider("https://rpc.sepolia.linea.build");
const signer = await provider.getSigner(); // 也可以用 wallet.connect(provider)
const escrow = new P2PEscrowClient({
address: "0xEscrowAddress",
runner: signer,
});
console.log(await escrow.getFeeRecipient());P2PEscrowClient.connect(address, runner) 提供了便捷的静态初始化方法。
6.3 浏览器环境
import { createP2PEscrowClientFromBrowser } from "@cgentai/cgent-contracts";
const escrow = await createP2PEscrowClientFromBrowser({
provider: window.ethereum,
address: "0xEscrowAddress",
accountIndex: 0, // 可选,默认 0
});
const account = await escrow.getRunnerAddress();6.4 创建订单
const buyerAddress = await escrow.getRunnerAddress();
await escrow.createOrder({
buyer: buyerAddress!,
seller: "0xSellerAddress",
orderId: 1n,
amount: 1000n * 10n ** 6n, // 以最小单位传值
token: "0xUSDC",
});在调用前确保买家钱包已对合约执行 ERC20.approve 授权。
6.5 卖家操作
// 卖家确认锁定
await escrow.withRunner(sellerSigner).lockOrder({
buyer: buyerAddress!,
orderId: 1n,
});
// 卖家等待锁定期结束后释放
await escrow.withRunner(sellerSigner).sellerRelease({
buyer: buyerAddress!,
orderId: 1n,
});
// 或者在需要时退款
await escrow.withRunner(sellerSigner).sellerRefund({
buyer: buyerAddress!,
orderId: 1n,
});6.6 买家确认或撤回
// 买家确认收货
await escrow.withRunner(buyerSigner).buyerConfirmReceipt({
seller: "0xSellerAddress",
orderId: 1n,
});
// 买家在卖家锁定前撤回
await escrow.withRunner(buyerSigner).buyerWithdraw({
seller: "0xSellerAddress",
orderId: 1n,
});6.7 仲裁流程
// 仲裁者设置仲裁中
await escrow.withRunner(arbitratorSigner).setArbitrationPending({
buyer: buyerAddress!,
seller: "0xSellerAddress",
orderId: 1n,
});
// 最终裁决:true 释放给卖家(扣除手续费),false 退给买家
await escrow.withRunner(arbitratorSigner).arbitrate({
buyer: buyerAddress!,
seller: "0xSellerAddress",
orderId: 1n,
releaseToSeller: true,
});6.8 查询订单与辅助函数
const order = await escrow.getOrder({
buyer: buyerAddress!,
seller: "0xSellerAddress",
orderId: 1n,
});
console.log(order.status); // OrderStatus 枚举值
const { feeAmount, sellerAmount } = P2PEscrowClient.calculateFee(order.amount);SDK 返回的 ResolvedOrder 将合约中的 uint256 转换为 bigint,可直接参与 JS/TS 计算。
7. 事件监听
P2PEscrowClient 继承了 TypeChain 的事件类型,可在 TypeScript 中获得强类型支持:
import type { P2PEscrow } from "@cgentai/cgent-contracts/typechain-types";
escrow.on(escrow.contract.filters.OrderCreated(), (orderKey, buyer, seller, orderId) => {
console.log("New order", { orderKey, buyer, seller, orderId: orderId.toString() });
});
// 取消监听
escrow.removeAllListeners(escrow.contract.filters.OrderCreated());8. 部署与网络
deployments/ 目录中存放了示例部署信息(例如 P2PEscrow-84532.json 对应于 Linea Sepolia 测试网)。使用 SDK 时请根据实际网络配置合约地址与 RPC 节点。
9. 开发与测试
- 本仓库基于 Hardhat,测试脚本位于
test/目录,可运行pnpm test或npx hardhat test。 - 若需自建环境,可使用
pnpm deploy(具体脚本请参考package.json)。 - 修改合约或 SDK 后,请重新编译生成 TypeChain 类型:
pnpm build。
如需更多帮助或功能扩展,欢迎提交 Issue 或 PR。
