@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,126 @@
1
+ 'use strict'
2
+
3
+ /* global describe, it */
4
+
5
+ // BSV-20 / BSV-21 fungible-token inscriptions: build/parse round-trips + validation.
6
+
7
+ require('chai').should()
8
+ var bsv = require('../..')
9
+ var B = bsv.Ordinals.BSV20
10
+ var Ord = bsv.Ordinals
11
+
12
+ describe('Ordinals BSV-20 fungible tokens', function () {
13
+ var key = bsv.PrivateKey.fromRandom()
14
+ var address = key.toAddress()
15
+
16
+ it('deploys a v1 ticker token and round-trips through parse', function () {
17
+ var s = B.buildDeploy({ address: address, tick: 'ORDI', max: '21000000', lim: '1000', dec: 18 })
18
+ var p = B.parseBsv20(s)
19
+ p.p.should.equal('bsv-20')
20
+ p.op.should.equal('deploy')
21
+ p.tick.should.equal('ORDI')
22
+ p.max.should.equal('21000000')
23
+ p.lim.should.equal('1000')
24
+ p.dec.should.equal('18')
25
+ // The payload rides in an inscription with the bsv-20 content-type.
26
+ Ord.parseInscription(s).contentType.should.equal('application/bsv-20')
27
+ // The base lock is the owner's P2PKH.
28
+ Ord.parseInscription(s).lock.toHex().should.equal(bsv.Script.buildPublicKeyHashOut(address).toHex())
29
+ })
30
+
31
+ it('mints and transfers a v1 ticker token', function () {
32
+ var mint = B.parseBsv20(B.buildMint({ address: address, tick: 'ORDI', amt: '1000' }))
33
+ mint.op.should.equal('mint')
34
+ mint.tick.should.equal('ORDI')
35
+ mint.amt.should.equal('1000')
36
+
37
+ var xfer = B.parseBsv20(B.buildTransfer({ address: address, tick: 'ORDI', amt: '250' }))
38
+ xfer.op.should.equal('transfer')
39
+ xfer.tick.should.equal('ORDI')
40
+ xfer.amt.should.equal('250')
41
+ })
42
+
43
+ it('deploy+mints a BSV-21 (id-based) token and transfers by id', function () {
44
+ var dm = B.parseBsv20(B.buildDeployMint({ address: address, amt: '1000000', dec: 8, sym: 'XYZ' }))
45
+ dm.op.should.equal('deploy+mint')
46
+ dm.amt.should.equal('1000000')
47
+ dm.dec.should.equal('8')
48
+ dm.sym.should.equal('XYZ')
49
+
50
+ var id = 'a'.repeat(64) + '_0'
51
+ var xfer = B.parseBsv20(B.buildTransfer({ address: address, id: id, amt: '5' }))
52
+ xfer.op.should.equal('transfer')
53
+ xfer.id.should.equal(id)
54
+ xfer.amt.should.equal('5')
55
+ ;(xfer.tick === undefined).should.equal(true)
56
+ })
57
+
58
+ it('preserves integer amounts larger than 2^53 exactly (string, never a JS number)', function () {
59
+ var huge = '99999999999999999999999999'
60
+ var p = B.parseBsv20(B.buildMint({ address: address, tick: 'BIG', amt: huge }))
61
+ p.amt.should.equal(huge)
62
+ })
63
+
64
+ it('accepts numeric amounts and normalizes them to strings', function () {
65
+ var p = B.parseBsv20(B.buildMint({ address: address, tick: 'NUM', amt: 42 }))
66
+ p.amt.should.equal('42')
67
+ })
68
+
69
+ // Code-review finding #4: leading-zero integer strings are canonicalized (indexers expect
70
+ // canonical decimals), while preserving arbitrary precision.
71
+ it('canonicalizes leading-zero amount strings', function () {
72
+ B.parseBsv20(B.buildMint({ address: address, tick: 'ORDI', amt: '007' })).amt.should.equal('7')
73
+ B.parseBsv20(B.buildDeploy({ address: address, tick: 'ORDI', max: '000100' })).max.should.equal('100')
74
+ // canonicalization does not corrupt a huge value
75
+ var huge = '90000000000000000000000000'
76
+ B.parseBsv20(B.buildMint({ address: address, tick: 'ORDI', amt: '0' + huge })).amt.should.equal(huge)
77
+ })
78
+
79
+ it('builds a 1-sat token output', function () {
80
+ var out = B.createMintOutput({ address: address, tick: 'ORDI', amt: '1' })
81
+ out.satoshis.should.equal(1)
82
+ B.isBsv20(out.script).should.equal(true)
83
+ })
84
+
85
+ it('round-trips through hex serialization', function () {
86
+ var s = B.buildDeploy({ address: address, tick: 'HEX', max: '1000' })
87
+ var p = B.parseBsv20(s.toHex())
88
+ p.tick.should.equal('HEX')
89
+ p.max.should.equal('1000')
90
+ })
91
+
92
+ it('parses a raw JSON string or an already-parsed object', function () {
93
+ var json = '{"p":"bsv-20","op":"mint","tick":"ORDI","amt":"1"}'
94
+ B.parseBsv20(json).amt.should.equal('1')
95
+ B.parseBsv20({ p: 'bsv-20', op: 'mint', tick: 'ORDI', amt: '1' }).op.should.equal('mint')
96
+ })
97
+
98
+ it('isBsv20 is false for a plain inscription and a P2PKH script', function () {
99
+ var plain = Ord.buildInscription({ address: address, contentType: 'text/plain', content: 'hi' })
100
+ B.isBsv20(plain).should.equal(false)
101
+ B.isBsv20(bsv.Script.buildPublicKeyHashOut(address)).should.equal(false)
102
+ ;(B.parseBsv20(plain) === null).should.equal(true)
103
+ })
104
+
105
+ describe('validation', function () {
106
+ it('rejects a tick longer than 4 UTF-8 bytes', function () {
107
+ ;(function () { B.buildDeploy({ address: address, tick: 'TOOLONG', max: '1' }) }).should.throw(/1–4 UTF-8 bytes/)
108
+ })
109
+ it('rejects a non-integer / negative amount', function () {
110
+ ;(function () { B.buildMint({ address: address, tick: 'ORDI', amt: '1.5' }) }).should.throw(/non-negative integer/)
111
+ ;(function () { B.buildMint({ address: address, tick: 'ORDI', amt: -5 }) }).should.throw(/non-negative integer/)
112
+ })
113
+ it('rejects a zero amount for mint/transfer', function () {
114
+ ;(function () { B.buildMint({ address: address, tick: 'ORDI', amt: '0' }) }).should.throw(/greater than zero/)
115
+ })
116
+ it('rejects dec out of the 0…18 range', function () {
117
+ ;(function () { B.buildDeploy({ address: address, tick: 'ORDI', max: '1', dec: 19 }) }).should.throw(/dec must be/)
118
+ })
119
+ it('rejects a malformed BSV-21 id', function () {
120
+ ;(function () { B.buildTransfer({ address: address, id: 'notanid', amt: '1' }) }).should.throw(/txid.*vout|<txid>/)
121
+ })
122
+ it('requires an owner (address or lock)', function () {
123
+ ;(function () { B.buildMint({ tick: 'ORDI', amt: '1' }) }).should.throw(/address or a lock/)
124
+ })
125
+ })
126
+ })
@@ -0,0 +1,71 @@
1
+ 'use strict'
2
+
3
+ /* global describe, it */
4
+
5
+ // 1Sat Ordinals inscription build/parse round-trip + output construction.
6
+
7
+ require('chai').should()
8
+ var bsv = require('../..')
9
+ var Ord = bsv.Ordinals
10
+
11
+ describe('Ordinals inscriptions', function () {
12
+ var key = bsv.PrivateKey.fromRandom()
13
+ var address = key.toAddress()
14
+
15
+ it('builds a P2PKH inscription and round-trips through parse', function () {
16
+ var s = Ord.buildInscription({
17
+ address: address, contentType: 'text/plain', content: 'hello ordinals'
18
+ })
19
+ var parsed = Ord.parseInscription(s)
20
+ parsed.should.be.an('object')
21
+ parsed.contentType.should.equal('text/plain')
22
+ parsed.contentText.should.equal('hello ordinals')
23
+ // The base lock is exactly the P2PKH for the address.
24
+ parsed.lock.toHex().should.equal(bsv.Script.buildPublicKeyHashOut(address).toHex())
25
+ })
26
+
27
+ it('preserves binary content and content-type exactly', function () {
28
+ var content = bsv.crypto.Random.getRandomBuffer(64)
29
+ var s = Ord.buildInscription({ address: address, contentType: 'image/png', content: content })
30
+ var parsed = Ord.parseInscription(s)
31
+ parsed.contentType.should.equal('image/png')
32
+ parsed.content.equals(content).should.equal(true)
33
+ })
34
+
35
+ it('round-trips through hex serialization', function () {
36
+ var s = Ord.buildInscription({ address: address, contentType: 'application/json', content: '{"a":1}' })
37
+ var parsed = Ord.parseInscription(s.toHex())
38
+ parsed.contentText.should.equal('{"a":1}')
39
+ parsed.contentType.should.equal('application/json')
40
+ })
41
+
42
+ it('accepts a custom base lock script', function () {
43
+ var lock = bsv.Script.buildPublicKeyHashOut(address)
44
+ var s = Ord.buildInscription({ lock: lock, contentType: 'text/plain', content: 'x' })
45
+ Ord.isInscription(s).should.equal(true)
46
+ Ord.parseInscription(s).lock.toHex().should.equal(lock.toHex())
47
+ })
48
+
49
+ it('isInscription is false for a plain P2PKH script', function () {
50
+ var p2pkh = bsv.Script.buildPublicKeyHashOut(address)
51
+ Ord.isInscription(p2pkh).should.equal(false)
52
+ var isNull = Ord.parseInscription(p2pkh) === null
53
+ isNull.should.equal(true)
54
+ })
55
+
56
+ it('createInscriptionOutput is a 1-sat output carrying the inscription', function () {
57
+ var out = Ord.createInscriptionOutput({ address: address, contentType: 'text/plain', content: 'hi' })
58
+ out.satoshis.should.equal(1)
59
+ Ord.isInscription(out.script).should.equal(true)
60
+ })
61
+
62
+ it('batchInscriptionOutputs builds one output per item', function () {
63
+ var outs = Ord.batchInscriptionOutputs([
64
+ { address: address, contentType: 'text/plain', content: 'a' },
65
+ { address: address, contentType: 'text/plain', content: 'b' }
66
+ ])
67
+ outs.length.should.equal(2)
68
+ Ord.parseInscription(outs[0].script).contentText.should.equal('a')
69
+ Ord.parseInscription(outs[1].script).contentText.should.equal('b')
70
+ })
71
+ })