Atomic Swaps
Overview
HTLC Script Builder
import { Transaction, PrivateKey, PublicKey, Script, Hash, OP } from '@bsv/sdk'
/**
* Hash Time-Locked Contract (HTLC) Builder
*
* Creates and manages HTLC scripts for atomic swaps.
*/
class HTLCBuilder {
/**
* Create an HTLC locking script
*
* The HTLC allows spending in two ways:
* 1. With the secret preimage (before timeout) - for the recipient
* 2. After timeout with refund key - for the sender
*
* @param recipientPubKey - Public key of the recipient
* @param refundPubKey - Public key for refund (sender)
* @param secretHash - Hash of the secret (SHA256)
* @param lockTime - Unix timestamp for timeout
* @returns HTLC locking script
*/
createHTLCScript(
recipientPubKey: PublicKey,
refundPubKey: PublicKey,
secretHash: string,
lockTime: number
): Script {
try {
// HTLC Script:
// IF
// OP_SHA256 <secretHash> OP_EQUALVERIFY <recipientPubKey> OP_CHECKSIG
// ELSE
// <lockTime> OP_CHECKLOCKTIMEVERIFY OP_DROP <refundPubKey> OP_CHECKSIG
// ENDIF
const script = new Script()
// IF branch (claim with secret)
script.chunks.push({ op: OP.OP_IF })
script.chunks.push({ op: OP.OP_SHA256 })
script.chunks.push({ data: Buffer.from(secretHash, 'hex') })
script.chunks.push({ op: OP.OP_EQUALVERIFY })
script.chunks.push({ data: recipientPubKey.toBuffer() })
script.chunks.push({ op: OP.OP_CHECKSIG })
// ELSE branch (refund after timeout)
script.chunks.push({ op: OP.OP_ELSE })
script.chunks.push({ data: this.numberToBuffer(lockTime) })
script.chunks.push({ op: OP.OP_CHECKLOCKTIMEVERIFY })
script.chunks.push({ op: OP.OP_DROP })
script.chunks.push({ data: refundPubKey.toBuffer() })
script.chunks.push({ op: OP.OP_CHECKSIG })
// End IF
script.chunks.push({ op: OP.OP_ENDIF })
return script
} catch (error) {
throw new Error(`HTLC script creation failed: ${error.message}`)
}
}
/**
* Create unlocking script to claim with secret
*/
createClaimScript(
secret: string,
signature: Buffer,
recipientPubKey: PublicKey
): Script {
const script = new Script()
// Push signature
script.chunks.push({ data: signature })
// Push secret preimage
script.chunks.push({ data: Buffer.from(secret, 'hex') })
// Push TRUE to select IF branch
script.chunks.push({ op: OP.OP_TRUE })
return script
}
/**
* Create unlocking script for refund
*/
createRefundScript(
signature: Buffer,
refundPubKey: PublicKey
): Script {
const script = new Script()
// Push signature
script.chunks.push({ data: signature })
// Push FALSE to select ELSE branch
script.chunks.push({ op: OP.OP_FALSE })
return script
}
/**
* Generate a random secret
*/
generateSecret(): { secret: string; hash: string } {
const secret = Buffer.from(PrivateKey.fromRandom().toHex(), 'hex')
const hash = Hash.sha256(secret)
return {
secret: secret.toString('hex'),
hash: hash.toString('hex')
}
}
/**
* Convert number to buffer for script
*/
private numberToBuffer(num: number): Buffer {
if (num === 0) return Buffer.from([])
if (num === -1) return Buffer.from([0x81])
const isNegative = num < 0
const absNum = Math.abs(num)
const bytes: number[] = []
let n = absNum
while (n > 0) {
bytes.push(n & 0xff)
n >>= 8
}
if (bytes[bytes.length - 1] & 0x80) {
bytes.push(isNegative ? 0x80 : 0x00)
} else if (isNegative) {
bytes[bytes.length - 1] |= 0x80
}
return Buffer.from(bytes)
}
}
/**
* Usage Example
*/
async function htlcExample() {
const builder = new HTLCBuilder()
// Generate keys
const recipientKey = PrivateKey.fromRandom()
const refundKey = PrivateKey.fromRandom()
// Generate secret
const { secret, hash } = builder.generateSecret()
// Lock time: 24 hours from now
const lockTime = Math.floor(Date.now() / 1000) + (24 * 60 * 60)
// Create HTLC script
const htlcScript = builder.createHTLCScript(
recipientKey.toPublicKey(),
refundKey.toPublicKey(),
hash,
lockTime
)
console.log('HTLC Script created')
console.log('Secret hash:', hash)
console.log('Lock time:', new Date(lockTime * 1000).toISOString())
}Atomic Swap Implementation
Cross-Chain Atomic Swap
Swap Safety and Recovery
Related Examples
See Also
Last updated
