create-script-template

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Create Script Template

创建脚本模板

Create script templates for the b-open-io/ts-templates repository following established patterns.
按照既定规范,为b-open-io/ts-templates仓库创建脚本模板。

When to Use

使用场景

  • Create a new BitCom protocol template (like AIP, MAP, SIGMA)
  • Build an OP_RETURN data template
  • Implement a ScriptTemplate for a new protocol
  • Add a template to ts-templates repository
  • 创建新的BitCom协议模板(如AIP、MAP、SIGMA)
  • 构建OP_RETURN数据模板
  • 为新协议实现ScriptTemplate
  • 向ts-templates仓库添加模板

Template Structure

模板结构

Every template follows this pattern:
typescript
import { ScriptTemplate, LockingScript, UnlockingScript, Script, Utils } from '@bsv/sdk'
import BitCom, { Protocol, BitComDecoded } from './BitCom.js'

export const PREFIX = 'PROTOCOL_ID'

export interface ProtocolData {
  bitcomIndex?: number
  // protocol-specific fields
  valid?: boolean
}

export default class Protocol implements ScriptTemplate {
  public readonly data: ProtocolData

  constructor(data: ProtocolData) {
    this.data = data
  }

  static decode(bitcom: BitComDecoded): Protocol[] { /* ... */ }
  static sign(/* params */): Promise<Protocol> { /* ... */ }
  lock(): LockingScript { /* ... */ }
  unlock(): { sign: Function, estimateLength: Function } { /* ... */ }
  verify(): boolean { /* ... */ }
}
所有模板均遵循以下模式:
typescript
import { ScriptTemplate, LockingScript, UnlockingScript, Script, Utils } from '@bsv/sdk'
import BitCom, { Protocol, BitComDecoded } from './BitCom.js'

export const PREFIX = 'PROTOCOL_ID'

export interface ProtocolData {
  bitcomIndex?: number
  // 协议专属字段
  valid?: boolean
}

export default class Protocol implements ScriptTemplate {
  public readonly data: ProtocolData

  constructor(data: ProtocolData) {
    this.data = data
  }

  static decode(bitcom: BitComDecoded): Protocol[] { /* ... */ }
  static sign(/* params */): Promise<Protocol> { /* ... */ }
  lock(): LockingScript { /* ... */ }
  unlock(): { sign: Function, estimateLength: Function } { /* ... */ }
  verify(): boolean { /* ... */ }
}

Creation Process

创建流程

Step 1: Understand the Protocol

步骤1:理解协议

Gather protocol specifications:
  • Protocol prefix/identifier (Bitcoin address or literal string)
  • Field order and data types
  • Signing requirements (if any)
  • Verification logic
收集协议规范:
  • 协议前缀/标识符(比特币地址或字面字符串)
  • 字段顺序和数据类型
  • 签名要求(如有)
  • 验证逻辑

Step 2: Create Template File

步骤2:创建模板文件

Location:
src/template/bitcom/ProtocolName.ts
Required exports:
  • PREFIX
    constant
  • ProtocolData
    interface
  • Default class implementing
    ScriptTemplate
路径:
src/template/bitcom/ProtocolName.ts
必需导出项:
  • PREFIX
    常量
  • ProtocolData
    接口
  • 实现
    ScriptTemplate
    的默认类

Step 3: Implement Core Methods

步骤3:实现核心方法

decode() - Parse from BitComDecoded:
typescript
static decode(bitcom: BitComDecoded): Protocol[] {
  const results: Protocol[] = []
  for (const protocol of bitcom.protocols) {
    if (protocol.protocol === PREFIX) {
      const script = Script.fromBinary(protocol.script)
      const chunks = script.chunks
      // Extract fields from chunks using Utils.toUTF8(chunk.data)
    }
  }
  return results
}
lock() - Generate locking script:
typescript
lock(): LockingScript {
  const script = new Script()
  script.writeBin(Utils.toArray(field1, 'utf8'))
  script.writeBin(Utils.toArray(field2, 'utf8'))

  const protocols: Protocol[] = [{
    protocol: PREFIX,
    script: script.toBinary(),
    pos: 0
  }]

  return new BitCom(protocols).lock()
}
decode() - 从BitComDecoded解析:
typescript
static decode(bitcom: BitComDecoded): Protocol[] {
  const results: Protocol[] = []
  for (const protocol of bitcom.protocols) {
    if (protocol.protocol === PREFIX) {
      const script = Script.fromBinary(protocol.script)
      const chunks = script.chunks
      // 使用Utils.toUTF8(chunk.data)从chunks中提取字段
    }
  }
  return results
}
lock() - 生成锁定脚本:
typescript
lock(): LockingScript {
  const script = new Script()
  script.writeBin(Utils.toArray(field1, 'utf8'))
  script.writeBin(Utils.toArray(field2, 'utf8'))

  const protocols: Protocol[] = [{
    protocol: PREFIX,
    script: script.toBinary(),
    pos: 0
  }]

  return new BitCom(protocols).lock()
}

Step 4: Add to mod.ts

步骤4:添加到mod.ts

Export the new template:
typescript
export { default as Protocol, PREFIX } from './src/template/bitcom/Protocol.js'
export type { ProtocolData, ProtocolOptions } from './src/template/bitcom/Protocol.js'
导出新模板:
typescript
export { default as Protocol, PREFIX } from './src/template/bitcom/Protocol.js'
export type { ProtocolData, ProtocolOptions } from './src/template/bitcom/Protocol.js'

Step 5: Create Pull Request

步骤5:创建拉取请求

  1. Create feature branch:
    git checkout -b feature/protocol-template
  2. Commit changes with descriptive message
  3. Push and create PR to b-open-io/ts-templates
  1. 创建功能分支:
    git checkout -b feature/protocol-template
  2. 提交带有描述性信息的变更
  3. 推送并向b-open-io/ts-templates创建PR

Key Patterns

关键模式

Chunk-Based Parsing

基于Chunk的解析

Always use
script.chunks
directly, never string splitting:
typescript
const script = Script.fromBinary(protocol.script)
const chunks = script.chunks

const field1 = Utils.toUTF8(chunks[0].data ?? [])
const field2 = Utils.toUTF8(chunks[1].data ?? [])
const signature = Array.from(chunks[2].data ?? [])
始终直接使用
script.chunks
,绝不使用字符串拆分:
typescript
const script = Script.fromBinary(protocol.script)
const chunks = script.chunks

const field1 = Utils.toUTF8(chunks[0].data ?? [])
const field2 = Utils.toUTF8(chunks[1].data ?? [])
const signature = Array.from(chunks[2].data ?? [])

Utils Over Buffer

优先使用Utils而非Buffer

Use @bsv/sdk Utils for all byte manipulation:
  • Utils.toArray(string, 'utf8')
    - String to bytes
  • Utils.toUTF8(bytes)
    - Bytes to string
  • Utils.toHex(bytes)
    - Bytes to hex
  • Utils.toBase64(bytes)
    - Bytes to base64
所有字节操作均使用@bsv/sdk的Utils:
  • Utils.toArray(string, 'utf8')
    - 字符串转字节
  • Utils.toUTF8(bytes)
    - 字节转字符串
  • Utils.toHex(bytes)
    - 字节转十六进制
  • Utils.toBase64(bytes)
    - 字节转Base64

Signature Verification

签名验证

For protocols with signatures, use BSM recovery:
typescript
for (let recovery = 0; recovery < 4; recovery++) {
  try {
    const publicKey = sig.RecoverPublicKey(
      recovery,
      new BigNumber(BSM.magicHash(message))
    )
    if (BSM.verify(message, sig, publicKey) &&
        publicKey.toAddress().toString() === address) {
      return true
    }
  } catch { /* try next */ }
}
对于带签名的协议,使用BSM恢复:
typescript
for (let recovery = 0; recovery < 4; recovery++) {
  try {
    const publicKey = sig.RecoverPublicKey(
      recovery,
      new BigNumber(BSM.magicHash(message))
    )
    if (BSM.verify(message, sig, publicKey) &&
        publicKey.toAddress().toString() === address) {
      return true
    }
  } catch { /* 尝试下一个 */ }
}

Additional Resources

额外资源

Reference Files

参考文件

  • references/template-anatomy.md
    - Detailed template structure
  • references/pr-workflow.md
    - Contribution workflow for ts-templates
  • references/template-anatomy.md
    - 详细的模板结构说明
  • references/pr-workflow.md
    - ts-templates的贡献流程

Examples

示例

  • examples/OpReturn.ts
    - Minimal template (no external deps)
  • examples/OpReturn.ts
    - 极简模板(无外部依赖)

More Examples

更多示例

For complete production templates, see the ts-templates repository: https://github.com/b-open-io/ts-templates/tree/master/src/template
Notable templates:
  • bitcom/Sigma.ts
    - Transaction-bound signatures (uses sigma-protocol)
  • bitcom/AIP.ts
    - Author Identity Protocol
  • bitcom/MAP.ts
    - Magic Attribute Protocol
  • bitcom/BAP.ts
    - Bitcoin Attestation Protocol
  • bitcom/B.ts
    - B:// file storage
  • opreturn/OpReturn.ts
    - Simple OP_RETURN
如需完整的生产级模板,请查看ts-templates仓库: https://github.com/b-open-io/ts-templates/tree/master/src/template
值得关注的模板:
  • bitcom/Sigma.ts
    - 交易绑定签名(使用sigma-protocol)
  • bitcom/AIP.ts
    - 作者身份协议
  • bitcom/MAP.ts
    - 魔法属性协议
  • bitcom/BAP.ts
    - 比特币证明协议
  • bitcom/B.ts
    - B://文件存储
  • opreturn/OpReturn.ts
    - 简单OP_RETURN