@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.
Files changed (60) hide show
  1. package/CHANGELOG.md +142 -0
  2. package/README.md +38 -38
  3. package/bin/cli.js +35 -5
  4. package/bsv-covenant.min.js +6 -6
  5. package/bsv-gdaf.min.js +2 -2
  6. package/bsv-ltp.min.js +2 -2
  7. package/bsv-shamir.min.js +1 -1
  8. package/bsv-smartcontract.min.js +6 -6
  9. package/bsv-statuslist.min.js +5 -5
  10. package/bsv-vcjwt.min.js +1 -1
  11. package/bsv.bundle.js +2 -2
  12. package/bsv.d.ts +289 -10
  13. package/bsv.min.js +2 -2
  14. package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
  15. package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
  16. package/docs/getting-started/INSTALLATION.md +23 -23
  17. package/docs/getting-started/QUICK_START.md +7 -7
  18. package/docs/migration/FROM_BSV_1_5_6.md +5 -5
  19. package/index.js +4 -0
  20. package/lib/crypto/ecdsa.js +13 -0
  21. package/lib/crypto/shamir.js +16 -4
  22. package/lib/gdaf/did-resolver.js +3 -1
  23. package/lib/gdaf/smartledger-anchor.js +154 -12
  24. package/lib/ltp/anchor.js +16 -3
  25. package/lib/ltp/obligation.js +56 -8
  26. package/lib/ltp/proof.js +4 -2
  27. package/lib/ltp/right.js +86 -11
  28. package/lib/ordinals/README.md +170 -0
  29. package/lib/ordinals/bsv20.js +185 -0
  30. package/lib/ordinals/index.js +49 -0
  31. package/lib/ordinals/inscription.js +159 -0
  32. package/lib/ordinals/ordlock.js +560 -0
  33. package/lib/smart_contract/builder.js +27 -3
  34. package/lib/smart_contract/covenant.js +37 -10
  35. package/lib/smart_contract/covenant_builder.js +7 -5
  36. package/lib/smart_contract/index.js +28 -15
  37. package/lib/smart_contract/preimage.js +7 -7
  38. package/lib/smart_contract/pushtx.js +47 -7
  39. package/lib/smart_contract/token.js +69 -1
  40. package/lib/spv/headerchain.js +77 -0
  41. package/lib/spv/index.js +16 -0
  42. package/lib/spv/merkleproof.js +108 -0
  43. package/lib/statuslist/index.js +65 -24
  44. package/lib/vcjwt/index.js +6 -0
  45. package/package.json +1 -1
  46. package/test/credentials-test.js +22 -19
  47. package/test/crypto/shamir.js +9 -1
  48. package/test/crypto/shamir_rngcap.js +29 -0
  49. package/test/gdaf/anchor_spv.js +163 -0
  50. package/test/ltp/verify_failclosed.js +134 -0
  51. package/test/ordinals/bsv20.js +126 -0
  52. package/test/ordinals/inscription.js +71 -0
  53. package/test/ordinals/ordlock.js +552 -0
  54. package/test/smart_contract/extract_field.js +61 -0
  55. package/test/smart_contract/nonenforcing_guard.js +44 -0
  56. package/test/smart_contract/ordinal_transfer.js +83 -0
  57. package/test/smart_contract/sighash_marketplace.js +110 -0
  58. package/test/spv/headerchain.js +86 -0
  59. package/test/spv/merkleproof.js +133 -0
  60. 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
+ }