@smartledger/bsv 5.5.3 → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +142 -0
- package/README.md +38 -38
- package/bin/cli.js +35 -5
- package/bsv-covenant.min.js +6 -6
- package/bsv-gdaf.min.js +2 -2
- package/bsv-ltp.min.js +2 -2
- package/bsv-shamir.min.js +1 -1
- package/bsv-smartcontract.min.js +6 -6
- package/bsv-statuslist.min.js +5 -5
- package/bsv-vcjwt.min.js +1 -1
- package/bsv.bundle.js +2 -2
- package/bsv.d.ts +289 -10
- package/bsv.min.js +2 -2
- package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
- package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
- package/docs/getting-started/INSTALLATION.md +23 -23
- package/docs/getting-started/QUICK_START.md +7 -7
- package/docs/migration/FROM_BSV_1_5_6.md +5 -5
- package/index.js +4 -0
- package/lib/crypto/ecdsa.js +13 -0
- package/lib/crypto/shamir.js +16 -4
- package/lib/gdaf/did-resolver.js +3 -1
- package/lib/gdaf/smartledger-anchor.js +154 -12
- package/lib/ltp/anchor.js +16 -3
- package/lib/ltp/obligation.js +56 -8
- package/lib/ltp/proof.js +4 -2
- package/lib/ltp/right.js +86 -11
- package/lib/ordinals/README.md +170 -0
- package/lib/ordinals/bsv20.js +185 -0
- package/lib/ordinals/index.js +49 -0
- package/lib/ordinals/inscription.js +159 -0
- package/lib/ordinals/ordlock.js +560 -0
- package/lib/smart_contract/builder.js +27 -3
- package/lib/smart_contract/covenant.js +37 -10
- package/lib/smart_contract/covenant_builder.js +7 -5
- package/lib/smart_contract/index.js +28 -15
- package/lib/smart_contract/preimage.js +7 -7
- package/lib/smart_contract/pushtx.js +47 -7
- package/lib/smart_contract/token.js +69 -1
- package/lib/spv/headerchain.js +77 -0
- package/lib/spv/index.js +16 -0
- package/lib/spv/merkleproof.js +108 -0
- package/lib/statuslist/index.js +65 -24
- package/lib/vcjwt/index.js +6 -0
- package/package.json +1 -1
- package/test/credentials-test.js +22 -19
- package/test/crypto/shamir.js +9 -1
- package/test/crypto/shamir_rngcap.js +29 -0
- package/test/gdaf/anchor_spv.js +163 -0
- package/test/ltp/verify_failclosed.js +134 -0
- package/test/ordinals/bsv20.js +126 -0
- package/test/ordinals/inscription.js +71 -0
- package/test/ordinals/ordlock.js +552 -0
- package/test/smart_contract/extract_field.js +61 -0
- package/test/smart_contract/nonenforcing_guard.js +44 -0
- package/test/smart_contract/ordinal_transfer.js +83 -0
- package/test/smart_contract/sighash_marketplace.js +110 -0
- package/test/spv/headerchain.js +86 -0
- package/test/spv/merkleproof.js +133 -0
- package/test/statuslist/failclosed.js +78 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
/**
|
|
3
|
+
* 1Sat Ordinals inscriptions.
|
|
4
|
+
*
|
|
5
|
+
* An inscription is content (a content-type + a body) carried on a 1-satoshi output
|
|
6
|
+
* behind an inert data envelope, appended to a normal locking script (P2PKH by
|
|
7
|
+
* default). The envelope is never executed, so spending is controlled entirely by the
|
|
8
|
+
* base lock while the inscription rides on the satoshi:
|
|
9
|
+
*
|
|
10
|
+
* <lockingScript>
|
|
11
|
+
* OP_FALSE OP_IF
|
|
12
|
+
* "ord"
|
|
13
|
+
* OP_1 <contentType>
|
|
14
|
+
* OP_0 <content>
|
|
15
|
+
* OP_ENDIF
|
|
16
|
+
*
|
|
17
|
+
* This matches the widely-used 1Sat Ordinals format (js-1sat-ord).
|
|
18
|
+
*/
|
|
19
|
+
var bsv = require('../..')
|
|
20
|
+
|
|
21
|
+
var ORD = Buffer.from('ord', 'utf8')
|
|
22
|
+
|
|
23
|
+
function scriptClass () { return bsv.Script }
|
|
24
|
+
function op () { return bsv.Opcode }
|
|
25
|
+
|
|
26
|
+
/** Resolve a base locking script from a Script, an Address, or an address string. */
|
|
27
|
+
function resolveLock (params) {
|
|
28
|
+
var Script = scriptClass()
|
|
29
|
+
if (params.lock) {
|
|
30
|
+
if (params.lock instanceof Script) return params.lock
|
|
31
|
+
if (Buffer.isBuffer(params.lock)) return Script.fromBuffer(params.lock)
|
|
32
|
+
if (typeof params.lock === 'string') return Script.fromHex(params.lock)
|
|
33
|
+
throw new Error('lock must be a Script, Buffer, or hex string')
|
|
34
|
+
}
|
|
35
|
+
if (params.address) {
|
|
36
|
+
var addr = (params.address instanceof bsv.Address)
|
|
37
|
+
? params.address
|
|
38
|
+
: bsv.Address.fromString(String(params.address))
|
|
39
|
+
return Script.buildPublicKeyHashOut(addr)
|
|
40
|
+
}
|
|
41
|
+
throw new Error('buildInscription requires an address or a lock script')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function toBuf (v, enc) {
|
|
45
|
+
if (Buffer.isBuffer(v)) return v
|
|
46
|
+
if (v == null) return Buffer.alloc(0)
|
|
47
|
+
return Buffer.from(String(v), enc || 'utf8')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Build a 1Sat Ordinals inscription locking script: a base lock followed by the
|
|
52
|
+
* inert `OP_FALSE OP_IF ... OP_ENDIF` envelope carrying the content.
|
|
53
|
+
*
|
|
54
|
+
* @param {object} params
|
|
55
|
+
* @param {string|Buffer} params.contentType e.g. 'text/plain', 'image/png'
|
|
56
|
+
* @param {string|Buffer} params.content the inscription body
|
|
57
|
+
* @param {Script|Buffer|string} [params.lock] base locking script (overrides address)
|
|
58
|
+
* @param {Address|string} [params.address] P2PKH owner (used if no `lock`)
|
|
59
|
+
* @returns {Script} the full inscription locking script
|
|
60
|
+
*/
|
|
61
|
+
function buildInscription (params) {
|
|
62
|
+
params = params || {}
|
|
63
|
+
var Opcode = op()
|
|
64
|
+
var lock = resolveLock(params)
|
|
65
|
+
var contentType = toBuf(params.contentType || 'text/plain')
|
|
66
|
+
var content = toBuf(params.content)
|
|
67
|
+
|
|
68
|
+
// Clone the base lock so we never mutate the caller's Script.
|
|
69
|
+
var s = scriptClass().fromBuffer(lock.toBuffer())
|
|
70
|
+
s.add(Opcode.OP_FALSE)
|
|
71
|
+
s.add(Opcode.OP_IF)
|
|
72
|
+
s.add(ORD)
|
|
73
|
+
s.add(Opcode.OP_1)
|
|
74
|
+
s.add(contentType)
|
|
75
|
+
s.add(Opcode.OP_0)
|
|
76
|
+
s.add(content)
|
|
77
|
+
s.add(Opcode.OP_ENDIF)
|
|
78
|
+
return s
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function chunkIsOp (chunk, opcodenum) {
|
|
82
|
+
return chunk && chunk.opcodenum === opcodenum && (chunk.buf == null)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Parse a 1Sat Ordinals inscription out of a locking script.
|
|
87
|
+
* @param {Script|Buffer|string} script
|
|
88
|
+
* @returns {null|{ contentType: string, content: Buffer, contentText: string, lock: Script }}
|
|
89
|
+
* null if the script carries no inscription envelope.
|
|
90
|
+
*/
|
|
91
|
+
function parseInscription (script) {
|
|
92
|
+
var Script = scriptClass()
|
|
93
|
+
var Opcode = op()
|
|
94
|
+
var s = (script instanceof Script) ? script
|
|
95
|
+
: Buffer.isBuffer(script) ? Script.fromBuffer(script)
|
|
96
|
+
: Script.fromHex(script)
|
|
97
|
+
var chunks = s.chunks
|
|
98
|
+
|
|
99
|
+
// Find `OP_FALSE OP_IF "ord"`.
|
|
100
|
+
var start = -1
|
|
101
|
+
for (var i = 0; i + 2 < chunks.length; i++) {
|
|
102
|
+
if (chunkIsOp(chunks[i], Opcode.OP_FALSE) &&
|
|
103
|
+
chunkIsOp(chunks[i + 1], Opcode.OP_IF) &&
|
|
104
|
+
chunks[i + 2].buf && chunks[i + 2].buf.equals(ORD)) {
|
|
105
|
+
start = i
|
|
106
|
+
break
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (start === -1) return null
|
|
110
|
+
|
|
111
|
+
// Everything before the envelope is the base lock.
|
|
112
|
+
var lock = new Script()
|
|
113
|
+
for (var k = 0; k < start; k++) lock.chunks.push(chunks[k])
|
|
114
|
+
|
|
115
|
+
// Walk fields after "ord" until OP_ENDIF: OP_1 => content-type, OP_0 => body.
|
|
116
|
+
var contentType = Buffer.alloc(0)
|
|
117
|
+
var content = Buffer.alloc(0)
|
|
118
|
+
for (var j = start + 3; j < chunks.length; j++) {
|
|
119
|
+
var c = chunks[j]
|
|
120
|
+
if (chunkIsOp(c, Opcode.OP_ENDIF)) break
|
|
121
|
+
if (chunkIsOp(c, Opcode.OP_1) && chunks[j + 1] && chunks[j + 1].buf) {
|
|
122
|
+
contentType = chunks[j + 1].buf; j++
|
|
123
|
+
} else if (chunkIsOp(c, Opcode.OP_0) && chunks[j + 1] && chunks[j + 1].buf) {
|
|
124
|
+
content = chunks[j + 1].buf; j++
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
contentType: contentType.toString('utf8'),
|
|
130
|
+
content: content,
|
|
131
|
+
contentText: content.toString('utf8'),
|
|
132
|
+
lock: lock
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** True if the script carries an inscription envelope. */
|
|
137
|
+
function isInscription (script) {
|
|
138
|
+
try { return parseInscription(script) !== null } catch (e) { return false }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Build the 1-satoshi Transaction.Output carrying an inscription.
|
|
143
|
+
* @returns {Transaction.Output}
|
|
144
|
+
*/
|
|
145
|
+
function createInscriptionOutput (params) {
|
|
146
|
+
params = params || {}
|
|
147
|
+
var satoshis = params.satoshis != null ? params.satoshis : 1
|
|
148
|
+
return new bsv.Transaction.Output({
|
|
149
|
+
script: buildInscription(params),
|
|
150
|
+
satoshis: satoshis
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = {
|
|
155
|
+
buildInscription: buildInscription,
|
|
156
|
+
parseInscription: parseInscription,
|
|
157
|
+
isInscription: isInscription,
|
|
158
|
+
createInscriptionOutput: createInscriptionOutput
|
|
159
|
+
}
|