smartledger-bsv 3.3.5 → 3.4.4
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 +400 -0
- package/README.md +235 -80
- package/SECURITY.md +88 -0
- package/anchor-entry.js +1 -0
- package/bin/cli.js +354 -0
- package/bsv-anchor.min.js +12 -0
- package/bsv-covenant.min.js +8 -8
- package/bsv-didweb.min.js +12 -0
- package/bsv-gdaf.min.js +9 -9
- package/bsv-ltp.min.js +9 -9
- package/bsv-mnemonic.min.js +2 -2
- package/bsv-shamir.min.js +3 -3
- package/bsv-smartcontract.min.js +9 -9
- package/bsv-statuslist.min.js +18 -0
- package/bsv-vcjwt.min.js +12 -0
- package/bsv.bundle.js +9 -9
- package/bsv.d.ts +486 -9
- package/bsv.min.js +8 -8
- package/build/webpack.anchor.config.js +17 -0
- package/build/webpack.didweb.config.js +17 -0
- package/build/webpack.statuslist.config.js +17 -0
- package/build/webpack.vcjwt.config.js +17 -0
- package/didweb-entry.js +1 -0
- package/docs/COVENANT_DEVELOPMENT_RESOLVED.md +2 -2
- package/docs/MODULE_REFERENCE_COMPLETE.md +61 -58
- package/docs/advanced/LEGAL_TOKEN_PROTOCOL.md +3 -3
- package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
- package/docs/getting-started/INSTALLATION.md +30 -30
- package/docs/getting-started/QUICK_START.md +18 -18
- package/docs/migration/FROM_BSV_1_5_6.md +16 -10
- package/docs/technical/roadmap.md +3 -3
- package/gdaf-entry.js +1 -2
- package/index.js +68 -9
- package/lib/anchor/index.js +102 -0
- package/lib/browser-utxo-manager-es5.js +11 -4
- package/lib/browser-utxo-manager.js +15 -8
- package/lib/didweb/index.js +177 -0
- package/lib/ltp/claim.js +1 -0
- package/lib/ltp/obligation.js +1 -0
- package/lib/ltp/registry.js +2 -0
- package/lib/ltp/right.js +1 -0
- package/lib/smart_contract/covenant.js +10 -1
- package/lib/smartutxo.js +20 -12
- package/lib/statuslist/index.js +164 -0
- package/lib/transaction/transaction.js +8 -1
- package/lib/util/_.js +7 -1
- package/lib/vcjwt/index.js +189 -0
- package/ltp-entry.js +1 -2
- package/package.json +21 -15
- package/statuslist-entry.js +1 -0
- package/utilities/blockchain-state.js +32 -23
- package/vcjwt-entry.js +1 -0
- package/demos/README.md +0 -188
- package/demos/architecture_demo.js +0 -247
- package/demos/browser-test.html +0 -1208
- package/demos/bsv_wallet_demo.js +0 -242
- package/demos/complete_ltp_demo.js +0 -511
- package/demos/debug_tools_demo.js +0 -87
- package/demos/demo_features.js +0 -123
- package/demos/easy_interface_demo.js +0 -109
- package/demos/ecies_demo.js +0 -182
- package/demos/gdaf_core_test.js +0 -131
- package/demos/gdaf_demo.js +0 -237
- package/demos/ltp_demo.js +0 -361
- package/demos/ltp_primitives_demo.js +0 -403
- package/demos/message_demo.js +0 -209
- package/demos/preimage_separation_demo.js +0 -383
- package/demos/script_helper_demo.js +0 -289
- package/demos/security_demo.js +0 -287
- package/demos/shamir_demo.js +0 -121
- package/demos/simple_demo.js +0 -204
- package/demos/simple_p2pkh_demo.js +0 -169
- package/demos/simple_utxo_preimage_demo.js +0 -196
- package/demos/smart_contract_demo.html +0 -1347
- package/demos/smart_contract_demo.js +0 -910
- package/demos/utxo_generator_demo.js +0 -244
- package/demos/validation_pipeline_demo.js +0 -155
- package/demos/web3keys.html +0 -740
- package/examples/README.md +0 -200
- package/examples/basic/transaction-creation.js +0 -534
- package/examples/basic/transaction_signature_api_gap.js +0 -178
- package/examples/complete_workflow_demo.js +0 -783
- package/examples/covenants/advanced_covenant_demo.js +0 -219
- package/examples/covenants/covenant_interface_demo.js +0 -270
- package/examples/covenants/covenant_manual_signature_resolved.js +0 -212
- package/examples/covenants/covenant_signature_template.js +0 -117
- package/examples/covenants2/covenant_bidirectional_example.js +0 -262
- package/examples/covenants2/covenant_utils_demo.js +0 -120
- package/examples/covenants2/preimage_covenant_utils.js +0 -287
- package/examples/covenants2/production_integration.js +0 -256
- package/examples/data/covenant_utxos.json +0 -28
- package/examples/data/utxos.json +0 -26
- package/examples/definitive_working_demo.js +0 -261
- package/examples/final_working_contracts.js +0 -338
- package/examples/preimage/README.md +0 -178
- package/examples/preimage/extract_preimage_bidirectional.js +0 -421
- package/examples/preimage/generate_sample_preimage.js +0 -208
- package/examples/preimage/generate_sighash_examples.js +0 -152
- package/examples/preimage/parse_preimage.js +0 -117
- package/examples/preimage/test_preimage_extractor.js +0 -53
- package/examples/preimage/test_varint_extraction.js +0 -95
- package/examples/scripts/custom_script_helper_example.js +0 -273
- package/examples/scripts/custom_script_signature_test.js +0 -344
- package/examples/scripts/script_interpreter.js +0 -193
- package/examples/smart_contract/complete_workflow_demo.js +0 -343
- package/examples/smart_contract/covenant_builder_demo.js +0 -176
- package/examples/smart_contract/script_testing_integration.js +0 -198
- package/examples/smart_contract_templates.js +0 -718
- package/examples/working_smart_contracts.js +0 -348
- package/lib/smart_contract/test_integration.js +0 -269
- package/tests/browser-compatibility/README.md +0 -35
- package/tests/browser-compatibility/test-cdn-vs-local.html +0 -186
- package/tests/browser-compatibility/test-pbkdf2.html +0 -51
- package/tests/bundle-completeness-test.html +0 -131
- package/tests/bundle-demo.html +0 -476
- package/tests/smartcontract-test.html +0 -239
- package/tests/standalone-modules-test.html +0 -260
- package/tests/test.html +0 -612
- package/tests/test_builtin_verify.js +0 -117
- package/tests/test_debug_integration.js +0 -71
- package/tests/test_ecdsa_little.js +0 -70
- package/tests/test_shamir.js +0 -221
- package/tests/test_smartverify_der.js +0 -110
- package/tests/test_standalone_shamir.html +0 -83
- package/tests/unpkg-demo.html +0 -194
- package/utilities/blockchain-state.json +0 -118565
package/index.js
CHANGED
|
@@ -2,17 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
var bsv = module.exports
|
|
4
4
|
|
|
5
|
-
// Initialize dependencies first to avoid circular dependency issues
|
|
5
|
+
// Initialize dependencies first to avoid circular dependency issues.
|
|
6
|
+
//
|
|
7
|
+
// `bn.js`, `bs58`, and `elliptic` are declared runtime deps in
|
|
8
|
+
// package.json. In Node they MUST be installed — silently swallowing
|
|
9
|
+
// a require() failure here used to mask broken installs behind cryptic
|
|
10
|
+
// downstream errors in lib/crypto/bn.js etc. We now let those throw in
|
|
11
|
+
// Node so the failure points at the real cause (`npm install` is broken).
|
|
12
|
+
// In a browser context the bundler is expected to inline these; if it
|
|
13
|
+
// somehow didn't, we tolerate the absence rather than block the whole
|
|
14
|
+
// library load.
|
|
6
15
|
bsv.deps = bsv.deps || {}
|
|
7
|
-
|
|
16
|
+
bsv.deps._ = require('./lib/util/_')
|
|
17
|
+
bsv.deps.Buffer = (typeof Buffer !== 'undefined') ? Buffer : null
|
|
18
|
+
|
|
19
|
+
if (typeof window === 'undefined') {
|
|
20
|
+
// Node — hard require; failure means broken install.
|
|
8
21
|
bsv.deps.bnjs = require('bn.js')
|
|
9
22
|
bsv.deps.bs58 = require('bs58')
|
|
10
|
-
bsv.deps.Buffer = (typeof Buffer !== 'undefined') ? Buffer : null
|
|
11
23
|
bsv.deps.elliptic = require('elliptic')
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
24
|
+
} else {
|
|
25
|
+
// Browser — bundler-resolved; tolerate absence individually.
|
|
26
|
+
try { bsv.deps.bnjs = require('bn.js') } catch (e) { /* polyfilled by bundler */ }
|
|
27
|
+
try { bsv.deps.bs58 = require('bs58') } catch (e) { /* polyfilled by bundler */ }
|
|
28
|
+
try { bsv.deps.elliptic = require('elliptic') } catch (e) { /* polyfilled by bundler */ }
|
|
16
29
|
}
|
|
17
30
|
|
|
18
31
|
// module information
|
|
@@ -29,7 +42,15 @@ bsv.versionGuard = function (version) {
|
|
|
29
42
|
bsv.versionGuard(global._bsv)
|
|
30
43
|
global._bsv = bsv.version
|
|
31
44
|
|
|
32
|
-
// SmartLedger security information
|
|
45
|
+
// SmartLedger security information.
|
|
46
|
+
// NOTE: these properties advertise that hardening *helpers* ship in this
|
|
47
|
+
// package (`bsv.SmartVerify`, `bsv.EllipticFixed`, `signature.toCanonical()`,
|
|
48
|
+
// etc.). They are NOT automatically wired into the default verify path:
|
|
49
|
+
// `transaction.verify()`, `signature.verify()`, and `Message().verify()` go
|
|
50
|
+
// through `lib/crypto/ecdsa.js`, which uses BSV's own pure-JS ECDSA and does
|
|
51
|
+
// not route through `SmartVerify` or `EllipticFixed`. To get the strict
|
|
52
|
+
// input validation, call `bsv.SmartVerify.smartVerify(...)` explicitly.
|
|
53
|
+
// See the Security section of README.md.
|
|
33
54
|
bsv.isHardened = true
|
|
34
55
|
bsv.hardenedBy = 'SmartLedger'
|
|
35
56
|
bsv.baseVersion = 'v1.5.6'
|
|
@@ -119,7 +140,9 @@ try {
|
|
|
119
140
|
try {
|
|
120
141
|
bsv.BrowserUTXOManager = require('./lib/browser-utxo-manager-es5')
|
|
121
142
|
} catch (e) {
|
|
122
|
-
|
|
143
|
+
if (typeof window === 'undefined') {
|
|
144
|
+
console.warn('[bsv] BrowserUTXOManager failed to load:', e.message)
|
|
145
|
+
}
|
|
123
146
|
}
|
|
124
147
|
|
|
125
148
|
// Node.js specific tools (advanced development tools)
|
|
@@ -136,6 +159,42 @@ if (typeof window === 'undefined' && typeof require === 'function') {
|
|
|
136
159
|
// Global Digital Attestation Framework (GDAF)
|
|
137
160
|
bsv.GDAF = require('./lib/gdaf')
|
|
138
161
|
|
|
162
|
+
// DID:web Module (W3C standards-based DIDs)
|
|
163
|
+
try {
|
|
164
|
+
bsv.DIDWeb = require('./lib/didweb')
|
|
165
|
+
} catch (e) {
|
|
166
|
+
if (typeof window === 'undefined') {
|
|
167
|
+
console.warn('[bsv] DIDWeb module failed to load:', e.message)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// VC-JWT Module (W3C Verifiable Credentials)
|
|
172
|
+
try {
|
|
173
|
+
bsv.VcJwt = require('./lib/vcjwt')
|
|
174
|
+
} catch (e) {
|
|
175
|
+
if (typeof window === 'undefined') {
|
|
176
|
+
console.warn('[bsv] VcJwt module failed to load:', e.message)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// StatusList2021 Module (Credential revocation)
|
|
181
|
+
try {
|
|
182
|
+
bsv.StatusList = require('./lib/statuslist')
|
|
183
|
+
} catch (e) {
|
|
184
|
+
if (typeof window === 'undefined') {
|
|
185
|
+
console.warn('[bsv] StatusList module failed to load:', e.message)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Anchor Module (BSV hash anchoring)
|
|
190
|
+
try {
|
|
191
|
+
bsv.Anchor = require('./lib/anchor')
|
|
192
|
+
} catch (e) {
|
|
193
|
+
if (typeof window === 'undefined') {
|
|
194
|
+
console.warn('[bsv] Anchor module failed to load:', e.message)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
139
198
|
// GDAF Direct Access Methods (for easier developer experience)
|
|
140
199
|
bsv.createDID = function(publicKey) {
|
|
141
200
|
var gdaf = new bsv.GDAF()
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* BSV Anchor Module
|
|
5
|
+
* Hash anchoring helpers for on-chain evidence (no PII)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
var crypto = require('crypto')
|
|
9
|
+
|
|
10
|
+
// SHA-256 hex hash
|
|
11
|
+
function sha256Hex(data) {
|
|
12
|
+
var buffer
|
|
13
|
+
if (typeof data === 'string') {
|
|
14
|
+
buffer = Buffer.from(data, 'utf8')
|
|
15
|
+
} else if (Buffer.isBuffer(data)) {
|
|
16
|
+
buffer = data
|
|
17
|
+
} else if (data instanceof Uint8Array) {
|
|
18
|
+
buffer = Buffer.from(data)
|
|
19
|
+
} else {
|
|
20
|
+
throw new Error('Data must be string, Buffer, or Uint8Array')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return crypto.createHash('sha256').update(buffer).digest('hex')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Build anchor payload for OP_RETURN
|
|
27
|
+
function buildAnchorPayload(params) {
|
|
28
|
+
if (!params.kind || !params.hash || !params.issuerDid) {
|
|
29
|
+
throw new Error('kind, hash, and issuerDid are required')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var validKinds = ['VC_ANCHOR_SHA256', 'STATUSLIST_SHA256', 'PRESENTATION_SHA256']
|
|
33
|
+
if (validKinds.indexOf(params.kind) === -1) {
|
|
34
|
+
throw new Error('Invalid kind. Must be one of: ' + validKinds.join(', '))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Validate hash format (64 hex characters)
|
|
38
|
+
if (!/^[a-fA-F0-9]{64}$/.test(params.hash)) {
|
|
39
|
+
throw new Error('Invalid hash format. Must be 64 hex characters')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
var payload = {
|
|
43
|
+
protocol: 'SmartLedger',
|
|
44
|
+
version: '1.0',
|
|
45
|
+
type: params.kind,
|
|
46
|
+
hash: params.hash,
|
|
47
|
+
issuer: params.issuerDid,
|
|
48
|
+
timestamp: params.issuedAt || new Date().toISOString()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
json: JSON.stringify(payload)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Verify anchor hash against original data
|
|
57
|
+
function verifyAnchorHash(originalData, anchorHash) {
|
|
58
|
+
var computed = sha256Hex(originalData)
|
|
59
|
+
return computed === anchorHash
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Extract anchor info from OP_RETURN data
|
|
63
|
+
function parseAnchorPayload(opReturnData) {
|
|
64
|
+
try {
|
|
65
|
+
var parsed = JSON.parse(opReturnData)
|
|
66
|
+
|
|
67
|
+
if (parsed.protocol !== 'SmartLedger') {
|
|
68
|
+
return { valid: false, error: 'Invalid protocol' }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
var validTypes = ['VC_ANCHOR_SHA256', 'STATUSLIST_SHA256', 'PRESENTATION_SHA256']
|
|
72
|
+
if (validTypes.indexOf(parsed.type) === -1) {
|
|
73
|
+
return { valid: false, error: 'Invalid anchor type' }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!/^[a-fA-F0-9]{64}$/.test(parsed.hash)) {
|
|
77
|
+
return { valid: false, error: 'Invalid hash format' }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
valid: true,
|
|
82
|
+
protocol: parsed.protocol,
|
|
83
|
+
version: parsed.version,
|
|
84
|
+
type: parsed.type,
|
|
85
|
+
hash: parsed.hash,
|
|
86
|
+
issuer: parsed.issuer,
|
|
87
|
+
timestamp: parsed.timestamp
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
return {
|
|
91
|
+
valid: false,
|
|
92
|
+
error: 'Failed to parse anchor payload: ' + error.message
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
sha256Hex: sha256Hex,
|
|
99
|
+
buildAnchorPayload: buildAnchorPayload,
|
|
100
|
+
verifyAnchorHash: verifyAnchorHash,
|
|
101
|
+
parseAnchorPayload: parseAnchorPayload
|
|
102
|
+
}
|
|
@@ -5,6 +5,13 @@
|
|
|
5
5
|
* Lightweight UTXO management for browser environments with configurable storage
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
// Set window.BSV_DEBUG = true (browser) or BSV_DEBUG=1 (Node) to enable info logs.
|
|
9
|
+
var debug = function () {
|
|
10
|
+
var enabled = (typeof process !== 'undefined' && process.env && process.env.BSV_DEBUG) ||
|
|
11
|
+
(typeof window !== 'undefined' && window.BSV_DEBUG)
|
|
12
|
+
if (enabled) console.log.apply(console, arguments)
|
|
13
|
+
}
|
|
14
|
+
|
|
8
15
|
var STORAGE_TYPES = {
|
|
9
16
|
MEMORY: 'memory',
|
|
10
17
|
SESSION: 'session',
|
|
@@ -75,7 +82,7 @@ BrowserUTXOManager.prototype.loadFromStorage = function() {
|
|
|
75
82
|
this.metadata = parsed.metadata
|
|
76
83
|
}
|
|
77
84
|
|
|
78
|
-
|
|
85
|
+
debug('✅ BrowserUTXOManager: Loaded ' + this.utxos.size + ' UTXOs from ' + this.options.storage + ' storage')
|
|
79
86
|
} catch (e) {
|
|
80
87
|
console.error('Failed to load UTXOs from storage:', e)
|
|
81
88
|
}
|
|
@@ -96,7 +103,7 @@ BrowserUTXOManager.prototype.saveToStorage = function() {
|
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
storage.setItem(this.options.storageKey, JSON.stringify(data))
|
|
99
|
-
|
|
106
|
+
debug('💾 BrowserUTXOManager: Saved ' + this.utxos.size + ' UTXOs to ' + this.options.storage + ' storage')
|
|
100
107
|
} catch (e) {
|
|
101
108
|
console.error('Failed to save UTXOs to storage:', e)
|
|
102
109
|
}
|
|
@@ -110,7 +117,7 @@ BrowserUTXOManager.prototype.addUTXO = function(utxo) {
|
|
|
110
117
|
var key = utxo.txid + ':' + utxo.vout
|
|
111
118
|
|
|
112
119
|
if (this.utxos.has(key)) {
|
|
113
|
-
|
|
120
|
+
debug('⚠️ UTXO already exists: ' + key)
|
|
114
121
|
return false
|
|
115
122
|
}
|
|
116
123
|
|
|
@@ -298,7 +305,7 @@ BrowserUTXOManager.prototype.importData = function(jsonData, merge) {
|
|
|
298
305
|
})
|
|
299
306
|
}
|
|
300
307
|
|
|
301
|
-
|
|
308
|
+
debug('✅ BrowserUTXOManager: Imported ' + (data.utxos && data.utxos.length || 0) + ' UTXOs')
|
|
302
309
|
return true
|
|
303
310
|
} catch (e) {
|
|
304
311
|
console.error('Failed to import UTXO data:', e)
|
|
@@ -5,6 +5,13 @@
|
|
|
5
5
|
* Lightweight UTXO management for browser environments with configurable storage
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
// Set window.BSV_DEBUG = true (browser) or BSV_DEBUG=1 (Node) to enable info logs.
|
|
9
|
+
var debug = function () {
|
|
10
|
+
var enabled = (typeof process !== 'undefined' && process.env && process.env.BSV_DEBUG) ||
|
|
11
|
+
(typeof window !== 'undefined' && window.BSV_DEBUG)
|
|
12
|
+
if (enabled) console.log.apply(console, arguments)
|
|
13
|
+
}
|
|
14
|
+
|
|
8
15
|
/**
|
|
9
16
|
* Storage types available for browser UTXO management
|
|
10
17
|
*/
|
|
@@ -127,7 +134,7 @@ function BrowserUTXOManager(options) {
|
|
|
127
134
|
}
|
|
128
135
|
|
|
129
136
|
this._updateMetadata()
|
|
130
|
-
|
|
137
|
+
debug(`✅ BrowserUTXOManager: Loaded ${this.utxos.size} UTXOs from ${this.options.storage} storage`)
|
|
131
138
|
|
|
132
139
|
} catch (error) {
|
|
133
140
|
console.error('BrowserUTXOManager: Error loading from storage:', error.message)
|
|
@@ -163,7 +170,7 @@ function BrowserUTXOManager(options) {
|
|
|
163
170
|
})
|
|
164
171
|
|
|
165
172
|
storage.setItem(this.options.storageKey, JSON.stringify(data))
|
|
166
|
-
|
|
173
|
+
debug(`💾 BrowserUTXOManager: Saved ${this.utxos.size} UTXOs to ${this.options.storage} storage`)
|
|
167
174
|
|
|
168
175
|
} catch (error) {
|
|
169
176
|
console.error('BrowserUTXOManager: Error saving to storage:', error.message)
|
|
@@ -186,7 +193,7 @@ function BrowserUTXOManager(options) {
|
|
|
186
193
|
|
|
187
194
|
// Check if already exists
|
|
188
195
|
if (this.utxos.has(key)) {
|
|
189
|
-
|
|
196
|
+
debug(`⚠️ UTXO already exists: ${key}`)
|
|
190
197
|
return false
|
|
191
198
|
}
|
|
192
199
|
|
|
@@ -217,7 +224,7 @@ function BrowserUTXOManager(options) {
|
|
|
217
224
|
this.saveToStorage()
|
|
218
225
|
}
|
|
219
226
|
|
|
220
|
-
|
|
227
|
+
debug(`✅ UTXO added: ${key} (${utxo.satoshis} sats)`)
|
|
221
228
|
return true
|
|
222
229
|
|
|
223
230
|
} catch (error) {
|
|
@@ -305,7 +312,7 @@ function BrowserUTXOManager(options) {
|
|
|
305
312
|
}
|
|
306
313
|
}
|
|
307
314
|
|
|
308
|
-
|
|
315
|
+
debug(`❌ UTXO spent: ${key} in ${spentUTXO.spentInTx}`)
|
|
309
316
|
})
|
|
310
317
|
|
|
311
318
|
this._updateMetadata()
|
|
@@ -446,11 +453,11 @@ function BrowserUTXOManager(options) {
|
|
|
446
453
|
const storage = this._getStorage()
|
|
447
454
|
if (storage) {
|
|
448
455
|
storage.removeItem(this.options.storageKey)
|
|
449
|
-
|
|
456
|
+
debug(`🔄 Cleared ${this.options.storage} storage`)
|
|
450
457
|
}
|
|
451
458
|
}
|
|
452
459
|
|
|
453
|
-
|
|
460
|
+
debug('🔄 BrowserUTXOManager reset complete')
|
|
454
461
|
}
|
|
455
462
|
|
|
456
463
|
/**
|
|
@@ -513,7 +520,7 @@ function BrowserUTXOManager(options) {
|
|
|
513
520
|
this.saveToStorage()
|
|
514
521
|
}
|
|
515
522
|
|
|
516
|
-
|
|
523
|
+
debug('✅ BrowserUTXOManager: Imported ' + (data.utxos && data.utxos.length || 0) + ' UTXOs')
|
|
517
524
|
return true
|
|
518
525
|
|
|
519
526
|
} catch (error) {
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DID:web Module
|
|
5
|
+
* Legally-recognizable DID (did:web) generation and management
|
|
6
|
+
* Supports ES256 (P-256) and ES256K (secp256k1) keys
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
var crypto = require('crypto')
|
|
10
|
+
|
|
11
|
+
// Generate issuer keys (ES256 or ES256K)
|
|
12
|
+
async function generateIssuerKeys(opts) {
|
|
13
|
+
opts = opts || {}
|
|
14
|
+
var alg = opts.alg || 'ES256'
|
|
15
|
+
var kid = opts.kid || 'key-' + Date.now()
|
|
16
|
+
|
|
17
|
+
if (alg !== 'ES256' && alg !== 'ES256K') {
|
|
18
|
+
throw new Error('Invalid algorithm. Must be ES256 or ES256K')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
var keyPair
|
|
22
|
+
if (alg === 'ES256') {
|
|
23
|
+
// P-256 (NIST curve)
|
|
24
|
+
keyPair = crypto.generateKeyPairSync('ec', {
|
|
25
|
+
namedCurve: 'P-256',
|
|
26
|
+
publicKeyEncoding: { type: 'spki', format: 'pem' },
|
|
27
|
+
privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
|
|
28
|
+
})
|
|
29
|
+
} else {
|
|
30
|
+
// secp256k1
|
|
31
|
+
keyPair = crypto.generateKeyPairSync('ec', {
|
|
32
|
+
namedCurve: 'secp256k1',
|
|
33
|
+
publicKeyEncoding: { type: 'spki', format: 'pem' },
|
|
34
|
+
privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Convert to JWK format
|
|
39
|
+
var publicJwk = crypto.createPublicKey(keyPair.publicKey).export({ format: 'jwk' })
|
|
40
|
+
var privateJwk = crypto.createPrivateKey(keyPair.privateKey).export({ format: 'jwk' })
|
|
41
|
+
|
|
42
|
+
// Add required JWK fields
|
|
43
|
+
publicJwk.kid = kid
|
|
44
|
+
publicJwk.alg = alg
|
|
45
|
+
publicJwk.use = 'sig'
|
|
46
|
+
publicJwk.kty = 'EC'
|
|
47
|
+
|
|
48
|
+
privateJwk.kid = kid
|
|
49
|
+
privateJwk.alg = alg
|
|
50
|
+
privateJwk.use = 'sig'
|
|
51
|
+
privateJwk.kty = 'EC'
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
privateJwk: privateJwk,
|
|
55
|
+
publicJwk: publicJwk,
|
|
56
|
+
kid: kid,
|
|
57
|
+
alg: alg
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Build did:web documents (did.json and jwks.json)
|
|
62
|
+
function buildDidWebDocuments(params) {
|
|
63
|
+
if (!params.domain) {
|
|
64
|
+
throw new Error('domain is required')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
var domain = params.domain
|
|
68
|
+
var did = 'did:web:' + domain.replace(/:/g, '%3A')
|
|
69
|
+
|
|
70
|
+
var verificationMethods = []
|
|
71
|
+
var publicKeys = []
|
|
72
|
+
|
|
73
|
+
// Add P-256 key if provided
|
|
74
|
+
if (params.p256) {
|
|
75
|
+
var p256Method = {
|
|
76
|
+
id: did + '#' + params.p256.kid,
|
|
77
|
+
type: 'JsonWebKey2020',
|
|
78
|
+
controller: did,
|
|
79
|
+
publicKeyJwk: params.p256.jwk
|
|
80
|
+
}
|
|
81
|
+
verificationMethods.push(p256Method)
|
|
82
|
+
publicKeys.push(params.p256.jwk)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Add secp256k1 key if provided
|
|
86
|
+
if (params.k1) {
|
|
87
|
+
var k1Method = {
|
|
88
|
+
id: did + '#' + params.k1.kid,
|
|
89
|
+
type: 'JsonWebKey2020',
|
|
90
|
+
controller: did,
|
|
91
|
+
publicKeyJwk: params.k1.jwk
|
|
92
|
+
}
|
|
93
|
+
verificationMethods.push(k1Method)
|
|
94
|
+
publicKeys.push(params.k1.jwk)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (verificationMethods.length === 0) {
|
|
98
|
+
throw new Error('At least one key (p256 or k1) must be provided')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Build DID Document
|
|
102
|
+
var didDocument = {
|
|
103
|
+
'@context': [
|
|
104
|
+
'https://www.w3.org/ns/did/v1',
|
|
105
|
+
'https://w3id.org/security/suites/jws-2020/v1'
|
|
106
|
+
],
|
|
107
|
+
id: did,
|
|
108
|
+
verificationMethod: verificationMethods,
|
|
109
|
+
authentication: verificationMethods.map(function(vm) { return vm.id }),
|
|
110
|
+
assertionMethod: verificationMethods.map(function(vm) { return vm.id })
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (params.controllerName) {
|
|
114
|
+
didDocument.controller = params.controllerName
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Build JWKS
|
|
118
|
+
var jwks = {
|
|
119
|
+
keys: publicKeys
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
did: did,
|
|
124
|
+
didDocument: didDocument,
|
|
125
|
+
jwks: jwks
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Rotate issuer key
|
|
130
|
+
function rotateIssuerKey(params) {
|
|
131
|
+
if (!params.domain || !params.newKey) {
|
|
132
|
+
throw new Error('domain and newKey are required')
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
var domain = params.domain
|
|
136
|
+
var did = 'did:web:' + domain.replace(/:/g, '%3A')
|
|
137
|
+
var keepOldForDays = params.keepOldForDays || 30
|
|
138
|
+
|
|
139
|
+
// Create verification method for new key
|
|
140
|
+
var newMethod = {
|
|
141
|
+
id: did + '#' + params.newKey.kid,
|
|
142
|
+
type: 'JsonWebKey2020',
|
|
143
|
+
controller: did,
|
|
144
|
+
publicKeyJwk: params.newKey.jwk
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Build updated DID Document with new key as primary
|
|
148
|
+
var didDocument = {
|
|
149
|
+
'@context': [
|
|
150
|
+
'https://www.w3.org/ns/did/v1',
|
|
151
|
+
'https://w3id.org/security/suites/jws-2020/v1'
|
|
152
|
+
],
|
|
153
|
+
id: did,
|
|
154
|
+
verificationMethod: [newMethod],
|
|
155
|
+
authentication: [newMethod.id],
|
|
156
|
+
assertionMethod: [newMethod.id],
|
|
157
|
+
rotationInfo: {
|
|
158
|
+
rotatedAt: new Date().toISOString(),
|
|
159
|
+
gracePeriodDays: keepOldForDays
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
var jwks = {
|
|
164
|
+
keys: [params.newKey.jwk]
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
didDocument: didDocument,
|
|
169
|
+
jwks: jwks
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
module.exports = {
|
|
174
|
+
generateIssuerKeys: generateIssuerKeys,
|
|
175
|
+
buildDidWebDocuments: buildDidWebDocuments,
|
|
176
|
+
rotateIssuerKey: rotateIssuerKey
|
|
177
|
+
}
|
package/lib/ltp/claim.js
CHANGED
|
@@ -691,6 +691,7 @@ var ClaimValidator = {
|
|
|
691
691
|
* @private
|
|
692
692
|
*/
|
|
693
693
|
_generateBatchId: function() {
|
|
694
|
+
// Non-security: identifier collision avoidance only
|
|
694
695
|
var data = 'batch_' + Date.now() + '_' + Math.random()
|
|
695
696
|
return Hash.sha256(Buffer.from(data)).toString('hex').substring(0, 16)
|
|
696
697
|
},
|
package/lib/ltp/obligation.js
CHANGED
|
@@ -929,6 +929,7 @@ var ObligationToken = {
|
|
|
929
929
|
* @private
|
|
930
930
|
*/
|
|
931
931
|
_generateUUID: function() {
|
|
932
|
+
// Non-security: identifier collision avoidance only (not RFC 4122 v4 random)
|
|
932
933
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
933
934
|
var r = Math.random() * 16 | 0
|
|
934
935
|
var v = c === 'x' ? r : (r & 0x3 | 0x8)
|
package/lib/ltp/registry.js
CHANGED
|
@@ -552,6 +552,7 @@ var LTPRegistry = {
|
|
|
552
552
|
* @private
|
|
553
553
|
*/
|
|
554
554
|
_generateRegistryId: function() {
|
|
555
|
+
// Non-security: identifier collision avoidance only
|
|
555
556
|
var data = 'reg_' + Date.now() + '_' + Math.random()
|
|
556
557
|
return 'reg_' + Hash.sha256(Buffer.from(data)).toString('hex').substring(0, 16)
|
|
557
558
|
},
|
|
@@ -685,6 +686,7 @@ var LTPRegistry = {
|
|
|
685
686
|
* @private
|
|
686
687
|
*/
|
|
687
688
|
_generateAuditId: function() {
|
|
689
|
+
// Non-security: identifier collision avoidance only
|
|
688
690
|
var data = 'audit_' + Date.now() + '_' + Math.random()
|
|
689
691
|
return 'audit_' + Hash.sha256(Buffer.from(data)).toString('hex').substring(0, 12)
|
|
690
692
|
},
|
package/lib/ltp/right.js
CHANGED
|
@@ -752,6 +752,7 @@ var RightToken = {
|
|
|
752
752
|
* @private
|
|
753
753
|
*/
|
|
754
754
|
_generateUUID: function() {
|
|
755
|
+
// Non-security: identifier collision avoidance only (not RFC 4122 v4 random)
|
|
755
756
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
756
757
|
var r = Math.random() * 16 | 0
|
|
757
758
|
var v = c === 'x' ? r : (r & 0x3 | 0x8)
|
|
@@ -26,6 +26,15 @@ try {
|
|
|
26
26
|
fs = null
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
// Set BSV_DEBUG=1 (Node) or window.BSV_DEBUG = true (browser) to surface
|
|
30
|
+
// informational warnings from this module. Matches the gating pattern
|
|
31
|
+
// used by lib/browser-utxo-manager-es5.js since v3.4.1.
|
|
32
|
+
var debug = function () {
|
|
33
|
+
var enabled = (typeof process !== 'undefined' && process.env && process.env.BSV_DEBUG) ||
|
|
34
|
+
(typeof window !== 'undefined' && window.BSV_DEBUG)
|
|
35
|
+
if (enabled) console.log.apply(console, arguments)
|
|
36
|
+
}
|
|
37
|
+
|
|
29
38
|
/**
|
|
30
39
|
* Covenant Class - Advanced covenant management
|
|
31
40
|
* @param {PrivateKey} privateKey - Private key for covenant operations
|
|
@@ -212,7 +221,7 @@ Covenant.prototype.validate = function(spendingTx, covenantUtxo) {
|
|
|
212
221
|
*/
|
|
213
222
|
Covenant.prototype.save = function(covenantUtxo) {
|
|
214
223
|
if (!fs) {
|
|
215
|
-
|
|
224
|
+
debug('File system operations not available in browser environment')
|
|
216
225
|
return covenantUtxo
|
|
217
226
|
}
|
|
218
227
|
|
package/lib/smartutxo.js
CHANGED
|
@@ -5,6 +5,15 @@
|
|
|
5
5
|
* Provides blockchain state management and UTXO tracking for testing and development
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
// Set BSV_DEBUG=1 (Node) or window.BSV_DEBUG = true (browser) to surface
|
|
9
|
+
// info/warning output from this module. Matches the gating pattern used
|
|
10
|
+
// by lib/browser-utxo-manager-es5.js since v3.4.1.
|
|
11
|
+
const debug = function () {
|
|
12
|
+
const enabled = (typeof process !== 'undefined' && process.env && process.env.BSV_DEBUG) ||
|
|
13
|
+
(typeof window !== 'undefined' && window.BSV_DEBUG)
|
|
14
|
+
if (enabled) console.log.apply(console, arguments)
|
|
15
|
+
}
|
|
16
|
+
|
|
8
17
|
// Browser-compatible imports
|
|
9
18
|
let fs, path, crypto, blockchainState
|
|
10
19
|
|
|
@@ -16,8 +25,7 @@ if (typeof window === 'undefined' && typeof require === 'function') {
|
|
|
16
25
|
crypto = require('crypto')
|
|
17
26
|
blockchainState = require('../utilities/blockchain-state')
|
|
18
27
|
} catch (e) {
|
|
19
|
-
|
|
20
|
-
console.warn('SmartUTXO: Running in browser mode - some features may be limited')
|
|
28
|
+
debug('SmartUTXO: Running in browser mode - some features may be limited')
|
|
21
29
|
}
|
|
22
30
|
}
|
|
23
31
|
|
|
@@ -40,7 +48,7 @@ class SmartUTXOManager {
|
|
|
40
48
|
const state = blockchainState.loadBlockchainState()
|
|
41
49
|
return state
|
|
42
50
|
} catch (error) {
|
|
43
|
-
|
|
51
|
+
debug('⚠️ Could not load blockchain state:', error.message)
|
|
44
52
|
return null
|
|
45
53
|
}
|
|
46
54
|
}
|
|
@@ -53,9 +61,9 @@ class SmartUTXOManager {
|
|
|
53
61
|
const state = blockchainState.loadBlockchainState()
|
|
54
62
|
blockchainState.saveBlockchainState(state)
|
|
55
63
|
const utxoCount = Object.keys(state.globalUTXOSet || {}).length
|
|
56
|
-
|
|
64
|
+
debug(`💾 Saved blockchain state with ${utxoCount} UTXOs`)
|
|
57
65
|
} catch (error) {
|
|
58
|
-
|
|
66
|
+
debug('⚠️ Could not save blockchain state:', error.message)
|
|
59
67
|
}
|
|
60
68
|
}
|
|
61
69
|
|
|
@@ -76,7 +84,7 @@ class SmartUTXOManager {
|
|
|
76
84
|
// Return the wallet's UTXOs
|
|
77
85
|
return state.wallets[address].utxos || []
|
|
78
86
|
} catch (error) {
|
|
79
|
-
|
|
87
|
+
debug('⚠️ Error getting UTXOs:', error.message)
|
|
80
88
|
return []
|
|
81
89
|
}
|
|
82
90
|
}
|
|
@@ -90,7 +98,7 @@ class SmartUTXOManager {
|
|
|
90
98
|
// Use the correct API: addUTXO(utxo, ownerAddress)
|
|
91
99
|
blockchainState.addUTXO(utxo, utxo.address)
|
|
92
100
|
} catch (error) {
|
|
93
|
-
|
|
101
|
+
debug('⚠️ Error adding UTXO:', error.message)
|
|
94
102
|
}
|
|
95
103
|
}
|
|
96
104
|
|
|
@@ -106,7 +114,7 @@ class SmartUTXOManager {
|
|
|
106
114
|
blockchainState.spendUTXO(input.txid, input.vout, spentInTx)
|
|
107
115
|
}
|
|
108
116
|
} catch (error) {
|
|
109
|
-
|
|
117
|
+
debug('⚠️ Error spending UTXOs:', error.message)
|
|
110
118
|
}
|
|
111
119
|
}
|
|
112
120
|
|
|
@@ -156,7 +164,7 @@ class SmartUTXOManager {
|
|
|
156
164
|
// Return the wallet's total value
|
|
157
165
|
return state.wallets[address].totalValue || 0
|
|
158
166
|
} catch (error) {
|
|
159
|
-
|
|
167
|
+
debug('⚠️ Error getting balance:', error.message)
|
|
160
168
|
return 0
|
|
161
169
|
}
|
|
162
170
|
}
|
|
@@ -176,7 +184,7 @@ class SmartUTXOManager {
|
|
|
176
184
|
lastUpdated: state.metadata.lastUpdated
|
|
177
185
|
}
|
|
178
186
|
} catch (error) {
|
|
179
|
-
|
|
187
|
+
debug('⚠️ Error getting stats:', error.message)
|
|
180
188
|
return { totalUTXOs: 0, totalValue: 0, totalWallets: 0, blockHeight: 0 }
|
|
181
189
|
}
|
|
182
190
|
}
|
|
@@ -189,10 +197,10 @@ class SmartUTXOManager {
|
|
|
189
197
|
const statePath = path.join(__dirname, '../utilities/blockchain-state.json')
|
|
190
198
|
if (fs.existsSync(statePath)) {
|
|
191
199
|
fs.unlinkSync(statePath)
|
|
192
|
-
|
|
200
|
+
debug('🔄 Blockchain state reset')
|
|
193
201
|
}
|
|
194
202
|
} catch (error) {
|
|
195
|
-
|
|
203
|
+
debug('⚠️ Could not reset blockchain state:', error.message)
|
|
196
204
|
}
|
|
197
205
|
}
|
|
198
206
|
}
|