@smartledger/bsv 7.9.0 → 7.10.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 +103 -0
- package/README.md +38 -38
- package/bsv-covenant.min.js +1 -1
- package/bsv-ecies.min.js +1 -1
- package/bsv-gdaf.min.js +54 -54
- package/bsv-ltp.min.js +58 -85
- package/bsv-message.min.js +2 -2
- package/bsv-mnemonic.min.js +12 -14
- package/bsv-script-helper.min.js +1 -1
- package/bsv-shamir.min.js +14 -16
- package/bsv-smartcontract.min.js +23 -25
- package/bsv.bundle.js +54 -54
- package/bsv.min.js +54 -54
- package/build/esbuild.js +86 -5
- 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 +9 -1
- package/lib/covenant/helpers.js +146 -0
- package/lib/covenant/index.js +21 -0
- package/lib/covenant/pushtx.js +243 -0
- package/lib/covenant-interface.js +418 -397
- package/lib/custom-script-helper.js +44 -38
- package/lib/ecies/bitcore-ecies.js +3 -4
- package/lib/ecies/electrum-ecies.js +4 -6
- package/lib/ecies/errors.js +1 -1
- package/lib/gdaf/attestation-signer.js +7 -7
- package/lib/gdaf/attestation-verifier.js +5 -6
- package/lib/gdaf/did-resolver.js +10 -9
- package/lib/gdaf/smartledger-anchor.js +13 -12
- package/lib/gdaf/zk-prover.js +8 -8
- package/lib/ltp/anchor.js +2 -3
- package/lib/ltp/claim.js +2 -3
- package/lib/ltp/index.js +2 -3
- package/lib/ltp/obligation.js +9 -9
- package/lib/ltp/proof.js +7 -7
- package/lib/ltp/registry.js +4 -5
- package/lib/ltp/right.js +11 -11
- package/lib/message/index.js +5 -4
- package/lib/message/message.js +11 -11
- package/lib/mnemonic/errors.js +1 -1
- package/lib/mnemonic/index.js +5 -4
- package/lib/mnemonic/mnemonic.js +22 -10
- package/lib/ordinals/bsv20.js +4 -4
- package/lib/ordinals/inscription.js +8 -12
- package/lib/ordinals/ordlock.js +26 -21
- package/lib/smart_contract/authorizers.js +8 -6
- package/lib/smart_contract/builder.js +32 -26
- package/lib/smart_contract/covenant.js +32 -25
- package/lib/smart_contract/covenant_helpers.js +8 -139
- package/lib/smart_contract/debugger.js +9 -6
- package/lib/smart_contract/dsl.js +5 -6
- package/lib/smart_contract/index.js +11 -8
- package/lib/smart_contract/locks.js +3 -4
- package/lib/smart_contract/opcode_list.js +2 -3
- package/lib/smart_contract/pels.js +4 -5
- package/lib/smart_contract/preimage.js +11 -7
- package/lib/smart_contract/pushtx.js +8 -263
- package/lib/smart_contract/script_interpreter.js +112 -105
- package/lib/smart_contract/script_tester.js +24 -18
- package/lib/smart_contract/script_utils.js +15 -14
- package/lib/smart_contract/sighash.js +23 -15
- package/lib/smart_contract/stack_examiner.js +70 -63
- package/lib/smart_contract/token.js +6 -6
- package/lib/smart_contract/utxo_generator.js +21 -15
- package/lib/smartutxo.js +27 -21
- package/lib/spv/headerchain.js +3 -3
- package/lib/spv/merkleproof.js +3 -3
- package/package.json +4 -2
- package/test/build/bundle_externals.js +116 -0
- package/version.js +1 -1
package/lib/mnemonic/errors.js
CHANGED
package/lib/mnemonic/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
bsv.Mnemonic = require('./mnemonic')
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
// Previously this module required the package root and registered itself onto
|
|
2
|
+
// it (`bsv.Mnemonic = require('./mnemonic')`), which made lib/ depend on
|
|
3
|
+
// index.js. The registration was redundant — index.js assigns bsv.Mnemonic
|
|
4
|
+
// itself — so this is now a plain re-export.
|
|
5
|
+
module.exports = require('./mnemonic')
|
package/lib/mnemonic/mnemonic.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var BN =
|
|
3
|
+
var HDPrivateKey = require('../hdprivatekey')
|
|
4
|
+
var BN = require('../crypto/bn')
|
|
5
5
|
var unorm = require('unorm')
|
|
6
|
-
var _ =
|
|
6
|
+
var _ = require('../util/_')
|
|
7
7
|
|
|
8
8
|
var pbkdf2 = require('./pbkdf2')
|
|
9
9
|
var errors = require('./errors')
|
|
10
|
+
// Named bsvErrors, not errors: `errors` above is this module's OWN error set.
|
|
11
|
+
// The library-wide errors module is a different object and must not shadow it.
|
|
12
|
+
var bsvErrors = require('../errors')
|
|
10
13
|
|
|
11
|
-
var Hash =
|
|
12
|
-
var Random =
|
|
14
|
+
var Hash = require('../crypto/hash')
|
|
15
|
+
var Random = require('../crypto/random')
|
|
13
16
|
|
|
14
|
-
var $ =
|
|
17
|
+
var $ = require('../util/preconditions')
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* This is an immutable class that represents a BIP39 Mnemonic code.
|
|
@@ -53,7 +56,7 @@ var Mnemonic = function (data, wordlist) {
|
|
|
53
56
|
} else if (_.isNumber(data)) {
|
|
54
57
|
ent = data
|
|
55
58
|
} else if (data) {
|
|
56
|
-
throw new
|
|
59
|
+
throw new bsvErrors.InvalidArgument('data', 'Must be a Buffer, a string or an integer')
|
|
57
60
|
}
|
|
58
61
|
ent = ent || 128
|
|
59
62
|
|
|
@@ -73,7 +76,7 @@ var Mnemonic = function (data, wordlist) {
|
|
|
73
76
|
throw new errors.InvalidMnemonic(phrase)
|
|
74
77
|
}
|
|
75
78
|
if (ent % 32 !== 0 || ent < 128) {
|
|
76
|
-
throw new
|
|
79
|
+
throw new bsvErrors.InvalidArgument('ENT', 'Values must be ENT > 128 and ENT % 32 == 0')
|
|
77
80
|
}
|
|
78
81
|
|
|
79
82
|
phrase = phrase || Mnemonic._mnemonic(ent, wordlist)
|
|
@@ -241,7 +244,7 @@ Mnemonic.fromSeed = function (seed, wordlist) {
|
|
|
241
244
|
*/
|
|
242
245
|
Mnemonic.prototype.toHDPrivateKey = function (passphrase, network) {
|
|
243
246
|
var seed = this.toSeed(passphrase)
|
|
244
|
-
return
|
|
247
|
+
return HDPrivateKey.fromSeed(seed, network)
|
|
245
248
|
}
|
|
246
249
|
|
|
247
250
|
/**
|
|
@@ -329,6 +332,15 @@ Mnemonic._entropyChecksum = function (entropy) {
|
|
|
329
332
|
return checksum
|
|
330
333
|
}
|
|
331
334
|
|
|
332
|
-
|
|
335
|
+
// Back-reference to the whole library, preserved as public API. Defined as a
|
|
336
|
+
// lazy getter rather than `Mnemonic.bsv = require('../../')`: this module is
|
|
337
|
+
// loaded while index.js is still initializing, so an eager require would
|
|
338
|
+
// capture a half-built namespace. Resolving on first access defers it past
|
|
339
|
+
// load and removes the module-init cycle.
|
|
340
|
+
Object.defineProperty(Mnemonic, 'bsv', {
|
|
341
|
+
configurable: true,
|
|
342
|
+
enumerable: true,
|
|
343
|
+
get: function () { return require('../../') }
|
|
344
|
+
})
|
|
333
345
|
|
|
334
346
|
module.exports = Mnemonic
|
package/lib/ordinals/bsv20.js
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
* are never coerced to JS numbers. `dec` (decimals, 0–18) scales display only.
|
|
18
18
|
*/
|
|
19
19
|
var inscription = require('./inscription')
|
|
20
|
+
var Script = require('../script')
|
|
21
|
+
var Output = require('../transaction/output')
|
|
20
22
|
|
|
21
23
|
var CONTENT_TYPE = 'application/bsv-20'
|
|
22
24
|
var MAX_DEC = 18
|
|
@@ -261,8 +263,7 @@ function buildDeployMint (params) {
|
|
|
261
263
|
}
|
|
262
264
|
|
|
263
265
|
function outputFor (script, satoshis) {
|
|
264
|
-
|
|
265
|
-
return new bsv.Transaction.Output({ script: script, satoshis: satoshis != null ? satoshis : 1 })
|
|
266
|
+
return new Output({ script: script, satoshis: satoshis != null ? satoshis : 1 })
|
|
266
267
|
}
|
|
267
268
|
|
|
268
269
|
/** 1-sat Output helpers mirroring the builders. */
|
|
@@ -276,8 +277,7 @@ function createAuthOutput (params) { return outputFor(buildAuth(params), params
|
|
|
276
277
|
|
|
277
278
|
/** Extract the JSON body from a locking script, a JSON string, a Buffer, or an object. */
|
|
278
279
|
function bodyOf (input) {
|
|
279
|
-
|
|
280
|
-
if (input && typeof input === 'object' && !Buffer.isBuffer(input) && !(input instanceof bsv.Script)) {
|
|
280
|
+
if (input && typeof input === 'object' && !Buffer.isBuffer(input) && !(input instanceof Script)) {
|
|
281
281
|
return input // already a parsed object
|
|
282
282
|
}
|
|
283
283
|
if (typeof input === 'string' && input.trim()[0] === '{') return input // raw JSON string
|
|
@@ -16,13 +16,13 @@
|
|
|
16
16
|
*
|
|
17
17
|
* This matches the widely-used 1Sat Ordinals format (js-1sat-ord).
|
|
18
18
|
*/
|
|
19
|
-
var
|
|
19
|
+
var Script = require('../script')
|
|
20
|
+
var Opcode = require('../opcode')
|
|
21
|
+
var Address = require('../address')
|
|
22
|
+
var Output = require('../transaction/output')
|
|
20
23
|
|
|
21
24
|
var ORD = Buffer.from('ord', 'utf8')
|
|
22
25
|
|
|
23
|
-
function scriptClass () { return bsv.Script }
|
|
24
|
-
function op () { return bsv.Opcode }
|
|
25
|
-
|
|
26
26
|
/** Describe a rejected value for an error message, without dumping its contents. */
|
|
27
27
|
function typeName (v) {
|
|
28
28
|
if (v === null) return 'null'
|
|
@@ -50,7 +50,6 @@ var CONTENT_ALIASES = ['data', 'body', 'payload', 'text', 'message']
|
|
|
50
50
|
|
|
51
51
|
/** Resolve a base locking script from a Script, an Address, or an address string. */
|
|
52
52
|
function resolveLock (params) {
|
|
53
|
-
var Script = scriptClass()
|
|
54
53
|
var hasLock = params.lock != null
|
|
55
54
|
var hasAddress = params.address != null
|
|
56
55
|
|
|
@@ -81,9 +80,9 @@ function resolveLock (params) {
|
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
if (hasAddress) {
|
|
84
|
-
var addr = (params.address instanceof
|
|
83
|
+
var addr = (params.address instanceof Address)
|
|
85
84
|
? params.address
|
|
86
|
-
:
|
|
85
|
+
: Address.fromString(String(params.address))
|
|
87
86
|
return Script.buildPublicKeyHashOut(addr)
|
|
88
87
|
}
|
|
89
88
|
|
|
@@ -111,7 +110,6 @@ function resolveLock (params) {
|
|
|
111
110
|
*/
|
|
112
111
|
function buildInscription (params) {
|
|
113
112
|
params = params || {}
|
|
114
|
-
var Opcode = op()
|
|
115
113
|
var lock = resolveLock(params)
|
|
116
114
|
|
|
117
115
|
if (params.content == null) {
|
|
@@ -137,7 +135,7 @@ function buildInscription (params) {
|
|
|
137
135
|
}
|
|
138
136
|
|
|
139
137
|
// Clone the base lock so we never mutate the caller's Script.
|
|
140
|
-
var s =
|
|
138
|
+
var s = Script.fromBuffer(lock.toBuffer())
|
|
141
139
|
s.add(Opcode.OP_FALSE)
|
|
142
140
|
s.add(Opcode.OP_IF)
|
|
143
141
|
s.add(ORD)
|
|
@@ -168,8 +166,6 @@ function chunkIsOp (chunk, opcodenum) {
|
|
|
168
166
|
* null if the script carries no inscription envelope.
|
|
169
167
|
*/
|
|
170
168
|
function parseInscription (script) {
|
|
171
|
-
var Script = scriptClass()
|
|
172
|
-
var Opcode = op()
|
|
173
169
|
var s = (script instanceof Script) ? script
|
|
174
170
|
: Buffer.isBuffer(script) ? Script.fromBuffer(script)
|
|
175
171
|
: Script.fromHex(script)
|
|
@@ -235,7 +231,7 @@ function createInscriptionOutput (params) {
|
|
|
235
231
|
if (typeof satoshis !== 'number' || !Number.isInteger(satoshis) || satoshis < 1) {
|
|
236
232
|
throw new Error('satoshis must be a positive integer (1 for a standard 1Sat ordinal)')
|
|
237
233
|
}
|
|
238
|
-
return new
|
|
234
|
+
return new Output({
|
|
239
235
|
script: buildInscription(params),
|
|
240
236
|
satoshis: satoshis
|
|
241
237
|
})
|
package/lib/ordinals/ordlock.js
CHANGED
|
@@ -37,14 +37,19 @@
|
|
|
37
37
|
*
|
|
38
38
|
* Requires post-Genesis limits: call SmartContract.enableGenesis() before verifying.
|
|
39
39
|
*/
|
|
40
|
-
var
|
|
41
|
-
var
|
|
42
|
-
var H = require('../smart_contract/covenant_helpers')
|
|
40
|
+
var P = require('../covenant/pushtx')
|
|
41
|
+
var H = require('../covenant/helpers')
|
|
43
42
|
var inscription = require('./inscription')
|
|
44
43
|
|
|
45
|
-
var Script =
|
|
46
|
-
var Opcode =
|
|
47
|
-
var
|
|
44
|
+
var Script = require('../script')
|
|
45
|
+
var Opcode = require('../opcode')
|
|
46
|
+
var Address = require('../address')
|
|
47
|
+
var PublicKey = require('../publickey')
|
|
48
|
+
var Hash = require('../crypto/hash')
|
|
49
|
+
var Transaction = require('../transaction')
|
|
50
|
+
var Input = require('../transaction/input')
|
|
51
|
+
var Output = require('../transaction/output')
|
|
52
|
+
var BufferReader = require('../encoding/bufferreader')
|
|
48
53
|
|
|
49
54
|
// OrdLock commits to the FULL output set (so payments can be pinned) but leaves the
|
|
50
55
|
// input set open for the buyer's funding — SIGHASH_ALL|ANYONECANPAY|FORKID (0xc1).
|
|
@@ -73,9 +78,9 @@ function coerceScript (v) {
|
|
|
73
78
|
|
|
74
79
|
/** Coerce an Address, PublicKey, PrivateKey, or address string to an Address. */
|
|
75
80
|
function toAddress (v) {
|
|
76
|
-
if (v instanceof
|
|
81
|
+
if (v instanceof Address) return v
|
|
77
82
|
if (v && typeof v.toAddress === 'function') return v.toAddress() // PublicKey / PrivateKey
|
|
78
|
-
return
|
|
83
|
+
return Address.fromString(String(v))
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
/** Resolve a 20-byte HASH160 owner commitment from an Address/PublicKey/key or 20-byte Buffer. */
|
|
@@ -84,7 +89,7 @@ function resolvePubKeyHash (owner) {
|
|
|
84
89
|
if (owner.length !== 20) throw new Error('seller pubkeyhash buffer must be 20 bytes (HASH160)')
|
|
85
90
|
return owner
|
|
86
91
|
}
|
|
87
|
-
if (owner instanceof
|
|
92
|
+
if (owner instanceof PublicKey) return Hash.sha256ripemd160(owner.toBuffer())
|
|
88
93
|
return toAddress(owner).hashBuffer
|
|
89
94
|
}
|
|
90
95
|
|
|
@@ -95,15 +100,15 @@ function resolvePubKeyHash (owner) {
|
|
|
95
100
|
*/
|
|
96
101
|
function payOutputFor (payTo, price) {
|
|
97
102
|
assertSats(price, 'payment price')
|
|
98
|
-
return new
|
|
103
|
+
return new Output({
|
|
99
104
|
script: Script.buildPublicKeyHashOut(toAddress(payTo)), satoshis: price
|
|
100
105
|
})
|
|
101
106
|
}
|
|
102
107
|
|
|
103
108
|
/** Coerce one payment spec to a Transaction.Output. */
|
|
104
109
|
function outputFromSpec (spec) {
|
|
105
|
-
if (spec instanceof
|
|
106
|
-
if (Buffer.isBuffer(spec)) return
|
|
110
|
+
if (spec instanceof Output) return spec
|
|
111
|
+
if (Buffer.isBuffer(spec)) return Output.fromBufferReader(new BufferReader(spec))
|
|
107
112
|
var to = spec.payTo != null ? spec.payTo : spec.address
|
|
108
113
|
var amt = spec.satoshis != null ? spec.satoshis : spec.price
|
|
109
114
|
if (to == null || amt == null) throw new Error('payment spec needs {address|payTo, satoshis|price}')
|
|
@@ -125,7 +130,7 @@ function resolvePayOutputs (params) {
|
|
|
125
130
|
if (params.price != null) {
|
|
126
131
|
var payTo = params.payTo != null ? params.payTo : params.seller
|
|
127
132
|
// A pre-built Output as payTo is used verbatim (its own value); otherwise build P2PKH(price).
|
|
128
|
-
var first = (payTo instanceof
|
|
133
|
+
var first = (payTo instanceof Output) ? payTo : payOutputFor(payTo, params.price)
|
|
129
134
|
var arr = [first]
|
|
130
135
|
if (params.royalties) params.royalties.forEach(function (r) { arr.push(outputFromSpec(r)) })
|
|
131
136
|
return arr
|
|
@@ -199,7 +204,7 @@ function chunkIsOp (chunk, opcodenum) {
|
|
|
199
204
|
function splitPayBlob (blob) {
|
|
200
205
|
var br = new BufferReader(blob)
|
|
201
206
|
var outs = []
|
|
202
|
-
while (!br.eof()) outs.push(
|
|
207
|
+
while (!br.eof()) outs.push(Output.fromBufferReader(br))
|
|
203
208
|
return outs
|
|
204
209
|
}
|
|
205
210
|
|
|
@@ -296,7 +301,7 @@ function parseOrdLock (script, opts) {
|
|
|
296
301
|
if (rebuilt.toHex() !== s.toHex()) return null
|
|
297
302
|
|
|
298
303
|
return {
|
|
299
|
-
seller: { pubKeyHash: sellerPKH, address:
|
|
304
|
+
seller: { pubKeyHash: sellerPKH, address: Address.fromPublicKeyHash(sellerPKH, network).toString() },
|
|
300
305
|
payOutputs: payOutputs,
|
|
301
306
|
payBlob: payBlob,
|
|
302
307
|
totalPrice: totalPrice,
|
|
@@ -317,7 +322,7 @@ function isOrdLock (script, opts) { return parseOrdLock(script, opts) !== null }
|
|
|
317
322
|
function listInscriptionOutput (params) {
|
|
318
323
|
params = params || {}
|
|
319
324
|
var satoshis = params.satoshis != null ? params.satoshis : 1
|
|
320
|
-
return new
|
|
325
|
+
return new Output({ script: buildOrdLock(params), satoshis: satoshis })
|
|
321
326
|
}
|
|
322
327
|
|
|
323
328
|
/**
|
|
@@ -426,7 +431,7 @@ function cancel (params) {
|
|
|
426
431
|
|
|
427
432
|
/** Add an input spending `outpoint` under `script` worth `satoshis`, script-sig empty. */
|
|
428
433
|
function addSpendInput (tx, outpoint, script, satoshis) {
|
|
429
|
-
tx.addInput(new
|
|
434
|
+
tx.addInput(new Input({
|
|
430
435
|
prevTxId: outpoint.txid || outpoint.prevTxId,
|
|
431
436
|
outputIndex: outpoint.outputIndex != null ? outpoint.outputIndex : outpoint.vout,
|
|
432
437
|
script: Script.empty()
|
|
@@ -479,11 +484,11 @@ function buildListingTx (params) {
|
|
|
479
484
|
throw new Error('buildListingTx: insufficient funding — need ' + fee + ' sat fee, funded ' + fundingTotal)
|
|
480
485
|
}
|
|
481
486
|
|
|
482
|
-
var tx = new
|
|
487
|
+
var tx = new Transaction()
|
|
483
488
|
addSpendInput(tx, ordinal, ordinal.script, ordSats) // input 0 = the ordinal (P2PKH)
|
|
484
489
|
funding.forEach(function (f) { addSpendInput(tx, f, f.script, f.satoshis) })
|
|
485
490
|
|
|
486
|
-
tx.addOutput(new
|
|
491
|
+
tx.addOutput(new Output({ script: lock, satoshis: ordSats })) // output 0 = listing
|
|
487
492
|
if (change > 0) {
|
|
488
493
|
tx.addOutput(payOutputFor(params.changeAddress || ordinal.privateKey.toAddress(), change))
|
|
489
494
|
}
|
|
@@ -533,7 +538,7 @@ function buildPurchaseTx (params) {
|
|
|
533
538
|
var payOuts = params.payOutputs
|
|
534
539
|
? params.payOutputs.map(outputFromSpec)
|
|
535
540
|
: parsed.payOutputs.map(function (p) {
|
|
536
|
-
return new
|
|
541
|
+
return new Output({ script: p.script, satoshis: p.satoshis })
|
|
537
542
|
})
|
|
538
543
|
var paidTotal = payOuts.reduce(function (a, o) { return a + o.satoshis }, 0)
|
|
539
544
|
|
|
@@ -545,7 +550,7 @@ function buildPurchaseTx (params) {
|
|
|
545
550
|
' sat (payments ' + paidTotal + ' + fee ' + fee + '), funded ' + fundingTotal)
|
|
546
551
|
}
|
|
547
552
|
|
|
548
|
-
var tx = new
|
|
553
|
+
var tx = new Transaction()
|
|
549
554
|
addSpendInput(tx, listing, lockingScript, ordSats) // input 0 = the listing (covenant)
|
|
550
555
|
params.funding.forEach(function (f) { addSpendInput(tx, f, f.script, f.satoshis) })
|
|
551
556
|
|
|
@@ -28,16 +28,18 @@
|
|
|
28
28
|
* always just a 20-byte value the covenant splices into the recreated scriptCode.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
var
|
|
31
|
+
var PrivateKey = require('../privatekey')
|
|
32
|
+
var PublicKey = require('../publickey')
|
|
33
|
+
var Script = require('../script')
|
|
32
34
|
var Hash = require('../crypto/hash')
|
|
33
|
-
var H = require('
|
|
35
|
+
var H = require('../covenant/helpers')
|
|
34
36
|
|
|
35
|
-
var Opcode =
|
|
37
|
+
var Opcode = require('../opcode')
|
|
36
38
|
var n = H.scriptNum
|
|
37
39
|
|
|
38
40
|
function pubBuffer (key) {
|
|
39
|
-
if (key instanceof
|
|
40
|
-
if (key instanceof
|
|
41
|
+
if (key instanceof PrivateKey) return key.toPublicKey().toBuffer()
|
|
42
|
+
if (key instanceof PublicKey) return key.toBuffer()
|
|
41
43
|
return key // already a Buffer
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -71,7 +73,7 @@ function singleKey () {
|
|
|
71
73
|
function redeemScript (m, pubkeys) {
|
|
72
74
|
var nn = pubkeys.length
|
|
73
75
|
if (m < 1 || m > nn || nn < 1 || nn > 16) throw new Error('multisig requires 1 <= m <= n <= 16')
|
|
74
|
-
var s = new
|
|
76
|
+
var s = new Script().add(Opcode['OP_' + m])
|
|
75
77
|
pubkeys.forEach(function (p) { s.add(Buffer.from(p)) }) // each emitted as 0x21||pk (33-byte push)
|
|
76
78
|
s.add(Opcode['OP_' + nn]).add(Opcode.OP_CHECKMULTISIG)
|
|
77
79
|
return s.toBuffer()
|
|
@@ -13,7 +13,13 @@
|
|
|
13
13
|
|
|
14
14
|
'use strict'
|
|
15
15
|
|
|
16
|
-
var
|
|
16
|
+
var sighash = require('../transaction/sighash')
|
|
17
|
+
var Interpreter = require('../script/interpreter')
|
|
18
|
+
var Signature = require('../crypto/signature')
|
|
19
|
+
var Hash = require('../crypto/hash')
|
|
20
|
+
var BN = require('../crypto/bn')
|
|
21
|
+
var Transaction = require('../transaction')
|
|
22
|
+
var Script = require('../script')
|
|
17
23
|
|
|
18
24
|
/**
|
|
19
25
|
* @deprecated NON-ENFORCING. `buildLockingScript` / `createCovenant` emit
|
|
@@ -45,7 +51,7 @@ function Builder(privateKey, options) {
|
|
|
45
51
|
this.validationRules = []
|
|
46
52
|
|
|
47
53
|
this.sighashType = this.options.sighashType ||
|
|
48
|
-
(
|
|
54
|
+
(Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID)
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
// The scripts this class builds are non-enforcing (see the class @deprecated note).
|
|
@@ -125,7 +131,7 @@ Builder.prototype.useTemplate = function(template, params) {
|
|
|
125
131
|
*/
|
|
126
132
|
Builder.prototype.buildLockingScript = function(preimageData) {
|
|
127
133
|
this._assertEnforcingAllowed()
|
|
128
|
-
var script = new
|
|
134
|
+
var script = new Script()
|
|
129
135
|
|
|
130
136
|
if (this.scriptTemplate) {
|
|
131
137
|
return this._buildFromTemplate(preimageData)
|
|
@@ -143,17 +149,17 @@ Builder.prototype.buildLockingScript = function(preimageData) {
|
|
|
143
149
|
* @returns {Script} Constructed unlocking script
|
|
144
150
|
*/
|
|
145
151
|
Builder.prototype.buildUnlockingScript = function(spendingTx, inputIndex, covenantData) {
|
|
146
|
-
var script = new
|
|
152
|
+
var script = new Script()
|
|
147
153
|
|
|
148
154
|
// Add signature
|
|
149
|
-
var covenantScript =
|
|
150
|
-
var signature =
|
|
155
|
+
var covenantScript = Script.fromHex(covenantData.script)
|
|
156
|
+
var signature = sighash.sign(
|
|
151
157
|
spendingTx,
|
|
152
158
|
this.privateKey,
|
|
153
159
|
this.sighashType,
|
|
154
160
|
inputIndex,
|
|
155
161
|
covenantScript,
|
|
156
|
-
new
|
|
162
|
+
new BN(covenantData.satoshis)
|
|
157
163
|
)
|
|
158
164
|
|
|
159
165
|
var fullSignature = Buffer.concat([
|
|
@@ -189,7 +195,7 @@ Builder.prototype.createCovenant = function(utxo, buildOptions) {
|
|
|
189
195
|
buildOptions = buildOptions || {}
|
|
190
196
|
|
|
191
197
|
// Create covenant creation transaction
|
|
192
|
-
var creationTx = new
|
|
198
|
+
var creationTx = new Transaction()
|
|
193
199
|
.from({
|
|
194
200
|
txId: utxo.txid,
|
|
195
201
|
outputIndex: utxo.vout,
|
|
@@ -199,13 +205,13 @@ Builder.prototype.createCovenant = function(utxo, buildOptions) {
|
|
|
199
205
|
.to(this.privateKey.toAddress(), utxo.satoshis - (buildOptions.fee || 1000))
|
|
200
206
|
|
|
201
207
|
// Generate creation preimage
|
|
202
|
-
var p2pkhScript =
|
|
203
|
-
var creationPreimage =
|
|
208
|
+
var p2pkhScript = Script.fromHex(utxo.script)
|
|
209
|
+
var creationPreimage = sighash.sighashPreimage(
|
|
204
210
|
creationTx,
|
|
205
211
|
this.sighashType,
|
|
206
212
|
0,
|
|
207
213
|
p2pkhScript,
|
|
208
|
-
new
|
|
214
|
+
new BN(utxo.satoshis)
|
|
209
215
|
)
|
|
210
216
|
|
|
211
217
|
// Extract preimage fields for covenant construction
|
|
@@ -266,13 +272,13 @@ Builder.prototype.validateSpending = function(spendingTx, covenantUtxo) {
|
|
|
266
272
|
}
|
|
267
273
|
|
|
268
274
|
// Generate spending preimage
|
|
269
|
-
var covenantScript =
|
|
270
|
-
var spendingPreimage =
|
|
275
|
+
var covenantScript = Script.fromHex(covenantUtxo.script)
|
|
276
|
+
var spendingPreimage = sighash.sighashPreimage(
|
|
271
277
|
spendingTx,
|
|
272
278
|
this.sighashType,
|
|
273
279
|
0,
|
|
274
280
|
covenantScript,
|
|
275
|
-
new
|
|
281
|
+
new BN(covenantUtxo.satoshis)
|
|
276
282
|
)
|
|
277
283
|
|
|
278
284
|
var Preimage = require('./preimage')
|
|
@@ -293,15 +299,15 @@ Builder.prototype.validateSpending = function(spendingTx, covenantUtxo) {
|
|
|
293
299
|
}
|
|
294
300
|
|
|
295
301
|
// Run Script.Interpreter validation
|
|
296
|
-
var interpreter = new
|
|
297
|
-
var flags =
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
+
var interpreter = new Interpreter()
|
|
303
|
+
var flags = Interpreter.SCRIPT_VERIFY_P2SH |
|
|
304
|
+
Interpreter.SCRIPT_VERIFY_STRICTENC |
|
|
305
|
+
Interpreter.SCRIPT_VERIFY_DERSIG |
|
|
306
|
+
Interpreter.SCRIPT_VERIFY_LOW_S |
|
|
307
|
+
Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
|
|
302
308
|
|
|
303
309
|
var unlockingScript = spendingTx.inputs[0].script
|
|
304
|
-
var lockingScript =
|
|
310
|
+
var lockingScript = Script.fromHex(covenantUtxo.script)
|
|
305
311
|
|
|
306
312
|
var interpreterResult = interpreter.verify(
|
|
307
313
|
unlockingScript,
|
|
@@ -309,7 +315,7 @@ Builder.prototype.validateSpending = function(spendingTx, covenantUtxo) {
|
|
|
309
315
|
spendingTx,
|
|
310
316
|
0,
|
|
311
317
|
flags,
|
|
312
|
-
new
|
|
318
|
+
new BN(covenantUtxo.satoshis)
|
|
313
319
|
)
|
|
314
320
|
|
|
315
321
|
if (!interpreterResult) {
|
|
@@ -347,7 +353,7 @@ Builder.prototype._buildFromTemplate = function(preimageData) {
|
|
|
347
353
|
* @private
|
|
348
354
|
*/
|
|
349
355
|
Builder.prototype._buildMultiFieldCovenant = function(preimageData) {
|
|
350
|
-
var script = new
|
|
356
|
+
var script = new Script()
|
|
351
357
|
|
|
352
358
|
// Duplicate preimage for multiple validations
|
|
353
359
|
script.add('OP_DUP')
|
|
@@ -359,7 +365,7 @@ Builder.prototype._buildMultiFieldCovenant = function(preimageData) {
|
|
|
359
365
|
script.add('OP_HASH256')
|
|
360
366
|
|
|
361
367
|
if (rule.expectedValue) {
|
|
362
|
-
var expectedHash =
|
|
368
|
+
var expectedHash = Hash.sha256sha256(Buffer.from(rule.expectedValue, 'hex'))
|
|
363
369
|
script.add(expectedHash)
|
|
364
370
|
script.add('OP_EQUALVERIFY')
|
|
365
371
|
}
|
|
@@ -381,12 +387,12 @@ Builder.prototype._buildMultiFieldCovenant = function(preimageData) {
|
|
|
381
387
|
* @private
|
|
382
388
|
*/
|
|
383
389
|
Builder.prototype._buildHashLockTemplate = function(preimageData, params) {
|
|
384
|
-
var script = new
|
|
390
|
+
var script = new Script()
|
|
385
391
|
|
|
386
392
|
script.add('OP_DUP')
|
|
387
393
|
script.add('OP_HASH256')
|
|
388
394
|
|
|
389
|
-
var expectedHash = params.hash ||
|
|
395
|
+
var expectedHash = params.hash || Hash.sha256sha256(preimageData.preimage)
|
|
390
396
|
script.add(expectedHash)
|
|
391
397
|
script.add('OP_EQUALVERIFY')
|
|
392
398
|
script.add('OP_DROP')
|
|
@@ -26,7 +26,14 @@
|
|
|
26
26
|
|
|
27
27
|
'use strict'
|
|
28
28
|
|
|
29
|
-
var
|
|
29
|
+
var sighash = require('../transaction/sighash')
|
|
30
|
+
var Input = require('../transaction/input')
|
|
31
|
+
var Interpreter = require('../script/interpreter')
|
|
32
|
+
var Signature = require('../crypto/signature')
|
|
33
|
+
var Hash = require('../crypto/hash')
|
|
34
|
+
var BN = require('../crypto/bn')
|
|
35
|
+
var Transaction = require('../transaction')
|
|
36
|
+
var Script = require('../script')
|
|
30
37
|
var path = require('path')
|
|
31
38
|
|
|
32
39
|
// Optional fs dependency for Node.js environments
|
|
@@ -65,7 +72,7 @@ function Covenant(privateKey, options) {
|
|
|
65
72
|
this.storageDir = options.storageDir || (typeof process !== 'undefined' ? path.join(process.cwd(), '.bsv-covenants') : '.bsv-covenants')
|
|
66
73
|
this.covenantUtxoPath = path.join(this.storageDir, 'covenant_utxos.json')
|
|
67
74
|
|
|
68
|
-
this.sighashType =
|
|
75
|
+
this.sighashType = Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID
|
|
69
76
|
|
|
70
77
|
// The locking script this class builds does NOT constrain the spend (see the
|
|
71
78
|
// class doc). Require explicit acknowledgement so no one ships it as a real
|
|
@@ -100,7 +107,7 @@ Covenant.prototype.createFromP2PKH = function(utxo) {
|
|
|
100
107
|
}
|
|
101
108
|
|
|
102
109
|
// Create covenant creation transaction
|
|
103
|
-
var creationTx = new
|
|
110
|
+
var creationTx = new Transaction()
|
|
104
111
|
.from({
|
|
105
112
|
txId: utxo.txid,
|
|
106
113
|
outputIndex: utxo.vout,
|
|
@@ -110,19 +117,19 @@ Covenant.prototype.createFromP2PKH = function(utxo) {
|
|
|
110
117
|
.to(this.address, utxo.satoshis - 1000) // 1000 sat fee
|
|
111
118
|
|
|
112
119
|
// Get preimage for covenant creation
|
|
113
|
-
var p2pkhScript =
|
|
114
|
-
var creationPreimage =
|
|
120
|
+
var p2pkhScript = Script.fromHex(utxo.script)
|
|
121
|
+
var creationPreimage = sighash.sighashPreimage(
|
|
115
122
|
creationTx,
|
|
116
123
|
this.sighashType,
|
|
117
124
|
0,
|
|
118
125
|
p2pkhScript,
|
|
119
|
-
new
|
|
126
|
+
new BN(utxo.satoshis)
|
|
120
127
|
)
|
|
121
128
|
|
|
122
|
-
var preimageHash =
|
|
129
|
+
var preimageHash = Hash.sha256sha256(creationPreimage)
|
|
123
130
|
|
|
124
131
|
// Build covenant locking script
|
|
125
|
-
var covenantLockingScript = new
|
|
132
|
+
var covenantLockingScript = new Script()
|
|
126
133
|
.add('OP_DUP')
|
|
127
134
|
.add('OP_HASH256')
|
|
128
135
|
.add(preimageHash)
|
|
@@ -168,28 +175,28 @@ Covenant.prototype.createSpendingTx = function(covenantUtxo, outputAddress, outp
|
|
|
168
175
|
var outputSats = outputSatoshis || (covenantUtxo.satoshis - 500) // 500 sat fee
|
|
169
176
|
|
|
170
177
|
// Create spending transaction - manual input for custom scripts
|
|
171
|
-
var spendingTx = new
|
|
178
|
+
var spendingTx = new Transaction()
|
|
172
179
|
|
|
173
180
|
// Manually add input for custom covenant script
|
|
174
|
-
spendingTx.addInput(new
|
|
181
|
+
spendingTx.addInput(new Input({
|
|
175
182
|
prevTxId: covenantUtxo.txid,
|
|
176
183
|
outputIndex: covenantUtxo.vout,
|
|
177
|
-
script:
|
|
178
|
-
}),
|
|
184
|
+
script: Script.empty() // Will be set after signing
|
|
185
|
+
}), Script.fromHex(covenantUtxo.script), covenantUtxo.satoshis)
|
|
179
186
|
|
|
180
187
|
// Add output
|
|
181
188
|
spendingTx.to(outputAddr, outputSats)
|
|
182
189
|
|
|
183
|
-
var covenantScript =
|
|
190
|
+
var covenantScript = Script.fromHex(covenantUtxo.script)
|
|
184
191
|
|
|
185
192
|
// Create signature against covenant script
|
|
186
|
-
var covenantSignature =
|
|
193
|
+
var covenantSignature = sighash.sign(
|
|
187
194
|
spendingTx,
|
|
188
195
|
this.privateKey,
|
|
189
196
|
this.sighashType,
|
|
190
197
|
0,
|
|
191
198
|
covenantScript,
|
|
192
|
-
new
|
|
199
|
+
new BN(covenantUtxo.satoshis)
|
|
193
200
|
)
|
|
194
201
|
|
|
195
202
|
var fullSignature = Buffer.concat([
|
|
@@ -201,7 +208,7 @@ Covenant.prototype.createSpendingTx = function(covenantUtxo, outputAddress, outp
|
|
|
201
208
|
var originalPreimage = Buffer.from(covenantUtxo.originalPreimage, 'hex')
|
|
202
209
|
|
|
203
210
|
// Create unlocking script
|
|
204
|
-
var unlockingScript = new
|
|
211
|
+
var unlockingScript = new Script()
|
|
205
212
|
.add(fullSignature)
|
|
206
213
|
.add(originalPreimage)
|
|
207
214
|
|
|
@@ -217,15 +224,15 @@ Covenant.prototype.createSpendingTx = function(covenantUtxo, outputAddress, outp
|
|
|
217
224
|
* @returns {Object} Validation result
|
|
218
225
|
*/
|
|
219
226
|
Covenant.prototype.validate = function(spendingTx, covenantUtxo) {
|
|
220
|
-
var interpreter = new
|
|
221
|
-
var flags =
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
227
|
+
var interpreter = new Interpreter()
|
|
228
|
+
var flags = Interpreter.SCRIPT_VERIFY_P2SH |
|
|
229
|
+
Interpreter.SCRIPT_VERIFY_STRICTENC |
|
|
230
|
+
Interpreter.SCRIPT_VERIFY_DERSIG |
|
|
231
|
+
Interpreter.SCRIPT_VERIFY_LOW_S |
|
|
232
|
+
Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
|
|
226
233
|
|
|
227
234
|
var unlockingScript = spendingTx.inputs[0].script
|
|
228
|
-
var lockingScript =
|
|
235
|
+
var lockingScript = Script.fromHex(covenantUtxo.script)
|
|
229
236
|
|
|
230
237
|
var result = interpreter.verify(
|
|
231
238
|
unlockingScript,
|
|
@@ -233,7 +240,7 @@ Covenant.prototype.validate = function(spendingTx, covenantUtxo) {
|
|
|
233
240
|
spendingTx,
|
|
234
241
|
0,
|
|
235
242
|
flags,
|
|
236
|
-
new
|
|
243
|
+
new BN(covenantUtxo.satoshis)
|
|
237
244
|
)
|
|
238
245
|
|
|
239
246
|
return {
|
|
@@ -366,7 +373,7 @@ Covenant.prototype._ensureStorageDir = function() {
|
|
|
366
373
|
* Static utility methods
|
|
367
374
|
*/
|
|
368
375
|
Covenant.reconstructP2pkhScript = function(address) {
|
|
369
|
-
return
|
|
376
|
+
return Script.buildPublicKeyHashOut(address).toHex()
|
|
370
377
|
}
|
|
371
378
|
|
|
372
379
|
module.exports = Covenant
|