OP_RETURN
Overview
Simple OP_RETURN Data Storage
import { Transaction, PrivateKey, P2PKH, Script, OP } from '@bsv/sdk'
/**
* Simple OP_RETURN Data Storage
*
* Store arbitrary data in OP_RETURN outputs
*/
class OpReturnDataStore {
/**
* Create an OP_RETURN script with data
*/
createOpReturnScript(data: Buffer | Buffer[]): Script {
const script = new Script()
// Add OP_FALSE (OP_0) and OP_RETURN
script.writeOpCode(OP.OP_FALSE)
script.writeOpCode(OP.OP_RETURN)
// Add data chunks
const dataArray = Array.isArray(data) ? data : [data]
for (const chunk of dataArray) {
script.writeBin(chunk)
}
return script
}
/**
* Store text data on blockchain
*/
async storeText(
senderKey: PrivateKey,
text: string,
utxo: {
txid: string
vout: number
satoshis: number
script: Script
}
): Promise<Transaction> {
try {
const tx = new Transaction()
// Add input
tx.addInput({
sourceTXID: utxo.txid,
sourceOutputIndex: utxo.vout,
unlockingScriptTemplate: new P2PKH().unlock(senderKey),
sequence: 0xffffffff
})
// Add OP_RETURN output with text data
const textBuffer = Buffer.from(text, 'utf8')
tx.addOutput({
satoshis: 0, // OP_RETURN outputs are provably unspendable
lockingScript: this.createOpReturnScript(textBuffer)
})
// Add change output
const fee = 500
const change = utxo.satoshis - fee
if (change > 546) {
tx.addOutput({
satoshis: change,
lockingScript: new P2PKH().lock(senderKey.toPublicKey().toHash())
})
}
await tx.sign()
console.log('Text stored on blockchain')
console.log('Transaction ID:', tx.id('hex'))
console.log('Data size:', textBuffer.length, 'bytes')
return tx
} catch (error) {
throw new Error(`Failed to store text: ${error.message}`)
}
}
/**
* Store multiple data fields
*/
async storeMultipleFields(
senderKey: PrivateKey,
fields: string[],
utxo: {
txid: string
vout: number
satoshis: number
script: Script
}
): Promise<Transaction> {
try {
const tx = new Transaction()
tx.addInput({
sourceTXID: utxo.txid,
sourceOutputIndex: utxo.vout,
unlockingScriptTemplate: new P2PKH().unlock(senderKey),
sequence: 0xffffffff
})
// Convert fields to buffers
const dataBuffers = fields.map(field => Buffer.from(field, 'utf8'))
// Add OP_RETURN output
tx.addOutput({
satoshis: 0,
lockingScript: this.createOpReturnScript(dataBuffers)
})
// Add change
const fee = 500
const change = utxo.satoshis - fee
if (change > 546) {
tx.addOutput({
satoshis: change,
lockingScript: new P2PKH().lock(senderKey.toPublicKey().toHash())
})
}
await tx.sign()
console.log('Multiple fields stored')
console.log('Fields:', fields.length)
console.log('Transaction ID:', tx.id('hex'))
return tx
} catch (error) {
throw new Error(`Failed to store fields: ${error.message}`)
}
}
/**
* Parse OP_RETURN data from script
*/
parseOpReturnData(script: Script): Buffer[] {
const chunks = script.chunks
const data: Buffer[] = []
// Skip OP_FALSE (index 0) and OP_RETURN (index 1)
for (let i = 2; i < chunks.length; i++) {
if (chunks[i].buf) {
data.push(chunks[i].buf)
}
}
return data
}
/**
* Extract OP_RETURN data from transaction
*/
extractData(tx: Transaction): Buffer[] | null {
for (const output of tx.outputs) {
const chunks = output.lockingScript.chunks
// Check if this is an OP_RETURN output
if (chunks.length >= 2 && chunks[1].opCodeNum === OP.OP_RETURN) {
return this.parseOpReturnData(output.lockingScript)
}
}
return null
}
}
/**
* Usage Example
*/
async function simpleOpReturnExample() {
const dataStore = new OpReturnDataStore()
const privateKey = PrivateKey.fromRandom()
const utxo = {
txid: 'funding-tx-id...',
vout: 0,
satoshis: 50000,
script: new P2PKH().lock(privateKey.toPublicKey().toHash())
}
// Store simple text
const tx1 = await dataStore.storeText(
privateKey,
'Hello, BSV!',
utxo
)
// Store multiple fields
const tx2 = await dataStore.storeMultipleFields(
privateKey,
['app_name', 'my_app', 'version', '1.0.0'],
utxo
)
// Extract data
const extractedData = dataStore.extractData(tx1)
if (extractedData) {
console.log('Extracted text:', extractedData[0].toString('utf8'))
}
}Document Timestamping
JSON Data Storage
File Metadata Registry
Related Examples
See Also
Last updated
