This skill should be used when the user asks to "create a script template", "add a new template to ts-templates", "create a BitCom template", "build an OP_RETURN template", or mentions creating...
Create script templates for the b-open-io/ts-templates repository following established patterns.
Every template follows this pattern:
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 { /* ... */ }
}
Gather protocol specifications:
Location: src/template/bitcom/ProtocolName.ts
Required exports:
PREFIX constantProtocolData interfaceScriptTemplatedecode() - Parse from BitComDecoded:
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:
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()
}
Export the new template:
export { default as Protocol, PREFIX } from './src/template/bitcom/Protocol.js'
export type { ProtocolData, ProtocolOptions } from './src/template/bitcom/Protocol.js'
git checkout -b feature/protocol-templateAlways use script.chunks directly, never string splitting:
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 ?? [])
Use @bsv/sdk Utils for all byte manipulation:
Utils.toArray(string, 'utf8') - String to bytesUtils.toUTF8(bytes) - Bytes to stringUtils.toHex(bytes) - Bytes to hexUtils.toBase64(bytes) - Bytes to base64For protocols with signatures, use BSM recovery:
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 */ }
}
references/template-anatomy.md - Detailed template structurereferences/pr-workflow.md - Contribution workflow for ts-templatesexamples/OpReturn.ts - Minimal template (no external deps)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 Protocolbitcom/MAP.ts - Magic Attribute Protocolbitcom/BAP.ts - Bitcoin Attestation Protocolbitcom/B.ts - B:// file storageopreturn/OpReturn.ts - Simple OP_RETURN