众筹: 使用CKB作为资金媒介完全由TypeScript开发

项目介绍

这是一个以 CKB 作为资金媒介 的众筹示例项目,包含On-Chain Script、dApp 与测试代码。创建者可以在链上发起众筹,支持者通过链上交易进行捐款;若众筹目标在规定时间内达成,资金按规则汇入创建者指定账户;若超过截止日期未达成筹款目标,资金将按原路径返还给支持者。整个过程中,核心操作均在链上完成,保证流程 分布式公开透明

从开发者角度看,本项目 全栈使用 TypeScript 开发,并结合CKB since 机制引入时间约束,用于实现到期前结算\到期后退款的逻辑。

Github: joii2020/crowdfunding

(dApp - Testnet 链接在Github about 中)

注意:

  • 本项目仅用于演示/教学,请勿直接用于生产环境
  • 当前仅支持使用 CKB capacity 作为筹资资金
  • Deadline 使用链上时间模型(since),它并不是现实世界的“秒级闹钟”

亮点

  • 纯 JS/TS 合约:Project / Contribution / Claim 三个 On-Chain Script 均使用 TypeScript 编写,并通过 ckb-js-vm 在链上执行
  • 完整流程覆盖:内置 Jest + ckb-testtool 模拟测试,覆盖创建项目、捐赠、合并、成功结算与失败退款等关键路径
  • 便捷的调用封装:提供常用交易拼装函数与工具方法,便于快速构建、发送交易并复用业务逻辑
  • 前后端一体app/ 为 Next.js 前端,可直接连接已部署合约;examples/ 提供 off-chain 脚本示例,便于演示与集成
  • 引入时间概念:基于 since 为众筹流程引入链上时间约束,将 Deadline 前的结算路径Deadline 后的退款路径 明确区分,展示在 CKB 上实现 time-lock 与业务状态机的一种实现方式

项目简介

这是一个基于 CKB 的众筹平台示例:

发起人创建项目并设置目标金额与截止时间;捐赠者通过 Contribution 锁定资金。为了降低最终结算交易的体积与成本,发起人(或任何第三方)可以合并同一项目下的 Contribution。若在 Deadline 前达成目标,发起人通过 Project 脚本领取资金;若在 Deadline 后仍未完成结算,则视为失败,捐赠者可通过 Claim 脚本按原路径退款。

本项目用 TypeScript 贯穿链上脚本、前端 dApp 与示例脚本,展示了构建、部署、交互与结算的一整套流程。

docs/design-zh.md

快速使用

编译依赖:

  • Node.js v20+
  • pnpm
  • ckb-debugger:用于编译 JS 合约并运行测试
  • offckb:用于部署合约;如果需要在 devnet 中测试,同样会用到

若仅在 testnet 运行 dApp,可暂时不安装/不关注 ckb-debugger 与 offckb。

pnpm install
pnpm run build       # 构建所有合约
pnpm run deploy      # 部署到 devnet(可加 --network testnet/mainnet)

目前已部署在 artifacts/deployment/scripts.json

scripts.json
{
“claim.bc”: {
“codeHash”: “0x66cce698ae0fbe90821a96dbf823b3ed9464488c289316df59988dc0ac738bb2”,
“hashType”: “data2”,
“cellDeps”: \[
{
“cellDep”: {
“outPoint”: {
“txHash”: “0xec75cd19b0bb38039b30b23047810437486759041477f0f65b796d1b8637a056”,
“index”: 0
},
“depType”: “code”
}
}
\]
},
“contribution.bc”: {
“codeHash”: “0x8371fddfa86bc4d87b9a3d86b997a03498343ac4fd6b42e3c4fa4c4b765a231b”,
“hashType”: “data2”,
“cellDeps”: \[
{
“cellDep”: {
“outPoint”: {
“txHash”: “0x9731ae1df645da1a12d575791e84eb15d1a93969cd9131aa153dee5a362723b3”,
“index”: 0
},
“depType”: “code”
}
}
\]
},
“project.bc”: {
“codeHash”: “0xfb3fff95a1b214d1176f2a21f962d596243380fdb03359948f3cb4d61d41b6e1”,
“hashType”: “data2”,
“cellDeps”: \[
{
“cellDep”: {
“outPoint”: {
“txHash”: “0xb735195d147115fd97f40f168d6742104f756860b7d3a2edc872fab35656a1f6”,
“index”: 0
},
“depType”: “code”
}
}
\]
}
}

运行示例(创建项目 → 接受捐赠 → 合并 → 结算),默认使用 devnet:

执行前需要配置 .env.example

pnpm run example

启动 dApp:

dApp 默认使用 CKB testnet。若希望在 devnet 下运行,可通过 offckb node 快速创建 devnet,同时需要修改 shared/src/utils/env.ts:15

pnpm run app:dev

下面是两笔已完成流程的链上交易:

  • 发起众筹(创建 Project Cell)TxHash:0xf38b27b490de800e60ce19bec3e055871507ef0a27d192b5c309f4fa66b42c4d
  • 完成众筹(Deadline 前筹集足够资金并支付给 Creator) TxHash:0x70c5c3c256033f4a1ca951d711ebb709eeb624b58c6d8256f2f934389d106b9c

合约设计

本项目使用 CKB capacity 作为资金单位进行众筹与结算。

  • Project(type script):Project Cell 的 args 定义发起人 lock hash、目标金额、截止时间,并包含引用的 Contribution / Claim 脚本哈希。脚本校验规则:

    1. 仅当累计 Contribution 金额 ≥ 目标金额 才可视为达标
    2. 必须在 Deadline 之前 完成结算;Deadline 过期后即使已筹够资金但未完成结算,也会被视为失败
    3. 成功结算时,输出中必须包含 一笔支付给发起人 的转账
    4. 众筹失败后允许回收/解锁 Project Cell(由该 Cell 的 lock script 决定最终花费权限)
    5. args 中包含 Contribution 与 Claim 的 CodeHash/HashType,用于约束捐款/退款路径不可被伪造
    6. 使用 Type ID,保证每个项目具备唯一性且不可伪造
  • Contribution(lock script):锁定单个捐赠者资金。args 包含 Project Script Hash、Deadline,以及 Claim 的 CodeHash/HashType。脚本规则:

    1. 同一 Project 下的多笔捐款可合并为一笔,并保持 capacity 守恒
    2. Deadline 之前禁止走退款路径(防止提前撤资)
    3. 成功结算时只能由 Project 脚本 消费
    4. 失败退款交易中必须包含捐款对应的 Claim(因为退款时 Project 可能已经被销毁,因此 Claim 信息需要在 args 中保留)

    捐赠者通过 Contribution 锁定资金;发起人(或任何第三方)可合并同一项目下的 Contribution,以压缩最终结算交易体积(合并会产生手续费,因此发起人通常有动力提前合并,避免临近 Deadline 时 Contribution Cell 过碎导致结算困难)。

  • Claim(lock script):代表可退款凭证。args 为 Project type hash + 捐赠者 lock hash。脚本校验:

    1. 仅在 Deadline 过期后 才可销毁
    2. 可配合 lock script 使用以保护其自身安全
    3. 执行退款时必须按源路径(Lock Script Hash)退回

退款时,如果此前 Contribution 已经被合并,仍可使用该项目下任意 Contribution 来提取 Claim 中记录的 capacity 并完成退款。

shared 模块设计

  • 核心目标:提供一层纯 TS SDK,将链上三脚本(Project / Contribution / Claim)与 dApp / 示例脚本解耦,复用交易拼装、编码与链上查询逻辑(供 example / 测试 / dApp 使用)
  • 环境与依赖utils/env.ts 读取 REACT_APP_CKB_NETWORK,按网络返回所需的 on-chain script(codeHash / cellDep);链上交互基于 @ckb-ccc/core
  • 参数与工具args.ts 封装 Project / Contribution / Claim 的 args 编解码;index.ts 提供金额换算、Hex 拼接、Since 与 Date 转换等通用工具
  • 链上状态chainState.ts 通过脚本哈希查询活跃/历史 Cells,解析 Project 状态、已筹金额、截止时间及 contribution/claim 列表,用于前端展示
  • 交易动作crowdfundingActions.ts 提供创建项目、捐赠、合并捐赠、成功结算、退款、销毁等高阶函数;内部统一调用 sendTx.ts 处理 since、fee、typeId 自动补全,确保脚本约束被正确满足
  • 开发辅助devTools.ts 提供快速构造链上场景的工具(如一键创建项目并注入多笔捐赠),方便本地与测试网演示调试

用户可以参考示例脚本:
examples/src/simple-success.ts

8 Likes

赞! 今年CKCON我们有讨论过在CKBoost(开源项目!)里增加众筹的模块,感觉可以考虑一下集成

4 Likes