mcpField
O
opnet-development

opnet-development

github.com/btc-vision开发080 次安装38 周前更新
代码仓库

关于 opnet-development

opnet-development 是用于构建 OPNet 项目的开发技能,涵盖智能合约和前端。它引导 Agent 按任务查阅文档,并规定实现、安全、测试和部署流程。

主要功能

  1. 01按任务查阅文档的流程
  2. 02智能合约与前端开发指南
  3. 03OP_WALLET 集成要求
  4. 04合约模拟与安全检查
  5. 05Lint、类型检查和构建要求

适用场景

  1. 01规划 OPNet 智能合约项目
  2. 02构建连接合约的前端
  3. 03检查交易安全与实现模式

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/btc-vision/opnet-skills --skill opnet-development

安装后在 Claude Code 中输入/opnet-development确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

docs/
asconfig.json
clients-bip32-QUANTUM.md
clients-bitcoin-address.md
clients-bip32-README.md
clients-ecpair-README.md
clients-bitcoin-payments.md
clients-bitcoin-transaction.md
clients-bitcoin-psbt.md
clients-bitcoin-README.md
clients-bitcoin-script.md
clients-walletconnect-README.md
contracts-as-bignum-README.md
contracts-btc-runtime-advanced-cross-contract-calls.md
contracts-btc-runtime-README.md
contracts-btc-runtime-advanced-contract-upgrades.md
contracts-btc-runtime-advanced-quantum-resistance.md
contracts-btc-runtime-advanced-signature-verification.md
contracts-btc-runtime-api-reference-blockchain.md
clients-walletconnect-wallet-integration.md
contracts-btc-runtime-advanced-bitcoin-scripts.md
contracts-btc-runtime-advanced-plugins.md
contracts-btc-runtime-api-reference-events.md
contracts-btc-runtime-api-reference-op721.md
contracts-btc-runtime-api-reference-op20.md
contracts-btc-runtime-contracts-op-net-base.md
contracts-btc-runtime-api-reference-storage.md
contracts-btc-runtime-api-reference-safe-math.md
contracts-btc-runtime-contracts-op20-token.md
contracts-btc-runtime-contracts-reentrancy-guard.md
contracts-btc-runtime-contracts-op721-nft.md

详细介绍

OPNet 开发技能

用于在 OPNet 上进行开发的综合技能。OPNet 是用于无信任智能合约的 Bitcoin L1 共识层。


步骤 1:先了解用户的需求

在阅读任何文档或指南之前,必须先了解用户的请求。

  1. 仔细阅读用户的消息
  2. 确定用户需要哪种类型的项目(合约、前端、后端、插件、审计或问题)
  3. 如果请求含糊不清,请提出澄清问题
  4. 只有在此之后,才开始阅读该项目类型对应的文档

不要不加判断地开始阅读所有文档。先了解任务,再只阅读相关文档。


步骤 2:编写任何代码之前必须阅读

如果不阅读必需的文档就编写代码,你会创建出有缺陷、可被利用的代码。


AI Agent 的关键规则

绝对规则——禁止使用原生 JavaScript

绝不编写原生 JavaScript。始终使用:

  • 前端:TypeScript + Vite + npm 包
  • 后端:TypeScript + Node.js + npm 包
  • 没有例外,连“快速示例”也不行。
不要:
  • 只阅读几个文件就说“我已经掌握了足够的背景信息”
  • 阅读项目类型列表中未列出的随机技能或指南
  • 只浏览 2-3 个文件就开始编写代码
  • 假设自己了解其他框架中的 OPNet 模式
  • 因为某些文件“看起来和已读文件相似”就跳过它们
  • 未运行 npm run lint 和 npm run typecheck 就创建 zip 文件或交付成果
  • 只说“运行 npm run lint 进行验证”,而不实际运行
必须:
  • 阅读下方为项目类型列出的每一个文件
  • 按顺序阅读——后面的文件依赖前面的文件
  • 阅读完整文件,而不只是前几个章节
  • 只阅读本技能中列出的文件——不要随意探索其他内容
  • 在编写任何代码之前,确认已阅读完所有文件
  • 实际运行 npm install、npm run lint、npm run typecheck、npm run build
  • 创建任何交付成果(zip、PR 等)之前,修复所有错误

强制工作流规则

1. 先构建合约,再构建前端

当用户要求构建一个与智能合约交互的网站/dApp 时,必须先构建 .wasm 合约,再构建前端。

工作流顺序:

  1. 构建并编译 AssemblyScript 智能合约 → 确认 .wasm 输出存在
  2. 运行合约测试,确保正确性
  3. 然后构建与该合约交互的前端

绝不要构建引用尚不存在的合约的前端。

2. 钱包集成:始终使用 @btc-vision/opwallet

所有 OPNet 网站都必须使用 @btc-vision/opwallet 集成 OP_WALLET。

OP_WALLET 是唯一官方钱包,能够全面支持 OPNet 功能(MLDSA 签名、抗量子密钥和完整的 OPNet 集成)。每个前端 dApp 都必须集成它。

3. VITE 为强制要求——没有例外

**所有前端项目都必须使用 Vite 作为构建工具。**不得使用 webpack、parcel、独立 rollup 或独立 esbuild。只能使用 Vite。

4. IPFS 部署:仅使用 OPNET-CLI

发布到 IPFS 时:

  1. 使用 Vite 构建:npm run build(生成 dist/ 文件夹)
  2. 输出内容为静态 HTML + JS + CSS 文件
  3. 使用 opnet-cli IPFS 上传脚本上传:
    • 仅上传到 IPFS(不使用域名): bash /root/openclaw/skills/opnet-cli/scripts/ipfs-upload.sh ./dist
    • 上传并发布到 .btc 域名: bash /root/openclaw/skills/opnet-cli/scripts/ipfs-upload.sh ./dist mysite
    • 试运行(上传但不在链上发布): bash /root/openclaw/skills/opnet-cli/scripts/ipfs-upload.sh ./dist mysite --dry-run
  4. 网站必须是完整的静态网站——不得使用服务端渲染或 API 路由
  5. 所有合约交互都通过 OPNet provider 在客户端进行

vite build 后的 dist/ 文件夹包含部署到 IPFS 所需的全部内容。

上传脚本会返回包含 CID 和网关 URL 的 JSON:

{
  "cid": "QmXyz...",
  "files": 12,
  "totalSize": 245000,
  "gateway": "https://ipfs.opnet.org/ipfs/QmXyz..."
}

禁止使用以下 IPFS 方法——绝不可使用:

  • ❌ 本地 IPFS 守护进程(Kubo)——不得运行 ipfs add、ipfs pin 或任何本地 Kubo 命令
  • ❌ ipfs-website 技能——此技能已弃用并删除
  • ❌ 直接向 IPFS API 发送 HTTP 请求——不得使用 curl、fetch 或向 IPFS 端点发送任何原始 HTTP 请求
  • ❌ 逐个上传文件——该脚本会通过适当的分块处理目录上传
  • ❌ 除上述 opnet-cli 脚本外的任何 IPFS 上传方法

所有 IPFS 上传一律使用 bash /root/openclaw/skills/opnet-cli/scripts/ipfs-upload.sh。没有例外。


常见的 Agent 错误——不要重蹈覆辙

以下是在多个 AI Agent 中观察到的真实错误。如果你犯了其中任何一个错误,代码就会出问题。

错误错误原因正确做法
使用 Keccak256 选择器(EVM 风格)OPNet 使用的是 SHA256,而不是 Keccak256。这是 Bitcoin,不是 Ethereum。所有哈希和方法选择器都使用 SHA256
对 OP-20 代币调用 approve()OP-20 没有 approve()。它使用 increaseAllowance() / decreaseAllowance() 来防止众所周知的 approve 竞态条件。使用 increaseAllowance(spender, amount) 和 decreaseAllowance(spender, amount)
将 bc1p... 地址传给 Address.fromString()Address.fromString() 接受两个十六进制公钥参数,而不是 Bech32 地址字符串Address.fromString(hashedMLDSAKey, tweakedPublicKey)——两者都必须是十六进制字符串
使用 bitcoinjs-libOPNet 有自己的 Bitcoin 库,其中包含关键补丁,PSBT 速度快 709 倍使用 @btc-vision/bitcoin——绝不要使用 bitcoinjs-lib
使用工厂部署子合约的模式OPNet 合约无法部署其他合约。这里没有 CREATE 或 CREATE2 操作码。分别部署每个合约,然后通过存储的地址将它们关联起来
在 sendTransaction() 之前跳过模拟Bitcoin 转账不可撤销。如果合约回滚,你的 BTC 就没了。务必先模拟:调用 contract.method() 进行模拟,确认成功后再调用 result.sendTransaction(params)
后端使用 Express/Fastify/Koa这些框架是禁止使用的,而且速度明显更慢。只能使用 @btc-vision/hyper-express 和 @btc-vision/uwebsocket.js
设置后未运行 npm-check-updates软件包版本不断变化。版本过时就会导致构建失败。务必运行 npx npm-check-updates -u && npm i eslint@^9.39.2 @eslint/js@^9.39.2 ...(参见 Install Commands 部分)
未提供弃用警告就让用户使用 verifyECDSASignature 或 verifySchnorrSignatureECDSA 和 Schnorr 均已弃用。ECDSA 受 UNSAFE_QUANTUM_SIGNATURES_ALLOWED 限制,当共识切换该标志时将无法使用。Schnorr 也已弃用,但仍可通过安全的 verifySignature 路径使用。直接把已弃用的方法交给用户而不发出警告,会让他们面临合约故障。务必先警告:ECDSA 和 Schnorr 均已弃用。明确指出 Blockchain.verifySignature(address, signature, hash) 是唯一正确的做法——它能感知共识状态,并自动选择正确的算法(目前为 Schnorr,强制启用后为 ML-DSA)。绝不要直接引导用户使用 verifyECDSASignature、verifyBitcoinECDSASignature 或 verifySchnorrSignature。请阅读 guidelines/ethereum-migration-guidelines.md 第 3 节。
使用 MessageSigner.signMessage() 或 signMLDSAMessage(),而不是 Auto 方法非 Auto 方法因环境而异。signMessage() 仅适用于本地密钥对(后端),signMLDSAMessage() 仅适用于 OP_WALLET(浏览器)。用错方法会导致运行时崩溃。务必使用 Auto 方法:MessageSigner.signMessageAuto()、tweakAndSignMessageAuto()、signMLDSAMessageAuto()。这些方法会自动检测你是在浏览器(OP_WALLET)还是后端(本地密钥对),并调用正确的底层方法。除非有明确理由且了解当前环境,否则绝不要使用非 Auto 变体。

如果发现自己犯了上述任何错误,请立即停下来并修正。


这为何重要

OPNet 开发涉及:

  • 经常变化的 Beta 软件包版本——猜测版本会导致构建失败
  • 严格的 TypeScript 规则——违反规则会造成安全漏洞
  • 平台特定模式——模式错误会导致漏洞、Gas 攻击和数据丢失

指南只是摘要。docs/ 文件夹才包含实际的实现模式。

只阅读 3 到 4 个文件远远不够。你必须阅读适用于项目类型的所有文件。


按项目类型规定的必读顺序

所有项目(每次都先阅读)
顺序文件原因
1docs/core-typescript-law-CompleteLaw.md规则——类型系统规则、禁止的结构、必需的模式
2guidelines/setup-guidelines.md软件包版本、tsconfig、ESLint 配置

智能合约(AssemblyScript)

编写合约代码前,请阅读以下所有内容:

顺序文件内容
1docs/core-typescript-law-CompleteLaw.md类型规则(同样适用于 AS)
2guidelines/setup-guidelines.md软件包版本、asconfig.json
3guidelines/contracts-guidelines.md合约模式概要
4docs/contracts-btc-runtime-README.md运行时概览
5docs/contracts-btc-runtime-getting-started-installation.md设置
6docs/contracts-btc-runtime-getting-started-first-contract.md入口点、工厂模式
7docs/contracts-btc-runtime-getting-started-project-structure.md目录结构
8docs/contracts-btc-runtime-core-concepts-storage-system.md存储类型、指针
9docs/contracts-btc-runtime-core-concepts-pointers.md指针分配
10docs/contracts-btc-runtime-api-reference-safe-math.mdSafeMath(u256 必须使用)
11docs/contracts-btc-runtime-gas-optimization.mdGas 模式、禁止的循环
12docs/contracts-btc-runtime-core-concepts-security.md安全检查清单

对于 OP20 代币,还需阅读:

  • docs/contracts-btc-runtime-api-reference-op20.md
  • docs/contracts-btc-runtime-contracts-op20-token.md

对于 OP721 NFT,还需阅读:

  • docs/contracts-btc-runtime-api-reference-op721.md
  • docs/contracts-btc-runtime-contracts-op721-nft.md

前端(React/Vite)

编写前端代码前,请阅读以下所有内容:

顺序文件内容
1docs/core-typescript-law-CompleteLaw.md类型规则、禁止的结构
2guidelines/setup-guidelines.md软件包版本、Vite 配置
3guidelines/frontend-guidelines.md前端模式概要
4docs/core-opnet-README.md客户端库概览
5docs/core-opnet-getting-started-installation.md安装
6docs/core-opnet-getting-started-quick-start.md快速入门
7docs/core-opnet-providers-json-rpc-provider.mdProvider 设置
8docs/core-opnet-providers-internal-caching.md缓存(必须阅读)
9docs/core-opnet-contracts-instantiating-contracts.md合约实例
10docs/core-opnet-contracts-simulating-calls.md读取操作
11docs/core-opnet-contracts-sending-transactions.md写入操作
12docs/core-opnet-contracts-transaction-configuration.md交易选项
13docs/core-transaction-transaction-factory-interfaces.md高级 TX 参数(费用、备注、锚点)
14docs/clients-walletconnect-README.md钱包连接
15docs/frontend-motoswap-ui-README.md标准——参考实现

后端/API(Node.js)

编写后端代码前,请阅读以下所有文件:

顺序文件内容
1docs/core-typescript-law-CompleteLaw.md类型规则、禁止使用的构造
2guidelines/setup-guidelines.md软件包版本
3guidelines/backend-guidelines.md后端模式概要
4docs/core-opnet-backend-api.md必需框架——hyper-express、uWebSockets.js
5docs/core-opnet-providers-json-rpc-provider.mdProvider 设置
6docs/core-opnet-providers-threaded-http.md线程处理(强制要求)
7docs/core-opnet-providers-internal-caching.md缓存(强制要求)
8docs/core-opnet-contracts-instantiating-contracts.md合约实例
9docs/core-opnet-contracts-sending-transactions.md发送交易
10docs/core-transaction-transaction-factory-interfaces.md高级交易参数(费用、备注、锚点)

禁止使用的框架: Express、Fastify、Koa、Hapi、Socket.io——仅使用 hyper-express 和 uWebSockets.js。


插件(OPNet Node)

编写插件代码前,请阅读以下所有文件:

顺序文件内容
1docs/core-typescript-law-CompleteLaw.md类型规则、禁止使用的构造
2guidelines/setup-guidelines.md软件包版本
3guidelines/plugin-guidelines.md插件模式概要
4docs/core-OIP-OIP-0003.md插件规范——完整规范
5docs/plugins-plugin-sdk-README.mdSDK 参考
6docs/plugins-opnet-node-README.md节点集成

**重要:**必须实现 onReorg() 来处理链重组,否则数据将不一致。


单元测试(TypeScript)

编写测试代码前,请阅读以下所有文件:

顺序文件内容
1docs/core-typescript-law-CompleteLaw.md类型规则
2guidelines/setup-guidelines.md软件包版本
3guidelines/unit-testing-guidelines.md测试模式概要
4docs/testing-unit-test-framework-README.md框架概述
5docs/testing-opnet-unit-test-README.md测试设置
6docs/testing-opnet-unit-test-docs-Blockchain.md区块链模拟
7docs/testing-opnet-unit-test-docs-ContractRuntime.md合约运行时

**重要:**单元测试使用 TypeScript(不是 AssemblyScript),并且有单独的 package.json。


对于一般性问题(架构、概念、最佳实践)

阅读: guidelines/generic-questions-guidelines.md

适用于以下问题:

  • “OPNet 如何运作?”
  • “OPNet 能抵御 51% 攻击吗?”
  • “OPNet 上的空投如何运作?”
  • “OPNet 与 Runes/Ordinals 有何区别?”
  • “为什么合约不能持有 BTC?”
  • “什么是交易钉死?”
  • “OPNet 与 Ethereum 有何不同?”
  • “如何将我的 Solidity 合约迁移到 OPNet?”
  • “OPNet 上与 ecrecover 等效的是什么?”

请参阅完整指南,了解完整的主题映射,以及针对每种问题类型应阅读哪些文档。

**对于 Ethereum 迁移问题:**阅读 guidelines/ethereum-migration-guidelines.md——其中涵盖从 Ethereum 到 OPNet 的概念映射(地址、签名、代币、钱包、交易、DEX 模式)。

关键——ecrecover / ECDSA / Schnorr / 签名验证问题: 当用户询问 ecrecover、ECDSA、Schnorr 或签名验证时,你必须:

  1. 首先警告:ECDSA 和 Schnorr 在 OPNet 上都已弃用。当共识禁用 UNSAFE_QUANTUM_SIGNATURES_ALLOWED 时,ECDSA 将失效。Schnorr 也已弃用,但仍可通过安全的 verifySignature 路径使用。
  2. 展示唯一正确的方法:Blockchain.verifySignature(address, signature, hash)——此方法能够感知共识状态、自动选择正确的算法(目前为 Schnorr,强制启用后为 ML-DSA),并且是唯一面向未来的方法。
  3. 仅展示客户端自动签名方法:MessageSigner.signMessageAuto() / tweakAndSignMessageAuto() / signMLDSAMessageAuto()。这些方法会自动检测环境是浏览器(OP_WALLET)还是后端(本地密钥对),并调用正确的方法。绝不要使用非 Auto 变体(signMessage()、signMLDSAMessage()、tweakAndSignMessage())——这些方法依赖特定环境,在错误的环境中会导致崩溃。
  4. 绝不要直接向用户推荐 verifyECDSASignature、verifyBitcoinECDSASignature 或 verifySchnorrSignature。这些都是已弃用的内部方法。
  5. 回答前阅读 guidelines/ethereum-migration-guidelines.md 第 3 节。

不要只给用户已弃用的 API 或依赖特定环境的签名方法。他们的代码一定会出问题。合约端应使用 verifySignature,客户端应使用 *Auto() 方法。

重要:对于概念性问题,回答前请先阅读相关文档/章节。不要猜测或擅自假设 OPNet 的工作方式。


对于安全审计

停止——进行任何审计前必须阅读

如果不阅读必需的文档就审计代码,你将错过关键漏洞。

OPNet 审计需要了解:

  • AssemblyScript 运行时内部机制——序列化、存储、缓存一致性
  • Bitcoin 特有的攻击向量——交易钉死、可塑性、链重组
  • 关键漏洞模式——标准审计会完全漏掉这些模式

审计任何代码前,你必须完整阅读 guidelines/audit-guidelines.md。

跳过审计指南就会漏掉漏洞。没有捷径。


免责声明(每份报告都必须包含)
IMPORTANT DISCLAIMER: This audit is AI-assisted and may contain errors,
false positives, or miss critical vulnerabilities. This is NOT a substitute
for a professional security audit by experienced human auditors.
Do NOT deploy to production based solely on this review.
Always engage professional auditors for contracts handling real value.

审计必读顺序

开始任何审计前,必须按顺序阅读以下所有内容:

顺序文件必读原因
1docs/core-typescript-law-CompleteLaw.md定义安全代码的类型规则
2guidelines/audit-guidelines.md完整审计指南——漏洞模式、检查清单、检测方法

然后根据代码类型阅读:

代码类型其他必读内容
智能合约docs/contracts-btc-runtime-core-concepts-security.md、docs/contracts-btc-runtime-gas-optimization.md、docs/contracts-btc-runtime-api-reference-safe-math.md、docs/contracts-btc-runtime-types-bytes-writer-reader.md
DEX/Swap 代码此 SKILL.md 中的 CSV、NativeSwap、Slashing 章节
前端guidelines/frontend-guidelines.md
后端guidelines/backend-guidelines.md
插件guidelines/plugin-guidelines.md——重组处理章节

审计验证检查点

在撰写任何审计发现之前,请确认:

  • 我已完整阅读 guidelines/audit-guidelines.md
  • 我已完整阅读 docs/core-typescript-law-CompleteLaw.md
  • 我已阅读此代码类型所需的所有其他文档
  • 我理解“关键运行时漏洞模式”章节
  • 我理解序列化/反序列化一致性要求
  • 我理解存储系统的缓存一致性问题
  • 我理解比特币特定的攻击向量(CSV、交易钉扎、重组)

如果无法勾选所有选项,请返回并阅读相关文档。


智能合约审计检查清单(摘要)

完整检查清单及检测模式请参阅 guidelines/audit-guidelines.md。

类别检查内容
算术运算所有 u256 运算均使用 SafeMath(不得直接使用 +、-、*、/)
溢出/下溢SafeMath.add()、SafeMath.sub()、SafeMath.mul()、SafeMath.div()
访问控制检查 onlyOwner,对敏感方法进行授权
重入外部调用前更改状态(检查-效果-交互模式)
Gas/循环不使用 while 循环,所有 for 循环均有界,不进行无界迭代
存储不遍历所有 map 键;总量使用已存储的聚合值
输入验证验证所有用户输入并检查边界
整数处理大数值通过 fromString() 创建 u256,不使用算术运算
序列化写入/读取类型保持一致,sizeof() 映射正确
缓存一致性比较前先从存储加载数据
删除标记存储删除使用 32 字节 EMPTY_BUFFER
边界检查最大索引检查使用 >= 而非 >
TypeScript/前端/后端审计检查清单(摘要)
类别检查内容
类型安全不使用 any、非空断言(! 运算符)或 @ts-ignore
空值安全显式检查 null,并正确使用可选链
BigInt所有聪金额/代币金额均使用 bigint,而非 number
不使用浮点数财务计算不使用浮点数
缓存缓存 Provider/合约实例,不要重复创建
输入验证验证地址、金额并检查边界
错误处理捕获并处理错误,不允许静默失败
Provider 类型使用 JSONRpcProvider(WebSocketProvider 仍处于实验阶段)
Bitcoin 专项审计清单(摘要)
类别检查项
CSV 时间锁所有交换接收地址都使用 CSV(防止 pinning)
UTXO 处理正确选择 UTXO,避免产生粉尘输出
交易可塑性确认前不得假定签名不可变
手续费狙击正确处理 locktime
重组处理删除或回滚重组区块的数据
P2WPKH仅允许压缩公钥(33 字节),拒绝未压缩公钥
见证脚本大小验证是否符合 3,600 字节的标准限制
DEX/交换审计清单(摘要)
类别检查项
预留系统在预留时锁定价格,而不是在执行时锁定
滑点保护强制执行最大滑点限制
抢先交易预留系统可防止抢先交易
队列操纵对滥用队列的行为施加罚没惩罚
部分成交对多提供方付款进行原子协调
关键运行时漏洞模式(摘要)

完整模式及代码示例请参阅 guidelines/audit-guidelines.md。

ID漏洞影响
C-07序列化不匹配(写入 u16,读取 u32)数据损坏
C-08将 sizeof() 字节误当作位数据截断
C-09有符号/无符号类型混淆(i8 → u8)符号丢失
C-10缓存一致性(setter 与未加载的缓存进行比较)状态静默损坏
C-11删除标记大小错误has() 返回错误结果
C-12通用整数截断(只读取第一个字节)数据丢失
H-06索引越界内存损坏
H-07差一错误(使用 > 而非 >=)缓冲区溢出
H-08指针冲突(截断但未哈希)存储内容被覆盖
M-05泰勒级数发散数学计算错误

审计报告末尾必须始终附上免责声明。绝不能声称审计已完成或能保证安全。


验证检查点

编写任何代码之前,你必须能够回答:

  1. 我正在构建什么类型的项目?(合约 / 前端 / 后端 / 插件 / 测试)

  2. 我是否阅读了该项目类型要求的每个文件?

    • 列出你阅读的每个文件
    • 如果无法全部列出,返回并阅读
  3. 准确的包版本是什么?(参见 guidelines/setup-guidelines.md)

    • 如果不清楚,返回并阅读
  4. 哪些构造是禁止的?

    • any、非空断言运算符、合约中的 while 循环、表示 satoshi 的 number 等。
    • 如果无法列出,返回并阅读
  5. 要求使用哪些模式?

    • 缓存、SafeMath、多线程等。
    • 如果无法列出,返回并阅读

停止——如果出现以下情况,请勿继续:
  • ❌ 阅读的 docs 文件少于 5 个
  • ❌ 跳过了必读列表中的任何文件
  • ❌ 阅读了项目类型要求列表之外的文件
  • ❌ 无法列出准确的包版本
  • ❌ 阅读 2–3 个文件后就准备说“我掌握的信息已经足够”

返回并阅读所有必读文件。不得走捷径。


代码验证顺序(必须遵守)

必须实际运行以下命令,而不只是提及它们。

第 1 步:安装依赖

非合约项目:

npx npm-check-updates -u && npm i eslint@^9.39.2 @eslint/js@^9.39.2 @btc-vision/bitcoin@rc @btc-vision/transaction@rc opnet@rc @btc-vision/bip32 @btc-vision/ecpair --prefer-online

合约项目:

npx npm-check-updates -u && npm i eslint@^9.39.2 @eslint/js@^9.39.2 @btc-vision/[email protected] @btc-vision/assemblyscript@^0.29.2 @btc-vision/[email protected] @btc-vision/btc-runtime@rc --prefer-online
  • 在运行任何其他命令之前,先运行适用的命令
  • 如果创建或修改了 package.json,则必须执行此步骤
  • 不得跳过此步骤——不得只运行 npm install
第 2 步:运行 Prettier
npm run format
  • 统一格式化所有代码
  • 在 lint 之前运行,以避免格式冲突
  • 不得跳过此步骤
第 3 步:运行 ESLint
npm run lint
  • 必须通过,且不得有任何错误
  • 如果存在错误,继续之前先修复
  • 不得说“你应该运行 lint”——必须实际运行
第 4 步:运行 TypeScript 检查
npm run typecheck
  • 如果没有相应脚本,则运行 npx tsc --noEmit
  • 必须通过,且不得有任何错误
  • 继续之前修复所有类型错误
步骤 5:构建
npm run build
  • 仅在格式检查、Lint 检查和类型检查通过后运行
  • 对于合约:确认已生成 .wasm 文件
步骤 6:运行测试
npm run test
  • 也可以使用 npx ts-node --esm tests/*.test.ts 运行单元测试
  • 所有测试都必须通过
  • 如果测试失败,请修复代码

停止——必须实际运行这些命令
  • ❌ 不要只写“运行 npm run lint 进行验证”
  • ❌ 不要因为“应该能正常运行”而跳过步骤
  • ❌ 未运行所有步骤前,不要认为代码已完成
  • ✅ 实际执行每条命令
  • ✅ 确认每条命令都通过
  • ✅ 在继续下一步前修复所有错误

如果你写了代码却没有运行这些命令,你的任务就没有完成。


任务完成检查点

在认为任何任务完成之前,请先问自己以下问题:

  1. 我是否完成了任务要求的所有步骤?

    • 我是否处理了用户提出的所有要求?
    • 我是否遗漏了任何要求?
  2. 我是否实际运行了验证命令?

    • 我是否运行了 npm install?(如果存在或更改了 package.json,则必须运行)
    • 我是否运行了 npm run format?(必须运行——Prettier 格式化)
    • 我是否运行了 npm run lint?(必须通过,且错误数为零)
    • 我是否运行了 npm run typecheck 或 npx tsc --noEmit?(必须运行)
    • 我是否运行了 npm run build?(对于可部署代码,必须运行)
    • 我是否运行了 npm run test?(如果存在测试,则必须运行)
    • 如果任何命令失败,我是否修复了错误?
    • “我应该运行 lint”不等于实际运行了它
  3. 我是否检查并重新审视了自己的工作?

    • 重新阅读我的成果——是否正确?
    • 我是否做出了可能有误的假设?
    • 是否有我未考虑到的边界情况?
    • 我的代码或回答是否可能引入错误或漏洞?
    • 对于智能合约:SafeMath、边界检查、访问控制、序列化
    • 对于 TypeScript:类型安全、空值处理、缓存模式
    • 对于回答:信息是否准确?我是否进行了核实?
  4. 我是否编写了完整且可用于生产环境的代码?

    • 绝不要添加“在生产环境中,你应该……”之类的注释
    • 绝不要添加存根、占位符或 TODO 注释
    • 绝不要使用“在此添加你的逻辑”之类的内容编写不完整的实现
    • 如果无法完整实现某项内容,请说明原因并询问用户
    • 所有代码都必须可以立即使用,而不是仅作为起点
  5. 调整非代码文件是否合适?

    • 如果行为发生变化,我是否更新了文档?
    • 如果依赖项发生变化,我是否更新了配置文件?
  6. 是否应该编写新的测试?

    • 如果我添加了新功能,是否为其编写了测试?
    • 测试是否覆盖了指南中的安全模式?
  7. 这是否只是探索或研究?

    • 如果是,则无需运行测试、Lint 检查和审计
    • 重点是提供准确的信息

这种自我检查可以避免工作不完整、遗漏要求和安全漏洞。


项目交付


停止——创建任何 ZIP 或交付物之前

打包前必须运行并通过所有验证命令:

# 1. Install dependencies (use the appropriate command for your project type)
# Non-contract:
npx npm-check-updates -u && npm i eslint@^9.39.2 @eslint/js@^9.39.2 @btc-vision/bitcoin@rc @btc-vision/transaction@rc opnet@rc @btc-vision/bip32 @btc-vision/ecpair --prefer-online
# Contract:
npx npm-check-updates -u && npm i eslint@^9.39.2 @eslint/js@^9.39.2 @btc-vision/[email protected] @btc-vision/assemblyscript@^0.29.2 @btc-vision/[email protected] @btc-vision/btc-runtime@rc --prefer-online

# 2. Format code
npm run format

# 3. Lint (MUST PASS)
npm run lint

# 4. TypeScript check (MUST PASS)
npm run typecheck
# OR: npx tsc --noEmit

# 5. Build (MUST SUCCEED)
npm run build

# 6. Tests (MUST PASS)
npm run test

如果任何命令失败,请勿创建 ZIP。请先修复错误。

❌ **禁止:**未运行验证命令就创建 ZIP ❌ **禁止:**只说“运行 npm run lint 进行验证”,而不实际运行 ❌ **禁止:**因为“应该能正常运行”而跳过类型检查


创建 ZIP 文件用于交付时:

绝不要包含:

  • node_modules/——接收方会运行 npm install
  • build/ 或 dist/——接收方会运行 npm run build
  • .git/——仓库历史记录
  • .env——包含机密信息

正确的 ZIP 命令(仅在所有检查通过后运行):

zip -r project.zip . -x "node_modules/*" -x "build/*" -x "dist/*" -x ".git/*" -x "*.wasm" -x ".env"

什么是 OPNet

OPNet 是一个比特币 L1 共识层,可直接在比特币上运行智能合约。它具有以下特点:

  • 不是元协议——它是一个完整的共识层
  • 完全无需信任——没有中心化组件
  • 无需许可——任何人都可以参与
  • 去中心化——依托比特币 PoW 和 OPNet epoch SHA1 挖矿
安全模型

经过 20 个区块后,一个 epoch 就已足够深埋;要修改它,需要以每小时数百万美元的代价重写比特币历史,因此 OPNet 状态的最终性高于比特币 6 次确认所提供的安全性。

每个 epoch 的校验和根都是整个状态的加密指纹。哪怕只相差 1 位,校验和也会完全改变,导致证明失败,从而让状态无声损坏成为不可能。

核心原则
  1. 合约采用 WebAssembly(AssemblyScript)——执行具有确定性
  2. 非托管——合约永远不会持有 BTC
  3. 验证而非托管——合约验证 L1 交易输出,而不持有资金
  4. 部分回滚——只有共识层执行会回滚;比特币转账始终有效
  5. 无需 Gas 代币——直接使用比特币
  6. CSV 时间锁是强制要求——所有在兑换中接收 BTC 的地址都必须使用 CSV(CheckSequenceVerify),以防止交易钉扎攻击
为什么 OPNet 需要共识(而不只是索引)

OPNet 与基于索引器的协议(如 Runes、Ordinals/BRC-20 或 Alkanes)有本质区别:

协议状态一致性不同节点会产生分歧吗?
Runes取决于索引器会——没有共识机制
BRC-20取决于索引器会——没有共识机制
Alkanes取决于索引器会——WASM 具有确定性,但没有共识
OPNet加密共识不会——工作量证明 + 证明声明确保各方达成一致

这很重要的原因:对于需要强制状态一致性的应用(如 DEX、托管服务或任何多方协调场景),索引器之间出现分歧将是灾难性的。当 NativeSwap 按特定价格锁定一笔预留时,每个节点都必须认同该预留存在。OPNet 的共识层通过加密证明保证这一点。


CSV:关键的防钉扎机制(强制要求)

什么是交易钉扎?

交易钉扎是一种灾难性的攻击途径,大多数比特币协议都忽视了这一点。其运作方式如下:

  1. 当你向某人发送比特币时,对方可以立即创建一笔花费该比特币的交易,即使第一笔交易尚未确认
  2. 攻击者创建大量由彼此依赖的未确认交易组成的链
  3. 这会让矿工无法将你的有效交易纳入区块
  4. 当攻击者操纵合约状态时,你的交易会困在内存池中
为什么没有防护的 DEX 会被钉扎攻击摧毁

针对未受保护的 DEX 的攻击场景:

  1. 攻击者钉扎你的兑换交易,阻止其确认
  2. 你的预留过期,但 BTC 仍卡在内存池中
  3. 攻击者取消自己的卖单,或操纵池状态
  4. 当你的交易最终确认时(如果能确认的话),代币已经不剩了
  5. 结果:攻击者不劳而获,你失去一切

所有未强制要求 CSV 的比特币协议都存在这一漏洞:

  • 只需一笔恶意的解锁请求,就能完全冻结多签桥
  • Ordinals 市场容易受到攻击
  • Runes 交易平台容易受到攻击
  • BRC-20 交易所容易受到攻击
CSV 解决方案

**CSV(CheckSequenceVerify,BIP 112)**可彻底消除钉扎攻击:

Without CSV: Maximum unconfirmed chain length = UNLIMITED (attackers can pin forever)
With CSV:    Maximum unconfirmed chain length = ZERO (must wait for confirmation)

要求所有卖方地址设置 1 个区块的 CSV 时间锁后,比特币一旦到达这些地址,至少一个区块内就无法再次花费。这一点可以通过数学方式证明,并能彻底堵住攻击途径。

实现要求

OPNet 交换中所有接收 BTC 的地址都必须使用 CSV 时间锁。

NativeSwap 在协议层强制执行这一要求。如果你正在构建任何协调 BTC 转账与智能合约状态的应用,就必须实现 CSV 保护。


两套地址系统(空投的关键)

为什么 OPNet 空投的运作方式不同于 Ethereum

在 Ethereum 上,只有一种地址格式。你可以遍历地址并调用 transfer(to, amount),因为 ERC20 合约只需使用相同的地址类型,减少发送方余额并增加接收方余额。

在 OPNet 上,合约余额以 ML-DSA 公钥哈希(32 字节抗量子地址)为键,但用户通常通过 Bitcoin 地址(Taproot P2TR,即经过调整的公钥)在外部识别。这是完全不同的密码学系统,两者之间没有内在关联。

地址系统格式用途
Bitcoin 地址Taproot P2TR(bc1p...)外部身份,即空投名单中的地址
OPNet 地址ML-DSA 公钥哈希(32 字节)合约余额、内部状态
为什么不能直接遍历并转账

如果你有一份来自代币持有者或快照参与者的 Bitcoin 地址列表:

// WRONG - THIS DOES NOT WORK
for (const btcAddress of airdropList) {
    await token.transfer(btcAddress, amount);  // IMPOSSIBLE
}

合约实际上无法直接向 Bitcoin 地址记入代币。 合约存储使用的是 ML-DSA 地址,而不是 Bitcoin 地址。只有当用户明确证明同时拥有这两种密钥后,它们之间的映射才会建立。

正确方案:基于领取的空投合约

OPNet 上的空投通过采用领取模式的智能合约实现:

1. 部署空投合约,按经过调整的公钥存储分配额度:

// Contract storage
mapping(tweakedPubKey => amount)  // Store: which Bitcoin addresses get how much
mapping(tweakedPubKey => claimed) // Track: has this allocation been claimed

2. 用户调用 claim(),并提供证明其控制该 Bitcoin 地址的签名:

// User's frontend (browser) - OP_WALLET signs automatically
const message = `Claim airdrop for ${contractAddress}`;
const signed = await MessageSigner.tweakAndSignMessageAuto(message);

// Submit to contract with signature in calldata
await airdropContract.claim(signature, messageHash);

3. 合约验证并转账:

// Contract logic
public claim(calldata: Calldata): BytesWriter {
    const signature = calldata.readBytes(64);
    const messageHash = calldata.readBytes(32);

    // Verify signature proves caller owns the tweaked public key
    if (!Blockchain.verifySignature(Blockchain.tx.origin, signature, messageHash, false)) {
        throw new Revert('Invalid signature');
    }

    // Get allocation for this tweaked public key
    const tweakedKey = Blockchain.tx.origin.tweakedPublicKey;
    const amount = this.allocations.get(tweakedKey);

    // Transfer to caller's ML-DSA address (now linked!)
    this._mint(Blockchain.tx.sender, amount);
    this.claimed.set(tweakedKey, true);
}

这就是“解锁交易”——用户证明自己同时拥有两种身份(Bitcoin 地址和 ML-DSA 地址),从而使合约能够将两者关联起来并记入代币。

香蕉储物柜类比
  • 你通过长相(Bitcoin 地址)认识 300 只猴子
  • 储物柜通过秘密握手(ML-DSA 密钥)开启
  • 你在储物柜上贴上猴子的长相,并把香蕉放进去
  • 猴子出现时,既要出示长相,也要完成握手
  • 系统由此得知:“这个长相 = 这个握手”,然后把香蕉给它
  • 香蕉一直“属于”它,但只有将长相与握手关联起来后,它才能取到香蕉

NativeSwap:如何在 Bitcoin 上构建真正的 DEX

NativeSwap 解答了 BitcoinFi 中最大的未解问题:如何构建一个真正的 AMM,让用户无需托管、以无需信任的方式用原生 BTC 交易代币?

根本问题

传统 AMM(如 Uniswap)会在资金池中持有两种资产,并通过数学公式设定价格。Bitcoin 无法做到这一点——智能合约实际上无法持有 BTC 并以程序化方式转移 BTC。

常见“解决方案”为何行不通:

  • 多签钱包:受信任方可能串通或消失
  • 封装 BTC:跨链桥会变成蜜罐(已有数十亿美元从跨链桥中被盗)
  • 纯订单簿:如果没有做市商持有库存,流动性会非常糟糕
虚拟储备:解决方案

NativeSwap 发现,AMM 不需要实际持有资产——只需跟踪交易的经济影响。这类似于:

  • 银行更新账本条目,而不转移实体现金
  • 期货市场交易价值数十亿美元的大宗商品,而无需接触一桶石油
  • 清算所结算数万亿美元,而不持有标的资产

工作原理:

  1. 合约维护两个数值:bitcoinReserve 和 tokenReserve
  2. 有人用 BTC 购买代币时,系统记录比特币储备增加、代币储备减少
  3. 实际 BTC 直接转给卖家,而不是转给合约
  4. AMM 定价仅取决于储备之间的比例
  5. 无论储备是实体还是虚拟,恒定乘积公式(bitcoinReserve × tokenReserve = k)的运作方式都相同
两阶段提交:为什么需要预留

问题:OPNet 可以回滚智能合约执行,但无法撤销比特币转账。BTC 一旦发出,该转账就受比特币的共识规则约束,而非 OPNet。

未使用预留时的灾难性情景:

  1. 你看到代币价格为 0.01 BTC/代币
  2. 你创建一笔发送 1 BTC 以购买 100 个代币的交易
  3. 在 10–20 分钟的确认时间内,其他交易将价格推高至 0.02 BTC/代币
  4. 在 Ethereum 上,你的交易会回滚,你的 ETH 会退回
  5. 在 Bitcoin 上,你的 BTC 已经转出——合约无法将其退回
  6. 你损失了 BTC,却没有获得任何代币

预留系统(两阶段提交):

阶段执行内容
阶段 1:预留证明你控制 BTC(UTXO 作为输入,再发送回你自己),支付少量费用,价格锁定在共识状态中
阶段 2:执行向提供者发送准确数量的 BTC(最多可原子性地发送至 200 个地址),保证按锁定价格执行

优势:

  • 无滑点风险:价格在预留时锁定
  • 无抢先交易:价格一旦锁定在 OPNet 状态中,任何人都无法更改
  • 部分成交:在单笔原子交易中自动协调向最多 200 个提供者付款(其他任何 Bitcoin 协议都无法实现)
队列影响:将待处理卖单纳入计算

卖家按当前 AMM 价格将代币加入队列。队列影响机制使用对数缩放调整有效代币储备:

为什么采用对数?

  • 市场以乘法方式处理信息
  • 队列从 100 个代币增加到 200 个代币,与从 1000 个增加到 2000 个代币,产生相同的心理影响
  • 首批卖家释放强烈的卖压信号;后续卖家的边际影响递减
  • 符合市场微观结构研究中的经验观察
削减:让操纵队列在经济上得不偿失

如果没有惩罚,队列影响机制就毫无价值:

  1. 攻击者添加大量虚假卖单 → 通过队列影响压低价格
  2. 攻击者买入低价代币
  3. 攻击者取消自己的卖单
  4. 从操纵中获利

削减机制:

  • 立即取消:罚没 50%(高于任何现实的操纵利润)
  • 长期占位:罚没比例提高至 90%
  • 罚没的代币返回资金池:攻击行为反而会改善流动性

这使操纵在经济上得不偿失,并确保队列深度是可靠的市场信号。

总结:为什么每个组件都必不可少
组件解决的限制
虚拟储备智能合约无法在 Bitcoin 上托管 BTC
预留(两阶段提交)OPNet 控制合约状态,而非 Bitcoin 转账
队列影响待处理订单会影响市场心理和定价
罚没没有处罚措施时,队列影响将可被操纵
CSV 时间锁UTXO 链容易受到交易钉住攻击
OPNet 共识索引器无法提供具有约束力的状态一致性

移除任何组件,系统就会变得可被利用,或无法继续作为 AMM 运作。


强制执行规则(不可妥协)

基于 ABI 的合约交互为强制要求

所有与 OPNet 智能合约交互的前端网站都必须使用 opnet npm 包和合约的 ABI 定义。 此要求不可妥协。

  • 始终在实例化合约时导入并使用合约的 ABI(来自 opnet 内置 ABI 或自定义 ABI)
  • 绝不使用原始 RPC 调用、手动编码 calldata,或任何其他方式与合约交互
  • 始终使用由 ABI 创建的类型化合约实例,以实现类型安全的方法调用和返回值解码
  • 阅读 docs/core-opnet-abi-reference-abi-overview.md 和 docs/core-opnet-abi-reference-custom-abis.md,了解 ABI 的创建和用法
// CORRECT - Use opnet package with ABI definition
import { JSONRpcProvider } from 'opnet';
import { MyContractABI } from './abi/MyContractABI.js';

const provider = new JSONRpcProvider('https://regtest.opnet.org');
const contract = provider.getContract(contractAddress, MyContractABI);
const result = await contract.someMethod(param1, param2);

// WRONG - Raw RPC calls without ABI
const result = await fetch(rpcUrl, { body: JSON.stringify({ method: 'call', params: [...] }) });

// WRONG - Manual calldata encoding
const calldata = new Uint8Array([...]);

如果 opnet 中没有合约的预构建 ABI,就必须按照 docs/core-opnet-abi-reference-custom-abis.md 创建自定义 ABI 定义。


已知的前端错误——切勿重犯

以下都是真实发生过的错误。现在每一项都严禁出现。

1. 错误:使用 contract.execute() 和原始 selector 字节
// WRONG - Raw execute with selector bytes. NEVER DO THIS.
const selector = new Uint8Array([0x01, 0x02, 0x03, 0x04]);
const result = await contract.execute(selector, calldata);

// CORRECT - Use ABI-defined typed method calls
const result = await contract.claim(signature, messageHash);

始终定义规范的 ABI,并按名称调用方法。原始 selector 会绕过类型安全,且可能静默失败。

2. 错误:缺少 getContract 参数

getContract 需要 5 个参数:(address, abi, provider, network, sender)。

// WRONG - Missing params (will fail or return broken contract)
const contract = getContract(address, abi);
const contract = getContract(address, abi, provider);

// CORRECT - All 5 params
const contract = getContract(address, abi, provider, network, senderAddress);

阅读 docs/core-opnet-contracts-instantiating-contracts.md,了解准确的签名。切勿猜测参数。

3. 错误:根据 walletconnect 的 signer 控制前端操作

在前端,钱包浏览器扩展负责签名。useWalletConnect() 返回的 signer 对象最初可能为 null/undefined——切勿根据它来限制用户操作。

// WRONG - Throws "Wallet not connected" because signer is null on frontend
if (!signer) throw new Error('Wallet not connected');
await contract.claim(signer, ...);

// CORRECT - Check wallet connection status, not signer object
const { isConnected, address } = useWalletConnect();
if (!isConnected || !address) throw new Error('Wallet not connected');
4. 错误:使用 walletconnect 的 provider 进行读取调用

创建一个单独的 JSONRpcProvider,用于只读合约调用。读取时不要复用 walletconnect 的 provider。

// WRONG - Using walletconnect provider for reads
const { provider } = useWalletConnect();
const data = await provider.call(...);

// CORRECT - Dedicated read provider
const readProvider = new JSONRpcProvider('https://regtest.opnet.org');
const contract = readProvider.getContract(address, abi);
const data = await contract.someReadMethod();
5. 错误:从错误的包导入

了解各符号所在的位置:

符号正确的包错误的包
Address@btc-vision/transaction(也由 opnet 重新导出)❌ @btc-vision/bitcoin(不在浏览器包中)
ABIDataTypes@btc-vision/transaction(也由 opnet 重新导出)❌ @btc-vision/bitcoin
JSONRpcProvideropnet❌ @btc-vision/provider
networks@btc-vision/bitcoin—
// CORRECT imports for frontend
import { Address, ABIDataTypes } from 'opnet';
import { JSONRpcProvider } from 'opnet';

// WRONG - Address is NOT in the browser bundle of @btc-vision/bitcoin
import { Address } from '@btc-vision/bitcoin'; // ❌ WILL FAIL IN BROWSER

不确定时,请从 opnet 导入——它会重新导出最常用的符号。

6. 错误:将原始 Bitcoin 地址(bc1q/bc1p)或原始 ML-DSA 公钥传递给 Address.fromString()

Address.fromString() 接受两个参数:

  1. 第一个参数:ML-DSA 公钥的哈希值(32 字节,以 0x 为前缀)。这不是原始 ML-DSA 公钥(原始公钥要大得多)。walletconnect hook 会通过 mldsaPublicKey 提供此值——它已经过哈希处理。
  2. 第二个参数:Bitcoin tweaked 公钥(33 字节,压缩格式,以 0x 为前缀)。walletconnect hook 会通过 publicKey 提供此值。

它不接受原始 Bitcoin 地址(bc1q/bc1p),也不接受只有一个参数的调用。

// WRONG - Passing a raw Bitcoin address. WILL CRASH.
const sender = Address.fromString(walletAddress); // walletAddress = "bc1q..." ❌

// WRONG - Only one parameter. WILL CRASH.
const sender = Address.fromString(publicKey); // ❌

// WRONG - Passing mldsaPublicKey (the RAW ML-DSA public key, ~2500 bytes).
// Address.fromString expects the 32-byte HASH, not the raw key. ❌
const sender = Address.fromString(mldsaPublicKey, publicKey); // ❌ WRONG! mldsaPublicKey is raw

// CORRECT - ALWAYS pass hashedMLDSAKey (32-byte hash) + publicKey (Bitcoin tweaked pubkey)
const sender = Address.fromString(hashedMLDSAKey, publicKey);
// hashedMLDSAKey = "0xABCD..." (32-byte SHA256 hash of ML-DSA pubkey, from walletconnect's hashedMLDSAKey)
// publicKey = "0x0203..." (33-byte compressed Bitcoin tweaked pubkey, from walletconnect's publicKey)

在前端使用 walletconnect 时:

const { publicKey, hashedMLDSAKey } = useWalletConnect();
// publicKey = Bitcoin tweaked public key (0x hex, 33 bytes compressed)
// hashedMLDSAKey = 32-byte SHA256 hash of ML-DSA public key (0x hex)
// NOTE: mldsaPublicKey is the RAW key (~2500 bytes) — do NOT use it for Address.fromString()

// CORRECT - Use hashedMLDSAKey (NOT mldsaPublicKey) + publicKey
const senderAddress = Address.fromString(hashedMLDSAKey, publicKey);

// Then use in getContract
const contract = getContract<IMyContract>(contractAddr, abi, provider, network, senderAddress);

如果 mldsaPublicKey 不可用(钱包尚不支持 ML-DSA),请使用 provider.getPublicKeyInfo(walletAddress) 获取公钥信息,然后构造 Address。

7. 错误:在需要公钥十六进制字符串的地方使用 walletAddress(bc1q.../bc1p...)

walletconnect 提供的 walletAddress 是一个 bech32 Bitcoin 地址(bc1q... 或 bc1p...)。它不是公钥。许多 OPNet API 需要的是公钥十六进制字符串(以 0x 为前缀),而不是 bech32 地址。

// WRONG - Passing bech32 address where public key is expected
const sender = Address.fromString(walletAddress); // "bc1q..." is NOT a public key ❌
await contract.someMethod(walletAddress);          // If it expects a pubkey ❌

// CORRECT - Use hashedMLDSAKey and publicKey from walletconnect
const { publicKey, hashedMLDSAKey, mldsaPublicKey, address: walletAddress } = useWalletConnect();
// publicKey = hex string "0x0203..." (Bitcoin tweaked pubkey, 33 bytes compressed)
// hashedMLDSAKey = hex string "0xABCD..." (32-byte SHA256 hash of ML-DSA pubkey)
// mldsaPublicKey = raw ML-DSA public key (~2500 bytes) — for signing ONLY, NOT for Address.fromString
// walletAddress = "bc1q..." (only use for display and refundTo)

经验法则:

  • walletAddress(bc1q/bc1p)→ 仅用于向用户显示,以及在 sendTransaction 中用作 refundTo
  • publicKey(0x 十六进制,33 字节)→ Bitcoin tweaked 公钥,用作 Address.fromString 的第二个参数
  • hashedMLDSAKey(0x 十六进制,32 字节)→ ML-DSA 公钥的 SHA256 哈希,用作 Address.fromString 的第一个参数
  • mldsaPublicKey(0x 十六进制,约 2500 字节)→ 原始 ML-DSA 公钥,仅用于 MLDSA 签名/验证。绝不要将其用于 Address.fromString

编写任何代码之前

你必须:

  1. 完整阅读 docs/core-typescript-law-CompleteLaw.md——这些是严格的 TypeScript 规则
  2. 确认项目配置符合 docs/ 配置文件中的标准
配置文件(位于 docs/)
文件用途
eslint-contract.json用于 AssemblyScript 合约的 ESLint 配置
eslint-generic.json用于 TypeScript 库的 ESLint 配置
eslint-react.json用于 React/Next.js 前端的 ESLint 配置
tsconfig-generic.jsonTypeScript 配置(不适用于合约)
asconfig.jsonAssemblyScript 编译器配置
TypeScript 是强制要求——没有例外

停止——绝对规则

你绝不能编写原始 JavaScript 代码,绝不例外。


所有代码都必须使用 TypeScript,并配备适当的工具链:

项目类型所需技术栈
前端TypeScript + Vite + npm 库
后端TypeScript + Node.js + npm 库
合约AssemblyScript(类似 TypeScript)
测试TypeScript
禁止事项——绝对不要这样做:
  • ❌ 原始 JavaScript 文件——绝不要编写 .js 源文件
  • ❌ 内联 <script> 标签——绝不要在 HTML 中嵌入 JS
  • ❌ 仅限浏览器的 JS——绝不要编写只能在浏览器控制台运行的代码
  • ❌ 没有构建系统——前端绝不要跳过 Vite/打包工具
  • ❌ 在 JS 中使用 // @ts-check——这不是 TypeScript,请使用真正的 .ts 文件
  • ❌ allowJs: true——绝不要在 tsconfig 中启用此项
  • ❌ CDN 脚本导入——请改用 npm 包
必须做到——始终遵循:
  • ✅ 所有源文件都必须是 .ts 或 .tsx
  • ✅ 所有前端应用都使用 Vite
  • ✅ 所有后端应用都使用 Node.js + TypeScript
  • ✅ 通过 npm 安装依赖(不要使用 CDN 链接)
  • ✅ 在 tsconfig 中启用严格模式
  • ✅ 明确定义所有类型
  • ✅ 使用规范的项目结构,包含 package.json、tsconfig.json 等文件
如果用户要求“快速脚本”或“简单示例”

**仍然要使用 TypeScript。**请创建规范的项目结构:

# Even for "quick" examples
mkdir project && cd project
npm init -y
npm install typescript tsx
# Write .ts file, run with npx tsx script.ts

不存在可以接受原始 JavaScript 的情况。


必须完成完整的项目设置

编写任何代码之前,项目必须具备:

project/
├── package.json          # With correct OPNet package versions
├── tsconfig.json         # Matching docs/tsconfig-generic.json
├── eslint.config.js      # Using appropriate config from docs/
├── .prettierrc           # Prettier configuration
├── .prettierignore       # Prettier ignore file
├── src/                  # Source code directory
│   └── index.ts          # Entry point
└── tests/                # Test directory (if applicable)
    └── *.test.ts
Prettier 配置(强制)

.prettierrc:

{
    "semi": true,
    "singleQuote": true,
    "tabWidth": 4,
    "trailingComma": "all",
    "printWidth": 100,
    "bracketSpacing": true,
    "arrowParens": "always"
}

.prettierignore:

node_modules/
build/
dist/
*.wasm
coverage/

Package.json 脚本(添加以下内容):

{
    "scripts": {
        "format": "prettier --write \"src/**/*.{ts,tsx}\"",
        "format:check": "prettier --check \"src/**/*.{ts,tsx}\""
    }
}

提交前运行 Prettier:

npm run format

对于前端(React/Vite),还需包含:

├── vite.config.ts        # Vite configuration
├── index.html            # Entry HTML
└── src/
    ├── App.tsx
    ├── main.tsx
    └── styles/           # CSS files (NO inline CSS)
        └── variables.css

对于合约(AssemblyScript),还需包含:

├── asconfig.json         # AssemblyScript config
└── assembly/
    ├── index.ts          # Contract entry point
    └── contracts/
        └── MyContract.ts

必须在编写应用代码之前创建这些文件。


配置验证清单
  • package.json 存在且包含正确的 OPNet 软件包版本
  • tsconfig.json 与 docs/tsconfig-generic.json 一致(或合约使用严格的 ESNext)
  • eslint.config.js 使用 docs/ 中适当的配置
  • .prettierrc 存在且配置正确
  • 任何地方都不得使用 any 类型——这是禁止的
  • 不得使用内联 CSS——使用 CSS 模块、Tailwind 或外部样式表
  • 不得使用 JavaScript 文件——仅使用 TypeScript
  • 代码已使用 Prettier 格式化(npm run format)
  • 符合 ESNext 标准
  • 单元测试存在且通过
如果有任何一项未通过 → 修复之前拒绝编写代码

配置错误的项目会导致漏洞利用和严重安全漏洞。


TypeScript 法则(关键)

摘自 docs/core-typescript-law-CompleteLaw.md:

禁止使用的结构
结构禁止原因
any随时可能引发运行时错误。没有例外。
unknown仅限系统边界处(JSON 解析、外部 API)使用
object(小写)使用特定接口或 Record<string, T>
Function(大写)使用特定签名
{}表示“任何非 nullish 值”。使用 Record<string, never>
非空断言(! 运算符)使用显式 null 检查或可选链
无用/重复代码出现此类代码说明设计有问题
绕过 ESLint绝不允许
分节分隔注释见下文
内联 CSS使用 CSS 模块、styled-components 或外部样式表。不得使用 style={{ }} 属性。
禁止:分节分隔注释

绝不编写如下形式的注释:

// ==================== PRIVATE METHODS ====================
// ---------------------- HELPERS ----------------------
// ************* CONSTANTS *************
// ####### INITIALIZATION #######

这些注释懒惰、不专业且毫无用处。它们只会增加噪声,没有任何价值。

应改用:为每个类、方法、属性和函数编写规范的 TSDoc:

/**
 * Transfers tokens from sender to recipient.
 *
 * @param to - The recipient address
 * @param amount - The amount to transfer in base units
 * @returns True if transfer succeeded
 * @throws {InsufficientBalanceError} If sender has insufficient balance
 * @throws {InvalidAddressError} If recipient address is invalid
 *
 * @example
 * ```typescript
 * const success = await token.transfer(recipientAddress, 1000n);
 * ```
 */
public async transfer(to: Address, amount: bigint): Promise<boolean> {
    // ...
}

TSDoc 要求:

  • 为每个参数添加 @param
  • 为非 void 返回值添加 @returns
  • 为可能出现的异常添加 @throws
  • 为非简单方法添加 @example
  • 描述方法的功能,而不是实现方式

代码组织应来自合理的类设计,而非 ASCII 图案。

数值类型
  • number:数组长度、循环计数器、小型标志、端口、像素
  • bigint:聪金额、区块高度、时间戳、数据库 ID、文件大小、累计总量
  • 财务值使用浮点数:禁止——使用具有明确缩放比例的定点 bigint
常见 API 陷阱

Address.fromString() 需要两个参数:

// WRONG - will fail (one param)
const addr = Address.fromString(addressString);

// WRONG - will fail (raw Bitcoin address)
const addr = Address.fromString('bc1q...');

// WRONG - raw ML-DSA public key is ~2500 bytes, NOT what this function expects
const addr = Address.fromString(rawMldsaPublicKey, tweakedPublicKey);

// CORRECT - always provide both: hashedMLDSAKey (32-byte hash) + publicKey (Bitcoin tweaked pubkey)
const addr = Address.fromString(hashedMLDSAKey, publicKey);

第一个参数是 ML-DSA 公钥的 32 字节 SHA256 哈希值——即 useWalletConnect() 中的 hashedMLDSAKey,而不是 mldsaPublicKey(后者是原始的约 2500 字节密钥)。第二个参数是经过 Bitcoin tweak 的公钥(压缩后 33 字节)——即 useWalletConnect() 中的 publicKey。两者都必须是带 0x 前缀的十六进制字符串。始终提供这两个参数。

必需的 tsconfig.json 设置
{
    "compilerOptions": {
        "strict": true,
        "noImplicitAny": true,
        "strictNullChecks": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "exactOptionalPropertyTypes": true,
        "noImplicitReturns": true,
        "noFallthroughCasesInSwitch": true,
        "noUncheckedIndexedAccess": true,
        "noImplicitOverride": true,
        "moduleResolution": "bundler",
        "module": "ESNext",
        "target": "ESNext",
        "lib": ["ESNext"],
        "isolatedModules": true,
        "verbatimModuleSyntax": true
    }
}

性能规则

必须使用多线程
  • 顺序处理 = 性能不可接受
  • CPU 密集型任务使用 Worker 线程
  • I/O 使用异步操作并设置适当的并发
  • 尽可能批量处理操作
  • 使用连接池
缓存(始终使用)
  • 复用合约实例——同一合约不得重复创建新实例
  • 复用提供程序——每个网络只使用一个提供程序实例
  • 本地缓存——用户数据存储在浏览器 localStorage/IndexedDB 中
  • API 缓存——对区块链状态进行服务器端缓存
  • 区块变化时失效——确认新区块后清除过期数据
RPC 调用优化

使用 .metadata() 代替多次调用:

// ❌ BAD - 4 RPC calls (slow)
const [name, symbol, decimals, totalSupply] = await Promise.all([
    contract.name(),
    contract.symbol(),
    contract.decimals(),
    contract.totalSupply()
]);

// ✅ GOOD - 1 RPC call (fast)
const { name, symbol, decimals, totalSupply } = (await contract.metadata()).decoded;

.metadata() 通过一次调用即可返回名称、符号、精度、总供应量、所有者等信息。

后端/API 框架

强制要求:使用 OPNet 的高性能库:

软件包用途
@btc-vision/uwebsocket.jsWebSocket 服务端(最快)
@btc-vision/hyper-expressHTTP 服务端(最快)

禁止使用:Express、Fastify、Koa、Hapi 或任何其他 HTTP 框架。它们的速度明显更慢。

// CORRECT - Use hyper-express with threading
import HyperExpress from '@btc-vision/hyper-express';
import { Worker } from 'worker_threads';

const app = new HyperExpress.Server();
// Use classes, not functions
// Delegate CPU work to workers

合约 Gas 优化(关键)

合约中禁止使用的模式
模式禁止原因替代方案
while 循环Gas 消耗无上限使用有界 for 循环
无限循环合约会停止运行并浪费 Gas始终设置退出条件
遍历所有映射键O(n) 会呈指数级增长使用索引查找、分页
遍历所有数组元素O(n) 成本会急剧上升存储聚合值、使用分页
无界数组会无限增长限制大小、使用清理机制
Gas 高效模式
// WRONG - Iterating all holders (O(n) disaster)
let total: u256 = u256.Zero;
for (let i = 0; i < holders.length; i++) {
    total = SafeMath.add(total, balances.get(holders[i]));
}

// CORRECT - Store running total
const totalSupply: StoredU256 = new StoredU256(TOTAL_SUPPLY_POINTER);
// Update on mint/burn, read in O(1)

安全审计清单

必须检查所有代码中的以下问题:
密码学
  • 密钥生成熵
  • Nonce 重用
  • 签名可塑性
  • 定时攻击
  • 重放攻击
智能合约
  • 重入
  • 整数溢出/下溢
  • 访问控制绕过
  • 授权缺陷
  • 状态篡改
  • 竞态条件
Bitcoin 特有问题
  • 交易可塑性
  • UTXO 选择漏洞
  • 费用狙击
  • 粉尘攻击
  • 交易钉扎攻击 - 必须使用 CSV 时间锁
  • 未确认交易链 - 验证 CSV 强制执行情况
DEX/兑换特有问题
  • 抢先交易 / MEV 攻击
  • 通过队列泛洪操纵价格
  • 预留过期边缘情况
  • 部分成交协调
  • 试图绕过罚没机制

快速入门

任务模板
新建 OP20 代币templates/contracts/OP20Token.ts
新建 OP721 NFTtemplates/contracts/OP721NFT.ts
通用合约templates/contracts/MyContract.ts
合约测试templates/tests/
前端 dApptemplates/frontend/
节点插件(索引器)templates/plugins/OP20Indexer.ts
节点插件(通用)templates/plugins/MyPlugin.ts

完整文件索引

配置文件(docs/)
文件描述
docs/asconfig.jsonAssemblyScript 编译器配置
docs/eslint-contract.json用于 AssemblyScript 合约的 ESLint
docs/eslint-generic.json用于 TypeScript 库的 ESLint
docs/eslint-react.json用于 React 前端的 ESLint
docs/tsconfig-generic.jsonTypeScript 配置(非合约)
docs/setup-README.md设置说明
TypeScript 规范
文件描述
docs/core-typescript-law-readme.md概览
docs/core-typescript-law-CompleteLaw.md完整规则 - 请先阅读
OPNet 客户端库
文件描述
docs/core-opnet-README.md库概览
docs/core-opnet-backend-api.md使用 hyper-express 的后端 API
docs/core-opnet-getting-started-installation.md安装
docs/core-opnet-getting-started-overview.md架构概览
docs/core-opnet-getting-started-quick-start.md快速入门指南
docs/core-opnet-providers-json-rpc-provider.mdJSON-RPC 提供程序
docs/core-opnet-providers-websocket-provider.mdWebSocket 提供程序
docs/core-opnet-providers-understanding-providers.md提供程序概念
docs/core-opnet-providers-advanced-configuration.md高级配置
docs/core-opnet-providers-internal-caching.md缓存系统
docs/core-opnet-providers-threaded-http.md多线程
docs/core-opnet-contracts-overview.md合约交互概览
docs/core-opnet-contracts-instantiating-contracts.md创建合约实例
docs/core-opnet-contracts-simulating-calls.md模拟调用
docs/core-opnet-contracts-sending-transactions.md发送交易
docs/core-opnet-contracts-gas-estimation.mdGas 估算
docs/core-opnet-contracts-offline-signing.md离线签名
docs/core-opnet-contracts-transaction-configuration.md交易配置
docs/core-opnet-contracts-contract-code.md获取合约代码
docs/core-opnet-abi-reference-abi-overview.mdABI 概览
docs/core-opnet-abi-reference-data-types.mdABI 数据类型
docs/core-opnet-abi-reference-op20-abi.mdOP20 ABI
docs/core-opnet-abi-reference-op20s-abi.mdOP20S ABI(签名)
docs/core-opnet-abi-reference-op721-abi.mdOP721 ABI
docs/core-opnet-abi-reference-motoswap-abis.mdMotoSwap ABI
docs/core-opnet-abi-reference-factory-abis.md工厂 ABI
docs/core-opnet-abi-reference-stablecoin-abis.md稳定币 ABI
docs/core-opnet-abi-reference-custom-abis.md创建自定义 ABI
docs/core-opnet-api-reference-provider-api.md提供程序 API
docs/core-opnet-api-reference-contract-api.md合约 API
docs/core-opnet-api-reference-epoch-api.mdEpoch API
docs/core-opnet-api-reference-utxo-manager-api.mdUTXO Manager API
docs/core-opnet-api-reference-types-interfaces.md类型与接口
docs/core-opnet-bitcoin-utxos.mdUTXO 处理
docs/core-opnet-bitcoin-utxo-optimization.mdUTXO 优化
docs/core-opnet-bitcoin-balances.md余额查询
docs/core-opnet-bitcoin-sending-bitcoin.md发送 BTC
docs/core-opnet-blocks-block-operations.md区块操作
docs/core-opnet-blocks-block-witnesses.md区块见证数据
docs/core-opnet-blocks-gas-parameters.mdGas 参数
docs/core-opnet-blocks-reorg-detection.md检测链重组
docs/core-opnet-epochs-overview.mdEpoch 概览
docs/core-opnet-epochs-epoch-operations.mdEpoch 操作
docs/core-opnet-epochs-mining-template.md挖矿模板
docs/core-opnet-epochs-submitting-epochs.md提交 Epoch
docs/core-opnet-transactions-broadcasting.md广播交易
docs/core-opnet-transactions-fetching-transactions.md获取交易
docs/core-opnet-transactions-transaction-receipts.md交易收据
docs/core-opnet-transactions-challenges.md交易挑战
docs/core-opnet-storage-storage-operations.md存储操作
docs/core-opnet-public-keys-public-key-operations.md公钥操作
docs/core-opnet-utils-bitcoin-utils.mdBitcoin 工具
docs/core-opnet-utils-binary-serialization.md二进制序列化
docs/core-opnet-utils-revert-decoder.md回滚解码器
docs/core-opnet-examples-op20-examples.mdOP20 示例
docs/core-opnet-examples-op721-examples.mdOP721 示例
docs/core-opnet-examples-deployment-examples.md部署示例
docs/core-opnet-examples-advanced-swaps.md交换示例
交易库
文件描述
docs/core-transaction-README.md库概览
docs/core-transaction-transaction-building.md构建交易
docs/core-transaction-transaction-factory-interfaces.mdTransactionFactory 接口(费用、备注、锚点、发送最大金额)
docs/core-transaction-offline-transaction-signing.md离线签名
docs/core-transaction-addresses-P2OP.mdP2OP 地址格式
docs/core-transaction-quantum-support-README.md量子概览
docs/core-transaction-quantum-support-01-introduction.md量子简介
docs/core-transaction-quantum-support-02-mnemonic-and-wallet.md量子钱包
docs/core-transaction-quantum-support-03-address-generation.md量子地址
docs/core-transaction-quantum-support-04-message-signing.md量子签名
docs/core-transaction-quantum-support-05-address-verification.md量子验证
地址系统与空投(重要)
文件描述
docs/core-opnet-address-systems-airdrop-pattern.md两种地址系统、空投模式(必读)
OIP 规范
文件描述
docs/core-OIP-README.mdOIP 概览
docs/core-OIP-OIP-0001.mdOIP 流程
docs/core-OIP-OIP-0002.md合约标准
docs/core-OIP-OIP-0003.md插件系统规范
docs/core-OIP-OIP-0004.mdEpoch 系统
docs/core-OIP-OIP-0020.mdOP20 代币标准
docs/core-OIP-OIP-0721.mdOP721 NFT 标准
Contract Runtime (btc-runtime)
FileDescription
docs/contracts-btc-runtime-README.mdRuntime overview
docs/contracts-btc-runtime-gas-optimization.mdGas optimization (CRITICAL)
docs/contracts-btc-runtime-getting-started-installation.mdInstallation
docs/contracts-btc-runtime-getting-started-first-contract.mdFirst contract
docs/contracts-btc-runtime-getting-started-project-structure.mdProject structure
docs/contracts-btc-runtime-core-concepts-blockchain-environment.mdBlockchain env
docs/contracts-btc-runtime-core-concepts-storage-system.mdStorage system
docs/contracts-btc-runtime-core-concepts-pointers.mdStorage pointers
docs/contracts-btc-runtime-core-concepts-events.mdEvents
docs/contracts-btc-runtime-core-concepts-decorators.mdDecorators
docs/contracts-btc-runtime-core-concepts-security.mdSecurity
docs/contracts-btc-runtime-api-reference-blockchain.mdBlockchain API
docs/contracts-btc-runtime-api-reference-storage.mdStorage API
docs/contracts-btc-runtime-api-reference-events.mdEvents API
docs/contracts-btc-runtime-api-reference-op20.mdOP20 API
docs/contracts-btc-runtime-api-reference-op721.mdOP721 API
docs/contracts-btc-runtime-api-reference-safe-math.mdSafeMath API
docs/contracts-btc-runtime-contracts-op-net-base.mdOP_NET base class
docs/contracts-btc-runtime-contracts-op20-token.mdOP20 implementation
docs/contracts-btc-runtime-contracts-op20s-signatures.mdOP20S signatures
docs/contracts-btc-runtime-contracts-op721-nft.mdOP721 implementation
docs/contracts-btc-runtime-contracts-reentrancy-guard.mdReentrancy guard
docs/contracts-btc-runtime-contracts-upgradeable.mdUpgradeable contracts
docs/contracts-btc-runtime-storage-stored-primitives.mdStored primitives
docs/contracts-btc-runtime-storage-stored-maps.mdStored maps
docs/contracts-btc-runtime-storage-stored-arrays.mdStored arrays
docs/contracts-btc-runtime-storage-memory-maps.mdMemory maps
docs/contracts-btc-runtime-types-address.mdAddress type
docs/contracts-btc-runtime-types-calldata.mdCalldata type
docs/contracts-btc-runtime-types-bytes-writer-reader.mdBytesWriter/Reader
docs/contracts-btc-runtime-types-safe-math.mdSafeMath type
docs/contracts-btc-runtime-advanced-cross-contract-calls.mdCross-contract calls
docs/contracts-btc-runtime-advanced-signature-verification.mdSignature verification
docs/contracts-btc-runtime-advanced-quantum-resistance.mdQuantum resistance
docs/contracts-btc-runtime-advanced-bitcoin-scripts.mdBitcoin scripts
docs/contracts-btc-runtime-advanced-contract-upgrades.mdContract upgrades
docs/contracts-btc-runtime-advanced-plugins.mdContract plugins
docs/contracts-btc-runtime-examples-basic-token.mdBasic token example
docs/contracts-btc-runtime-examples-stablecoin.mdStablecoin example
docs/contracts-btc-runtime-examples-nft-with-reservations.mdNFT example
docs/contracts-btc-runtime-examples-oracle-integration.mdOracle example
Other Contract Docs
FileDescription
docs/contracts-as-bignum-README.mdBigNum library (u256, u128)
docs/contracts-opnet-transform-README.mdTransform decorators
docs/contracts-opnet-transform-std-README.mdStandard library
docs/contracts-example-tokens-README.mdExample tokens
docs/contracts-example-tokens-docs-OP_20.mdOP20 example
客户端库
文件描述
docs/clients-bitcoin-README.mdBitcoin 库概览
docs/clients-bitcoin-psbt.mdPSBT 类、签名、定稿
docs/clients-bitcoin-payments.md支付类型(P2TR、P2WPKH、P2WSH、P2SH、P2OP)
docs/clients-bitcoin-script.md脚本构建、操作码
docs/clients-bitcoin-address.md地址编码/解码
docs/clients-bitcoin-transaction.md交易类
docs/clients-bip32-README.mdBIP32 HD 派生
docs/clients-bip32-QUANTUM.md量子支持
docs/clients-ecpair-README.mdEC 密钥对
docs/clients-walletconnect-README.mdWalletConnect
docs/clients-walletconnect-wallet-integration.md钱包集成
测试
文件描述
docs/testing-unit-test-framework-README.md测试框架
docs/testing-opnet-unit-test-README.md单元测试
docs/testing-opnet-unit-test-docs-README.md测试文档
docs/testing-opnet-unit-test-docs-Blockchain.md区块链模拟
docs/testing-opnet-unit-test-docs-ContractRuntime.md合约运行时
前端
文件描述
docs/frontend-motoswap-ui-README.md前端指南(标准)
插件
文件描述
docs/plugins-plugin-sdk-README.md插件 SDK
docs/plugins-opnet-node-README.mdOPNet 节点
docs/plugins-opnet-node-docker-README.mdDocker 设置
模板
合约模板(templates/contracts/)
文件描述
templates/contracts/OP20Token.tsOP20 代币实现
templates/contracts/OP721NFT.tsOP721 NFT 实现
templates/contracts/MyContract.ts通用合约模板
templates/contracts/index.ts入口点 / 导出
前端模板(templates/frontend/)
文件描述
templates/frontend/App.tsx主应用组件
templates/frontend/OPNetProvider.tsxOPNet 上下文提供程序
templates/frontend/WalletConnect.tsx钱包连接组件
templates/frontend/ContractInteraction.tsx合约交互组件
templates/frontend/useWallet.ts钱包 Hook
templates/frontend/useContract.ts合约 Hook
templates/frontend/vite.config.tsVite 配置
templates/frontend/package.json软件包依赖项
插件模板(templates/plugins/)
文件描述
templates/plugins/MyPlugin.ts通用插件模板
templates/plugins/OP20Indexer.tsOP20 索引器插件
templates/plugins/types.ts类型定义
templates/plugins/index.ts入口点
templates/plugins/plugin.json插件清单
测试模板(templates/tests/)
文件描述
templates/tests/OP20.test.tsOP20 测试示例
templates/tests/setup.ts测试设置
templates/tests/gulpfile.jsGulp 构建配置

故障排除

常见错误及修复方法记录在 references/troubleshooting.md 中。遇到构建错误、RPC 故障、前端崩溃或部署问题时,请查阅该文档。


高级交易功能

当用户询问如何为交易(部署、交互、资金注入)添加费用、备注或高级功能时,务必查阅 docs/core-transaction-transaction-factory-interfaces.md。

常见用户请求 → 参数
用户请求参数接口
“添加手续费” / “设置费率”feeRate: number(sat/vB)TransactionParameters
“添加优先费”priorityFee: bigintTransactionParameters
“添加备注/备忘录”note: string | Uint8ArrayTransactionParameters
“使用锚定输出”anchor: trueTransactionParameters
“发送到多个地址”extraOutputs: PsbtOutputExtended[]TransactionParameters
“发送最大金额/全部余额”autoAdjustAmount: trueIFundingTransactionParameters
“从单独的 UTXO 支付手续费”feeUtxos: UTXO[]IFundingTransactionParameters
“设置最低 gas”minGas: bigintTransactionParameters
“离线签名”toOfflineBuffer() / fromOfflineBuffer()CallResult 方法
“签名但不广播”signTransaction()CallResult 方法
“广播预签名 TX”sendPresignedTransaction()CallResult 方法
CallResult 交易方法
// Sign without broadcast
const signedTx = await simulation.signTransaction(params);

// Sign and broadcast
const receipt = await simulation.sendTransaction(params);

// Broadcast pre-signed
const receipt = await simulation.sendPresignedTransaction(signedTx);

// Offline signing workflow
const buffer = await simulation.toOfflineBuffer(address, amount);
const reconstructed = CallResult.fromOfflineBuffer(buffer);
快速示例:添加手续费 + 备注
await simulation.sendTransaction({
    signer: wallet.keypair,
    mldsaSigner: wallet.mldsaKeypair,
    refundTo: wallet.p2tr,
    network: networks.regtest,
    maximumAllowedSatToSpend: 100000n,
    feeRate: 15,                    // 15 sat/vB
    priorityFee: 5000n,             // +5000 sats priority
    note: "Payment for invoice #123", // OP_RETURN memo
});

完整详情请阅读 docs/core-transaction-transaction-factory-interfaces.md。


合约开发

核心概念
  1. 合约使用自定义的 AssemblyScript 分支(@btc-vision/assemblyscript)——此分支为标准 AssemblyScript 添加了闭包支持,从而支持回调和高阶函数模式。请始终安装 @btc-vision/assemblyscript,而不是上游的 assemblyscript 包。
  2. 每次交互都会运行构造函数——使用 onDeployment() 进行初始化
  3. 合约无法持有 BTC——它们是计算器,而非托管方
  4. 验证而非托管模式——将 Blockchain.tx.outputs 与内部状态进行检查
装饰器参考
// Mark method as callable
@method({ name: 'param1', type: ABIDataTypes.UINT256 })

// Specify return types
@returns({ name: 'result', type: ABIDataTypes.UINT256 })

// Declare emitted events
@emit('Transfer', 'Approval')
存储类型
类型用途
StoredU256单个 u256 值
StoredBoolean布尔标志
StoredString字符串值
StoredMapU256键值映射(u256 键/值)
AddressMemoryMap内存中的地址映射

测试

所有代码都必须有测试
import { opnet, OPNetUnit, Assert, Blockchain } from '@btc-vision/unit-test-framework';

await opnet('My Tests', async (vm: OPNetUnit) => {
    vm.beforeEach(async () => {
        Blockchain.dispose();
        await Blockchain.init();
    });

    await vm.it('should work correctly', async () => {
        const result = await contract.someMethod();
        Assert.expect(result).toEqual(expected);
    });
});

插件开发

OPNet 节点就像 Minecraft 服务器一样——支持插件!

关键资源
  • 阅读 docs/plugins-plugin-sdk-README.md
  • 阅读插件规范 docs/core-OIP-OIP-0003.md
  • 使用 templates/plugins/OP20Indexer.ts 创建索引器
插件生命周期
钩子调用时机是否阻塞
onFirstInstall首次安装是
onNetworkInit每次加载是
onBlockChange确认新区块时否
onReorg链重组时是(关键)
关键:处理重组

你必须实现 onReorg(),以回滚发生重组的区块对应的状态。否则会导致数据不一致。


前端开发

合约交互:始终使用 opnet npm 包 + ABI

**所有与 OPNet 合约交互的前端都必须使用 opnet npm 包及合约的 ABI 定义。**无一例外。不得使用原始 RPC,也不得手动编码。ABI 提供类型安全的方法调用、自动 calldata 编码/解码,以及妥善的错误处理。有关内置和自定义 ABI 定义,请参阅 ABI 参考文档(docs/core-opnet-abi-reference-*.md)。

配置规范

前端配置必须使用 docs/eslint-react.json 和 docs/tsconfig-generic.json:

  • Vite + React
  • 使用 Vitest 进行测试
  • 使用 TypeScript 严格模式的 ESLint
  • ESNext 目标
缓存(强制要求)
  • 复用 provider 实例——每个网络使用一个单例
  • 复用合约实例——按地址缓存
  • 缓存 API 响应——在区块变更时使缓存失效
关键钩子
// OPNet provider
const { provider, isConnected, network } = useOPNet();

// Contract interaction
const { contract, callMethod, loading } = useContract(address, abi);

// Wallet connection
const { address, connect, disconnect, signPsbt } = useWallet();

完整集成指南请参阅 docs/frontend-motoswap-ui-README.md。


后端/API 开发

强制要求的框架
包用途
@btc-vision/hyper-expressHTTP 服务端(速度最快)
@btc-vision/uwebsocket.jsWebSocket 服务端(速度最快)

禁止使用:Express、Fastify、Koa、Hapi——它们的速度明显更慢。

完整指南请参阅 docs/core-opnet-backend-api.md。


官方钱包:OP_WALLET(强制要求)

**OP_WALLET 是支持 OPNet 的主要官方钱包。**它由 OPNet 团队开发,提供了与 OPNet Bitcoin L1 智能合约生态系统交互所需的最完整功能。

**所有 OPNet dApp 都必须通过 @btc-vision/opwallet 集成 OP_WALLET。**这是不可妥协的要求。

全面支持 OPNet 为何必须使用 OP_WALLET
功能OP_WALLET其他钱包
官方支持是否
MLDSA 签名是否
抗量子密钥是否
完整 OPNet 集成是部分支持
第一方更新是否
主要功能
  1. MLDSA(ML-DSA)签名:只有 OP_WALLET 支持抗量子的 ML-DSA 签名,这对保障 OPNet 的未来安全至关重要
  2. 全面支持地址系统:OP_WALLET 可正确处理 Bitcoin 地址(调整后的公钥)和 OPNet 地址(ML-DSA 公钥哈希)
  3. 原生 OPNet 功能:新功能发布后即可直接使用所有 OPNet 功能
  4. 优化的用户体验:专为 OPNet dApp 交互打造
集成

在前端安装 @btc-vision/opwallet 以集成钱包:

npm i @btc-vision/opwallet

同时使用 @btc-vision/walletconnect 提供连接界面:

import { WalletConnectProvider, useWalletConnect, SupportedWallets } from '@btc-vision/walletconnect';

// Wrap your app
<WalletConnectProvider theme="dark">
  <App />
</WalletConnectProvider>

// In your component
const { connectToWallet, mldsaPublicKey, hashedMLDSAKey, publicKey, signMLDSAMessage } = useWalletConnect();

// Connect specifically to OP_WALLET for full feature support
connectToWallet(SupportedWallets.OP_WALLET);

// Use MLDSA signatures (OP_WALLET only)
if (mldsaPublicKey) {
  const signature = await signMLDSAMessage('Your message');
}

// For Address.fromString — use hashedMLDSAKey (32-byte hash), NOT mldsaPublicKey (raw ~2500 bytes)
const senderAddress = Address.fromString(hashedMLDSAKey, publicKey);
安装

从 Chrome 网上应用店 安装 OP_WALLET


客户端库

包文档描述
@btc-vision/bitcoindocs/clients-bitcoin-README.mdBitcoin 库(PSBT 速度快 709 倍)
@btc-vision/bip32docs/clients-bip32-README.mdHD 派生 + 抗量子
@btc-vision/ecpairdocs/clients-ecpair-README.mdEC 密钥对
@btc-vision/transactiondocs/core-transaction-README.mdOPNet 交易
opnetdocs/core-opnet-README.md主客户端库
@btc-vision/walletconnectdocs/clients-walletconnect-README.md钱包连接(OP_WALLET + UniSat)

版本要求

工具最低版本
Node.js>= 24.0.0
TypeScript>= 5.9.3
ESLint^9.39.2
@eslint/js^9.39.2
AssemblyScript@btc-vision/assemblyscript@^0.29.2(支持闭包的自定义分支)
强制安装命令

对于非合约项目(前端、后端、插件、测试):

npx npm-check-updates -u && npm i eslint@^9.39.2 @eslint/js@^9.39.2 @btc-vision/bitcoin@rc @btc-vision/transaction@rc opnet@rc @btc-vision/bip32 @btc-vision/ecpair --prefer-online

对于合约项目(AssemblyScript):

npx npm-check-updates -u && npm i eslint@^9.39.2 @eslint/js@^9.39.2 @btc-vision/[email protected] @btc-vision/assemblyscript@^0.29.2 @btc-vision/[email protected] @btc-vision/btc-runtime@rc --prefer-online

创建 package.json 后,始终运行相应命令。没有例外。


重要提醒

  1. 首先阅读 typescript-law——这是不可妥协的规则
  2. 核实项目配置——编写任何代码之前
  3. 禁止使用 any 类型——任何时候都不行
  4. 测试所有内容——必须编写单元测试
  5. **处理

评论

支持 Markdown