@bsv/sdk 1.0.0 → 1.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/README.md +25 -3
- package/package.json +9 -5
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- package/.github/ISSUE_TEMPLATE/discussion.md +0 -24
- package/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -23
- package/CHANGELOG.md +0 -72
- package/CONTRIBUTING.md +0 -85
- package/ROADMAP.md +0 -3
- package/docs/getting-started/COMMONJS.md +0 -94
- package/docs/getting-started/REACT-TS.md +0 -131
- package/docs/getting-started/TS-NODE.md +0 -106
- package/docs/getting-started/VUE.md +0 -103
- package/jest.config.js +0 -6
- package/mod.ts +0 -8
- package/src/compat/BSM.ts +0 -51
- package/src/compat/ECIES.ts +0 -557
- package/src/compat/HD.ts +0 -348
- package/src/compat/Mnemonic.ts +0 -295
- package/src/compat/__tests/BSM.test.ts +0 -38
- package/src/compat/__tests/ECIES.test.ts +0 -90
- package/src/compat/__tests/HD.test.ts +0 -405
- package/src/compat/__tests/Mnemonic.test.ts +0 -177
- package/src/compat/__tests/Mnemonic.vectors.ts +0 -172
- package/src/compat/bip-39-wordlist-en.ts +0 -2053
- package/src/compat/index.ts +0 -4
- package/src/messages/EncryptedMessage.ts +0 -70
- package/src/messages/SignedMessage.ts +0 -87
- package/src/messages/__tests/EncryptedMessage.test.ts +0 -36
- package/src/messages/__tests/SignedMessage.test.ts +0 -53
- package/src/messages/index.ts +0 -2
- package/src/primitives/AESGCM.ts +0 -479
- package/src/primitives/BasePoint.ts +0 -21
- package/src/primitives/BigNumber.ts +0 -4619
- package/src/primitives/Curve.ts +0 -1163
- package/src/primitives/DRBG.ts +0 -102
- package/src/primitives/ECDSA.ts +0 -164
- package/src/primitives/Hash.ts +0 -1420
- package/src/primitives/JacobianPoint.ts +0 -410
- package/src/primitives/K256.ts +0 -116
- package/src/primitives/Mersenne.ts +0 -123
- package/src/primitives/MontgomoryMethod.ts +0 -160
- package/src/primitives/Point.ts +0 -852
- package/src/primitives/PrivateKey.ts +0 -195
- package/src/primitives/PublicKey.ts +0 -154
- package/src/primitives/Random.ts +0 -55
- package/src/primitives/ReductionContext.ts +0 -528
- package/src/primitives/Signature.ts +0 -235
- package/src/primitives/SymmetricKey.ts +0 -75
- package/src/primitives/TransactionSignature.ts +0 -189
- package/src/primitives/__tests/AESGCM.test.ts +0 -338
- package/src/primitives/__tests/BRC42.private.vectors.ts +0 -33
- package/src/primitives/__tests/BRC42.public.vectors.ts +0 -33
- package/src/primitives/__tests/BigNumber.arithmatic.test.ts +0 -572
- package/src/primitives/__tests/BigNumber.binary.test.ts +0 -203
- package/src/primitives/__tests/BigNumber.constructor.test.ts +0 -176
- package/src/primitives/__tests/BigNumber.dhGroup.test.ts +0 -18
- package/src/primitives/__tests/BigNumber.fixtures.ts +0 -264
- package/src/primitives/__tests/BigNumber.serializers.test.ts +0 -157
- package/src/primitives/__tests/BigNumber.utils.test.ts +0 -347
- package/src/primitives/__tests/Curve.unit.test.ts +0 -192
- package/src/primitives/__tests/DRBG.test.ts +0 -18
- package/src/primitives/__tests/DRBG.vectors.ts +0 -167
- package/src/primitives/__tests/ECDH.test.ts +0 -31
- package/src/primitives/__tests/ECDSA.test.ts +0 -58
- package/src/primitives/__tests/HMAC.test.ts +0 -59
- package/src/primitives/__tests/Hash.test.ts +0 -121
- package/src/primitives/__tests/PBKDF2.vectors.ts +0 -119
- package/src/primitives/__tests/PrivateKey.test.ts +0 -17
- package/src/primitives/__tests/PublicKey.test.ts +0 -66
- package/src/primitives/__tests/Random.test.ts +0 -14
- package/src/primitives/__tests/Reader.test.ts +0 -296
- package/src/primitives/__tests/ReductionContext.test.ts +0 -279
- package/src/primitives/__tests/SymmetricKey.test.ts +0 -58
- package/src/primitives/__tests/SymmetricKey.vectors.ts +0 -40
- package/src/primitives/__tests/Writer.test.ts +0 -198
- package/src/primitives/__tests/sighash.vectors.ts +0 -3503
- package/src/primitives/__tests/utils.test.ts +0 -108
- package/src/primitives/index.ts +0 -8
- package/src/primitives/utils.ts +0 -665
- package/src/script/LockingScript.ts +0 -30
- package/src/script/OP.ts +0 -219
- package/src/script/Script.ts +0 -426
- package/src/script/ScriptChunk.ts +0 -7
- package/src/script/ScriptTemplate.ts +0 -36
- package/src/script/Spend.ts +0 -1379
- package/src/script/UnlockingScript.ts +0 -30
- package/src/script/__tests/Script.test.ts +0 -369
- package/src/script/__tests/Spend.test.ts +0 -248
- package/src/script/__tests/script.invalid.vectors.ts +0 -925
- package/src/script/__tests/script.valid.vectors.ts +0 -1120
- package/src/script/__tests/scriptFromVector.ts +0 -42
- package/src/script/__tests/spend.valid.vectors.ts +0 -2288
- package/src/script/index.ts +0 -7
- package/src/script/templates/P2PKH.ts +0 -109
- package/src/script/templates/RPuzzle.ts +0 -140
- package/src/script/templates/index.ts +0 -2
- package/src/transaction/Broadcaster.ts +0 -42
- package/src/transaction/ChainTracker.ts +0 -22
- package/src/transaction/FeeModel.ts +0 -13
- package/src/transaction/MerklePath.ts +0 -259
- package/src/transaction/Transaction.ts +0 -602
- package/src/transaction/TransactionInput.ts +0 -63
- package/src/transaction/TransactionOutput.ts +0 -37
- package/src/transaction/__tests/MerklePath.test.ts +0 -181
- package/src/transaction/__tests/Transaction.test.ts +0 -413
- package/src/transaction/__tests/bigtx.vectors.ts +0 -4
- package/src/transaction/__tests/bump.invalid.vectors.ts +0 -8
- package/src/transaction/__tests/bump.valid.vectors.ts +0 -4
- package/src/transaction/__tests/tx.invalid.vectors.ts +0 -281
- package/src/transaction/__tests/tx.valid.vectors.ts +0 -364
- package/src/transaction/broadcasters/ARC.ts +0 -106
- package/src/transaction/broadcasters/__tests/ARC.test.ts +0 -115
- package/src/transaction/broadcasters/index.ts +0 -1
- package/src/transaction/fee-models/SatoshisPerKilobyte.ts +0 -71
- package/src/transaction/fee-models/index.ts +0 -1
- package/src/transaction/index.ts +0 -6
- package/ts2md.json +0 -5
- package/tsconfig.base.json +0 -26
- package/tsconfig.cjs.json +0 -11
- package/tsconfig.eslint.json +0 -12
- package/tsconfig.esm.json +0 -9
- package/tsconfig.json +0 -17
- package/tsconfig.types.json +0 -11
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import MerklePath from '../../../dist/cjs/src/transaction/MerklePath'
|
|
2
|
-
import invalidBumps from './bump.invalid.vectors'
|
|
3
|
-
import validBumps from './bump.valid.vectors'
|
|
4
|
-
|
|
5
|
-
const BRC74Hex = 'fe8a6a0c000c04fde80b0011774f01d26412f0d16ea3f0447be0b5ebec67b0782e321a7a01cbdf7f734e30fde90b02004e53753e3fe4667073063a17987292cfdea278824e9888e52180581d7188d8fdea0b025e441996fc53f0191d649e68a200e752fb5f39e0d5617083408fa179ddc5c998fdeb0b0102fdf405000671394f72237d08a4277f4435e5b6edf7adc272f25effef27cdfe805ce71a81fdf50500262bccabec6c4af3ed00cc7a7414edea9c5efa92fb8623dd6160a001450a528201fdfb020101fd7c010093b3efca9b77ddec914f8effac691ecb54e2c81d0ab81cbc4c4b93befe418e8501bf01015e005881826eb6973c54003a02118fe270f03d46d02681c8bc71cd44c613e86302f8012e00e07a2bb8bb75e5accff266022e1e5e6e7b4d6d943a04faadcf2ab4a22f796ff30116008120cafa17309c0bb0e0ffce835286b3a2dcae48e4497ae2d2b7ced4f051507d010a00502e59ac92f46543c23006bff855d96f5e648043f0fb87a7a5949e6a9bebae430104001ccd9f8f64f4d0489b30cc815351cf425e0e78ad79a589350e4341ac165dbe45010301010000af8764ce7e1cc132ab5ed2229a005c87201c9a5ee15c0f91dd53eff31ab30cd4'
|
|
6
|
-
|
|
7
|
-
const BRC74JSON = {
|
|
8
|
-
blockHeight: 813706,
|
|
9
|
-
path: [
|
|
10
|
-
[
|
|
11
|
-
{
|
|
12
|
-
offset: 3048,
|
|
13
|
-
hash: '304e737fdfcb017a1a322e78b067ecebb5e07b44f0a36ed1f01264d2014f7711'
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
offset: 3049,
|
|
17
|
-
txid: true,
|
|
18
|
-
hash: 'd888711d588021e588984e8278a2decf927298173a06737066e43f3e75534e00'
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
offset: 3050,
|
|
22
|
-
txid: true,
|
|
23
|
-
hash: '98c9c5dd79a18f40837061d5e0395ffb52e700a2689e641d19f053fc9619445e'
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
offset: 3051,
|
|
27
|
-
duplicate: true
|
|
28
|
-
}
|
|
29
|
-
],
|
|
30
|
-
[
|
|
31
|
-
{
|
|
32
|
-
offset: 1524,
|
|
33
|
-
hash: '811ae75c80fecd27efff5ef272c2adf7edb6e535447f27a4087d23724f397106'
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
offset: 1525,
|
|
37
|
-
hash: '82520a4501a06061dd2386fb92fa5e9ceaed14747acc00edf34a6cecabcc2b26'
|
|
38
|
-
}
|
|
39
|
-
],
|
|
40
|
-
[
|
|
41
|
-
{
|
|
42
|
-
offset: 763,
|
|
43
|
-
duplicate: true
|
|
44
|
-
}
|
|
45
|
-
],
|
|
46
|
-
[
|
|
47
|
-
{
|
|
48
|
-
offset: 380,
|
|
49
|
-
hash: '858e41febe934b4cbc1cb80a1dc8e254cb1e69acff8e4f91ecdd779bcaefb393'
|
|
50
|
-
}
|
|
51
|
-
],
|
|
52
|
-
[
|
|
53
|
-
{
|
|
54
|
-
offset: 191,
|
|
55
|
-
duplicate: true
|
|
56
|
-
}
|
|
57
|
-
],
|
|
58
|
-
[
|
|
59
|
-
{
|
|
60
|
-
offset: 94,
|
|
61
|
-
hash: 'f80263e813c644cd71bcc88126d0463df070e28f11023a00543c97b66e828158'
|
|
62
|
-
}
|
|
63
|
-
],
|
|
64
|
-
[
|
|
65
|
-
{
|
|
66
|
-
offset: 46,
|
|
67
|
-
hash: 'f36f792fa2b42acfadfa043a946d4d7b6e5e1e2e0266f2cface575bbb82b7ae0'
|
|
68
|
-
}
|
|
69
|
-
],
|
|
70
|
-
[
|
|
71
|
-
{
|
|
72
|
-
offset: 22,
|
|
73
|
-
hash: '7d5051f0d4ceb7d2e27a49e448aedca2b3865283ceffe0b00b9c3017faca2081'
|
|
74
|
-
}
|
|
75
|
-
],
|
|
76
|
-
[
|
|
77
|
-
{
|
|
78
|
-
offset: 10,
|
|
79
|
-
hash: '43aeeb9b6a9e94a5a787fbf04380645e6fd955f8bf0630c24365f492ac592e50'
|
|
80
|
-
}
|
|
81
|
-
],
|
|
82
|
-
[
|
|
83
|
-
{
|
|
84
|
-
offset: 4,
|
|
85
|
-
hash: '45be5d16ac41430e3589a579ad780e5e42cf515381cc309b48d0f4648f9fcd1c'
|
|
86
|
-
}
|
|
87
|
-
],
|
|
88
|
-
[
|
|
89
|
-
{
|
|
90
|
-
offset: 3,
|
|
91
|
-
duplicate: true
|
|
92
|
-
}
|
|
93
|
-
],
|
|
94
|
-
[
|
|
95
|
-
{
|
|
96
|
-
offset: 0,
|
|
97
|
-
hash: 'd40cb31af3ef53dd910f5ce15e9a1c20875c009a22d25eab32c11c7ece6487af'
|
|
98
|
-
}
|
|
99
|
-
]
|
|
100
|
-
]
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const BRC74Root = '57aab6e6fb1b697174ffb64e062c4728f2ffd33ddcfa02a43b64d8cd29b483b4'
|
|
104
|
-
const BRC74TXID1 = '304e737fdfcb017a1a322e78b067ecebb5e07b44f0a36ed1f01264d2014f7711'
|
|
105
|
-
const BRC74TXID2 = 'd888711d588021e588984e8278a2decf927298173a06737066e43f3e75534e00'
|
|
106
|
-
const BRC74TXID3 = '98c9c5dd79a18f40837061d5e0395ffb52e700a2689e641d19f053fc9619445e'
|
|
107
|
-
|
|
108
|
-
describe('MerklePath', () => {
|
|
109
|
-
it('Parses from hex', () => {
|
|
110
|
-
const path = MerklePath.fromHex(BRC74Hex)
|
|
111
|
-
expect(path.path).toEqual(BRC74JSON.path)
|
|
112
|
-
})
|
|
113
|
-
it('Serializes to hex', () => {
|
|
114
|
-
const path = new MerklePath(BRC74JSON.blockHeight, BRC74JSON.path)
|
|
115
|
-
expect(path.toHex()).toEqual(BRC74Hex)
|
|
116
|
-
})
|
|
117
|
-
it('Computes a root', () => {
|
|
118
|
-
const path = new MerklePath(BRC74JSON.blockHeight, BRC74JSON.path)
|
|
119
|
-
expect(path.computeRoot(BRC74TXID1)).toEqual(BRC74Root)
|
|
120
|
-
expect(path.computeRoot(BRC74TXID2)).toEqual(BRC74Root)
|
|
121
|
-
expect(path.computeRoot(BRC74TXID3)).toEqual(BRC74Root)
|
|
122
|
-
})
|
|
123
|
-
it('Verifies using a ChainTracker', async () => {
|
|
124
|
-
const path = new MerklePath(BRC74JSON.blockHeight, BRC74JSON.path)
|
|
125
|
-
const tracker = {
|
|
126
|
-
isValidRootForHeight: jest.fn((root, height) => root === BRC74Root && height === BRC74JSON.blockHeight)
|
|
127
|
-
}
|
|
128
|
-
const result = await path.verify(BRC74TXID1, tracker)
|
|
129
|
-
expect(result).toBe(true)
|
|
130
|
-
expect(tracker.isValidRootForHeight).toHaveBeenCalledWith(BRC74Root, BRC74JSON.blockHeight)
|
|
131
|
-
})
|
|
132
|
-
it('Combines two paths', () => {
|
|
133
|
-
const path0A = [...BRC74JSON.path[0]]
|
|
134
|
-
const path0B = [...BRC74JSON.path[0]]
|
|
135
|
-
const path1A = [...BRC74JSON.path[1]]
|
|
136
|
-
const path1B = [...BRC74JSON.path[1]]
|
|
137
|
-
const pathRest = [...BRC74JSON.path]
|
|
138
|
-
pathRest.shift()
|
|
139
|
-
pathRest.shift()
|
|
140
|
-
path0A.splice(2, 2)
|
|
141
|
-
path0B.shift()
|
|
142
|
-
path0B.shift()
|
|
143
|
-
path1A.shift()
|
|
144
|
-
path1B.pop()
|
|
145
|
-
const pathAJSON = {
|
|
146
|
-
blockHeight: BRC74JSON.blockHeight,
|
|
147
|
-
path: [
|
|
148
|
-
path0A,
|
|
149
|
-
path1A,
|
|
150
|
-
...pathRest
|
|
151
|
-
]
|
|
152
|
-
}
|
|
153
|
-
const pathBJSON = {
|
|
154
|
-
blockHeight: BRC74JSON.blockHeight,
|
|
155
|
-
path: [
|
|
156
|
-
path0B,
|
|
157
|
-
path1B,
|
|
158
|
-
...pathRest
|
|
159
|
-
]
|
|
160
|
-
}
|
|
161
|
-
const pathA = new MerklePath(pathAJSON.blockHeight, pathAJSON.path)
|
|
162
|
-
const pathB = new MerklePath(pathBJSON.blockHeight, pathBJSON.path)
|
|
163
|
-
expect(pathA.computeRoot(BRC74TXID2)).toEqual(BRC74Root)
|
|
164
|
-
expect(() => pathA.computeRoot(BRC74TXID3)).toThrow()
|
|
165
|
-
expect(() => pathB.computeRoot(BRC74TXID2)).toThrow()
|
|
166
|
-
expect(pathB.computeRoot(BRC74TXID3)).toEqual(BRC74Root)
|
|
167
|
-
pathA.combine(pathB)
|
|
168
|
-
expect(pathA.computeRoot(BRC74TXID2)).toEqual(BRC74Root)
|
|
169
|
-
expect(pathA.computeRoot(BRC74TXID3)).toEqual(BRC74Root)
|
|
170
|
-
})
|
|
171
|
-
it('Rejects invalid bumps', () => {
|
|
172
|
-
for (const invalid of invalidBumps) {
|
|
173
|
-
expect(() => MerklePath.fromHex(invalid.bump)).toThrow(invalid.error)
|
|
174
|
-
}
|
|
175
|
-
})
|
|
176
|
-
it('Verifies valid bumps', async () => {
|
|
177
|
-
for (const valid of validBumps) {
|
|
178
|
-
expect(() => MerklePath.fromHex(valid.bump)).not.toThrowError()
|
|
179
|
-
}
|
|
180
|
-
})
|
|
181
|
-
})
|
|
@@ -1,413 +0,0 @@
|
|
|
1
|
-
import BigNumber from '../../../dist/cjs/src/primitives/BigNumber'
|
|
2
|
-
import TransactionSignature from '../../../dist/cjs/src/primitives/TransactionSignature'
|
|
3
|
-
import { toHex, toArray } from '../../../dist/cjs/src/primitives/utils'
|
|
4
|
-
import Script from '../../../dist/cjs/src/script/Script'
|
|
5
|
-
import UnlockingScript from '../../../dist/cjs/src/script/UnlockingScript'
|
|
6
|
-
import LockingScript from '../../../dist/cjs/src/script/LockingScript'
|
|
7
|
-
import Transaction from '../../../dist/cjs/src/transaction/Transaction'
|
|
8
|
-
import { hash256, hash160 } from '../../../dist/cjs/src/primitives/Hash'
|
|
9
|
-
import PrivateKey from '../../../dist/cjs/src/primitives/PrivateKey'
|
|
10
|
-
import Curve from '../../../dist/cjs/src/primitives/Curve'
|
|
11
|
-
import P2PKH from '../../../dist/cjs/src/script/templates/P2PKH'
|
|
12
|
-
|
|
13
|
-
import sighashVectors from '../../primitives/__tests/sighash.vectors'
|
|
14
|
-
import invalidTransactions from './tx.invalid.vectors'
|
|
15
|
-
import validTransactions from './tx.valid.vectors'
|
|
16
|
-
import bigTX from './bigtx.vectors'
|
|
17
|
-
|
|
18
|
-
const BRC62Hex = '0100beef01fe636d0c0007021400fe507c0c7aa754cef1f7889d5fd395cf1f785dd7de98eed895dbedfe4e5bc70d1502ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e010b00bc4ff395efd11719b277694cface5aa50d085a0bb81f613f70313acd28cf4557010400574b2d9142b8d28b61d88e3b2c3f44d858411356b49a28a4643b6d1a6a092a5201030051a05fc84d531b5d250c23f4f886f6812f9fe3f402d61607f977b4ecd2701c19010000fd781529d58fc2523cf396a7f25440b409857e7e221766c57214b1d38c7b481f01010062f542f45ea3660f86c013ced80534cb5fd4c19d66c56e7e8c5d4bf2d40acc5e010100b121e91836fd7cd5102b654e9f72f3cf6fdbfd0b161c53a9c54b12c841126331020100000001cd4e4cac3c7b56920d1e7655e7e260d31f29d9a388d04910f1bbd72304a79029010000006b483045022100e75279a205a547c445719420aa3138bf14743e3f42618e5f86a19bde14bb95f7022064777d34776b05d816daf1699493fcdf2ef5a5ab1ad710d9c97bfb5b8f7cef3641210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013e660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000001000100000001ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e000000006a47304402203a61a2e931612b4bda08d541cfb980885173b8dcf64a3471238ae7abcd368d6402204cbf24f04b9aa2256d8901f0ed97866603d2be8324c2bfb7a37bf8fc90edd5b441210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013c660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000000'
|
|
19
|
-
|
|
20
|
-
describe('Transaction', () => {
|
|
21
|
-
const txIn = {
|
|
22
|
-
sourceTXID: '0000000000000000000000000000000000000000000000000000000000000000',
|
|
23
|
-
sourceOutputIndex: 0,
|
|
24
|
-
unlockingScript: UnlockingScript.fromHex('ae'),
|
|
25
|
-
sequence: 0
|
|
26
|
-
}
|
|
27
|
-
const txOut = {
|
|
28
|
-
satoshis: BigNumber.fromHex('0500000000000000', 'be'),
|
|
29
|
-
lockingScript: LockingScript.fromHex('ae')
|
|
30
|
-
}
|
|
31
|
-
const tx = new Transaction(0, [txIn], [txOut], 0)
|
|
32
|
-
const txhex =
|
|
33
|
-
'000000000100000000000000000000000000000000000000000000000000000000000000000000000001ae0000000001050000000000000001ae00000000'
|
|
34
|
-
const txbuf = toArray(txhex, 'hex')
|
|
35
|
-
|
|
36
|
-
const tx2idhex = '8c9aa966d35bfeaf031409e0001b90ccdafd8d859799eb945a3c515b8260bcf2'
|
|
37
|
-
const tx2hex =
|
|
38
|
-
'01000000029e8d016a7b0dc49a325922d05da1f916d1e4d4f0cb840c9727f3d22ce8d1363f000000008c493046022100e9318720bee5425378b4763b0427158b1051eec8b08442ce3fbfbf7b30202a44022100d4172239ebd701dae2fbaaccd9f038e7ca166707333427e3fb2a2865b19a7f27014104510c67f46d2cbb29476d1f0b794be4cb549ea59ab9cc1e731969a7bf5be95f7ad5e7f904e5ccf50a9dc1714df00fbeb794aa27aaff33260c1032d931a75c56f2ffffffffa3195e7a1ab665473ff717814f6881485dc8759bebe97e31c301ffe7933a656f020000008b48304502201c282f35f3e02a1f32d2089265ad4b561f07ea3c288169dedcf2f785e6065efa022100e8db18aadacb382eed13ee04708f00ba0a9c40e3b21cf91da8859d0f7d99e0c50141042b409e1ebbb43875be5edde9c452c82c01e3903d38fa4fd89f3887a52cb8aea9dc8aec7e2c9d5b3609c03eb16259a2537135a1bf0f9c5fbbcbdbaf83ba402442ffffffff02206b1000000000001976a91420bb5c3bfaef0231dc05190e7f1c8e22e098991e88acf0ca0100000000001976a9149e3e2d23973a04ec1b02be97c30ab9f2f27c3b2c88ac00000000'
|
|
39
|
-
const tx2buf = toArray(tx2hex, 'hex')
|
|
40
|
-
|
|
41
|
-
it('should make a new transaction', () => {
|
|
42
|
-
let tx = new Transaction()
|
|
43
|
-
expect(tx).toBeDefined()
|
|
44
|
-
tx = new Transaction()
|
|
45
|
-
expect(tx).toBeDefined()
|
|
46
|
-
|
|
47
|
-
expect(Transaction.fromBinary(txbuf).toHex()).toEqual(txhex)
|
|
48
|
-
|
|
49
|
-
// should set known defaults
|
|
50
|
-
expect(tx.version).toEqual(1)
|
|
51
|
-
expect(tx.inputs.length).toEqual(0)
|
|
52
|
-
expect(tx.outputs.length).toEqual(0)
|
|
53
|
-
expect(tx.lockTime).toEqual(0)
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
describe('#constructor', () => {
|
|
57
|
-
it('should set these known defaults', () => {
|
|
58
|
-
const tx = new Transaction()
|
|
59
|
-
expect(tx.version).toEqual(1)
|
|
60
|
-
expect(tx.inputs.length).toEqual(0)
|
|
61
|
-
expect(tx.outputs.length).toEqual(0)
|
|
62
|
-
expect(tx.lockTime).toEqual(0)
|
|
63
|
-
})
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
describe('#fromHex', () => {
|
|
67
|
-
it('should recover from this known tx', () => {
|
|
68
|
-
expect(Transaction.fromHex(txhex).toHex()).toEqual(txhex)
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('should recover from this known tx from the blockchain', () => {
|
|
72
|
-
expect(Transaction.fromHex(tx2hex).toHex()).toEqual(tx2hex)
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
describe('#fromBinary', () => {
|
|
77
|
-
it('should recover from this known tx', () => {
|
|
78
|
-
expect(toHex(Transaction.fromBinary(txbuf).toBinary())).toEqual(txhex)
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
it('should recover from this known tx from the blockchain', () => {
|
|
82
|
-
expect(toHex(Transaction.fromBinary(tx2buf).toBinary())).toEqual(tx2hex)
|
|
83
|
-
})
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
describe('#toHex', () => {
|
|
87
|
-
it('should produce this known tx', () => {
|
|
88
|
-
expect(Transaction.fromHex(txhex).toHex()).toEqual(txhex)
|
|
89
|
-
})
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
describe('#toBinary', () => {
|
|
93
|
-
it('should produce this known tx', () => {
|
|
94
|
-
expect(toHex(Transaction.fromBinary(txbuf).toBinary())).toEqual(txhex)
|
|
95
|
-
})
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
describe('#hash', () => {
|
|
99
|
-
it('should correctly calculate the hash of this known transaction', () => {
|
|
100
|
-
const tx = Transaction.fromBinary(tx2buf)
|
|
101
|
-
expect(toHex(tx.hash().reverse())).toEqual(tx2idhex)
|
|
102
|
-
})
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
describe('#id', () => {
|
|
106
|
-
it('should correctly calculate the txid of this known transaction', () => {
|
|
107
|
-
const tx = Transaction.fromBinary(tx2buf)
|
|
108
|
-
expect(tx.id('hex')).toEqual(tx2idhex)
|
|
109
|
-
})
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
describe('#addInput', () => {
|
|
113
|
-
it('should add an input', () => {
|
|
114
|
-
const txIn = {
|
|
115
|
-
sourceTXID: '0000000000000000000000000000000000000000000000000000000000000000',
|
|
116
|
-
sourceOutputIndex: 0,
|
|
117
|
-
unlockingScript: new UnlockingScript(),
|
|
118
|
-
sequence: 0xffffffff
|
|
119
|
-
}
|
|
120
|
-
const tx = new Transaction()
|
|
121
|
-
expect(tx.inputs.length).toEqual(0)
|
|
122
|
-
tx.addInput(txIn)
|
|
123
|
-
expect(tx.inputs.length).toEqual(1)
|
|
124
|
-
})
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
describe('#addOutput', () => {
|
|
128
|
-
it('should add an output', () => {
|
|
129
|
-
const txOut = {
|
|
130
|
-
lockingScript: new LockingScript(),
|
|
131
|
-
satoshis: new BigNumber(0)
|
|
132
|
-
}
|
|
133
|
-
const tx = new Transaction()
|
|
134
|
-
expect(tx.outputs.length).toEqual(0)
|
|
135
|
-
tx.addOutput(txOut)
|
|
136
|
-
expect(tx.outputs.length).toEqual(1)
|
|
137
|
-
})
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
describe('Signing', () => {
|
|
141
|
-
it('Signs unlocking script templates, hydrating the scripts', async () => {
|
|
142
|
-
const privateKey = new PrivateKey(1)
|
|
143
|
-
const publicKey = new Curve().g.mul(privateKey)
|
|
144
|
-
const publicKeyHash = hash160(publicKey.encode(true)) as number[]
|
|
145
|
-
const p2pkh = new P2PKH()
|
|
146
|
-
const sourceTx = new Transaction(1, [], [{
|
|
147
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
148
|
-
satoshis: new BigNumber(4000)
|
|
149
|
-
}], 0)
|
|
150
|
-
const spendTx = new Transaction(1, [{
|
|
151
|
-
sourceTransaction: sourceTx,
|
|
152
|
-
sourceOutputIndex: 0,
|
|
153
|
-
unlockingScriptTemplate: p2pkh.unlock(privateKey),
|
|
154
|
-
sequence: 0xffffffff
|
|
155
|
-
}], [{
|
|
156
|
-
satoshis: new BigNumber(1000),
|
|
157
|
-
lockingScript: p2pkh.lock(publicKeyHash)
|
|
158
|
-
}, {
|
|
159
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
160
|
-
change: true
|
|
161
|
-
}], 0)
|
|
162
|
-
expect(spendTx.inputs[0].unlockingScript).not.toBeDefined()
|
|
163
|
-
await spendTx.fee()
|
|
164
|
-
await spendTx.sign()
|
|
165
|
-
expect(spendTx.inputs[0].unlockingScript).toBeDefined()
|
|
166
|
-
// P2PKH unlocking scripts have two chunks (the signature and public key)
|
|
167
|
-
expect(spendTx.inputs[0].unlockingScript.chunks.length).toBe(2)
|
|
168
|
-
})
|
|
169
|
-
it('Throws an Error if signing before the fee is computed', async () => {
|
|
170
|
-
const privateKey = new PrivateKey(1)
|
|
171
|
-
const publicKey = new Curve().g.mul(privateKey)
|
|
172
|
-
const publicKeyHash = hash160(publicKey.encode(true)) as number[]
|
|
173
|
-
const p2pkh = new P2PKH()
|
|
174
|
-
const sourceTx = new Transaction(1, [], [{
|
|
175
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
176
|
-
satoshis: new BigNumber(4000)
|
|
177
|
-
}], 0)
|
|
178
|
-
const spendTx = new Transaction(1, [{
|
|
179
|
-
sourceTransaction: sourceTx,
|
|
180
|
-
sourceOutputIndex: 0,
|
|
181
|
-
unlockingScriptTemplate: p2pkh.unlock(privateKey),
|
|
182
|
-
sequence: 0xffffffff
|
|
183
|
-
}], [{
|
|
184
|
-
satoshis: new BigNumber(1000),
|
|
185
|
-
lockingScript: p2pkh.lock(publicKeyHash)
|
|
186
|
-
}, {
|
|
187
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
188
|
-
change: true
|
|
189
|
-
}], 0)
|
|
190
|
-
await expect(spendTx.sign()).rejects.toThrow()
|
|
191
|
-
})
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
describe('Fees', () => {
|
|
195
|
-
it('Computes fees with the default fee model', async () => {
|
|
196
|
-
const privateKey = new PrivateKey(1)
|
|
197
|
-
const publicKey = new Curve().g.mul(privateKey)
|
|
198
|
-
const publicKeyHash = hash160(publicKey.encode(true)) as number[]
|
|
199
|
-
const p2pkh = new P2PKH()
|
|
200
|
-
const sourceTx = new Transaction(1, [], [{
|
|
201
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
202
|
-
satoshis: 4000
|
|
203
|
-
}], 0)
|
|
204
|
-
const spendTx = new Transaction(1, [{
|
|
205
|
-
sourceTransaction: sourceTx,
|
|
206
|
-
sourceOutputIndex: 0,
|
|
207
|
-
unlockingScriptTemplate: p2pkh.unlock(privateKey),
|
|
208
|
-
sequence: 0xffffffff
|
|
209
|
-
}], [{
|
|
210
|
-
satoshis: new BigNumber(1000),
|
|
211
|
-
lockingScript: p2pkh.lock(publicKeyHash)
|
|
212
|
-
}, {
|
|
213
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
214
|
-
change: true
|
|
215
|
-
}], 0)
|
|
216
|
-
expect(spendTx.outputs[1].satoshis).not.toBeDefined()
|
|
217
|
-
await spendTx.fee()
|
|
218
|
-
// Transaction size is 225 bytes for one-input two-output P2PKH.
|
|
219
|
-
// Default fee rate is 10 sat/kb = 2.25 sats (round up to 3).
|
|
220
|
-
// 4000 sats in - 1000 sats out - 3 sats fee = expected 2997 sats change.
|
|
221
|
-
expect(spendTx.outputs[1].satoshis).toEqual(2997)
|
|
222
|
-
})
|
|
223
|
-
it('Computes fees with a custom fee model', async () => {
|
|
224
|
-
const privateKey = new PrivateKey(1)
|
|
225
|
-
const publicKey = new Curve().g.mul(privateKey)
|
|
226
|
-
const publicKeyHash = hash160(publicKey.encode(true)) as number[]
|
|
227
|
-
const p2pkh = new P2PKH()
|
|
228
|
-
const sourceTx = new Transaction(1, [], [{
|
|
229
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
230
|
-
satoshis: 4000
|
|
231
|
-
}], 0)
|
|
232
|
-
const spendTx = new Transaction(1, [{
|
|
233
|
-
sourceTransaction: sourceTx,
|
|
234
|
-
sourceOutputIndex: 0,
|
|
235
|
-
unlockingScriptTemplate: p2pkh.unlock(privateKey),
|
|
236
|
-
sequence: 0xffffffff
|
|
237
|
-
}], [{
|
|
238
|
-
satoshis: 1000,
|
|
239
|
-
lockingScript: p2pkh.lock(publicKeyHash)
|
|
240
|
-
}, {
|
|
241
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
242
|
-
change: true
|
|
243
|
-
}], 0)
|
|
244
|
-
expect(spendTx.outputs[1].satoshis).not.toBeDefined()
|
|
245
|
-
await spendTx.fee({
|
|
246
|
-
// Our custom fee model will always charge 1033 sats for a tx.
|
|
247
|
-
computeFee: async () => 1033
|
|
248
|
-
})
|
|
249
|
-
// 4000 sats in - 1000 sats out - 1033 sats fee = expected 1967 sats change
|
|
250
|
-
expect(spendTx.outputs[1].satoshis).toEqual(1967)
|
|
251
|
-
})
|
|
252
|
-
it('Distributes change among multiple change outputs', async () => {
|
|
253
|
-
const privateKey = new PrivateKey(1)
|
|
254
|
-
const publicKey = new Curve().g.mul(privateKey)
|
|
255
|
-
const publicKeyHash = hash160(publicKey.encode(true)) as number[]
|
|
256
|
-
const p2pkh = new P2PKH()
|
|
257
|
-
const sourceTx = new Transaction(1, [], [{
|
|
258
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
259
|
-
satoshis: 4000
|
|
260
|
-
}], 0)
|
|
261
|
-
const spendTx = new Transaction(1, [{
|
|
262
|
-
sourceTransaction: sourceTx,
|
|
263
|
-
sourceOutputIndex: 0,
|
|
264
|
-
unlockingScriptTemplate: p2pkh.unlock(privateKey),
|
|
265
|
-
sequence: 0xffffffff
|
|
266
|
-
}], [{
|
|
267
|
-
satoshis: 1000,
|
|
268
|
-
lockingScript: p2pkh.lock(publicKeyHash)
|
|
269
|
-
}, {
|
|
270
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
271
|
-
change: true
|
|
272
|
-
}, {
|
|
273
|
-
lockingScript: p2pkh.lock(publicKeyHash),
|
|
274
|
-
change: true
|
|
275
|
-
}], 0)
|
|
276
|
-
expect(spendTx.outputs[1].satoshis).not.toBeDefined()
|
|
277
|
-
expect(spendTx.outputs[2].satoshis).not.toBeDefined()
|
|
278
|
-
await spendTx.fee({
|
|
279
|
-
// Our custom fee model will always charge 1033 sats for a tx.
|
|
280
|
-
computeFee: async () => 1033
|
|
281
|
-
})
|
|
282
|
-
// 4000 sats in - 1000 sats out - 1033 sats fee = expected 1967 sats change
|
|
283
|
-
// Divide by 2 (no remainder) = 983 sats per change output
|
|
284
|
-
expect(spendTx.outputs[1].satoshis).toEqual(983)
|
|
285
|
-
expect(spendTx.outputs[2].satoshis).toEqual(983)
|
|
286
|
-
})
|
|
287
|
-
})
|
|
288
|
-
|
|
289
|
-
describe('Broadcast', () => {
|
|
290
|
-
it('Broadcasts with the provided Broadcaster instance', async () => {
|
|
291
|
-
const mockBroadcast = jest.fn(() => 'MOCK_RV')
|
|
292
|
-
const tx = new Transaction()
|
|
293
|
-
const rv = await tx.broadcast({
|
|
294
|
-
broadcast: mockBroadcast
|
|
295
|
-
})
|
|
296
|
-
expect(mockBroadcast).toHaveBeenCalledWith(tx)
|
|
297
|
-
expect(rv).toEqual('MOCK_RV')
|
|
298
|
-
})
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
describe('BEEF', () => {
|
|
302
|
-
it('Serialization and deserialization', async () => {
|
|
303
|
-
const tx = Transaction.fromBEEF(toArray(BRC62Hex, 'hex'))
|
|
304
|
-
expect(tx.inputs[0].sourceTransaction.merklePath.blockHeight).toEqual(814435)
|
|
305
|
-
const beef = toHex(tx.toBEEF())
|
|
306
|
-
expect(beef).toEqual(BRC62Hex)
|
|
307
|
-
})
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
describe('EF', () => {
|
|
311
|
-
it('Serialization and deserialization', async () => {
|
|
312
|
-
const tx = Transaction.fromBEEF(toArray(BRC62Hex, 'hex'))
|
|
313
|
-
const ef = toHex(tx.toEF())
|
|
314
|
-
expect(ef).toEqual('010000000000000000ef01ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e000000006a47304402203a61a2e931612b4bda08d541cfb980885173b8dcf64a3471238ae7abcd368d6402204cbf24f04b9aa2256d8901f0ed97866603d2be8324c2bfb7a37bf8fc90edd5b441210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff3e660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac013c660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac00000000')
|
|
315
|
-
})
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
describe('Verification', () => {
|
|
319
|
-
it('Verifies the transaction from the BEEF spec', async () => {
|
|
320
|
-
const tx = Transaction.fromBEEF(toArray(BRC62Hex, 'hex'))
|
|
321
|
-
const alwaysYesChainTracker = {
|
|
322
|
-
isValidRootForHeight: async () => true
|
|
323
|
-
}
|
|
324
|
-
const verified = await tx.verify(alwaysYesChainTracker)
|
|
325
|
-
expect(verified).toBe(true)
|
|
326
|
-
})
|
|
327
|
-
})
|
|
328
|
-
|
|
329
|
-
describe('vectors: a 1mb transaction', () => {
|
|
330
|
-
it('should find the correct id of this (valid, on the blockchain) 1 mb transaction', () => {
|
|
331
|
-
const txidhex = bigTX.txidhex
|
|
332
|
-
const txhex = bigTX.txhex
|
|
333
|
-
const tx = Transaction.fromHex(txhex)
|
|
334
|
-
const txid = tx.id('hex')
|
|
335
|
-
expect(txid).toEqual(txidhex)
|
|
336
|
-
})
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
describe('vectors: sighash and serialization', () => {
|
|
340
|
-
sighashVectors.forEach((vector, i) => {
|
|
341
|
-
if (i === 0) {
|
|
342
|
-
return
|
|
343
|
-
}
|
|
344
|
-
it(`should pass bitcoin-abc sighash test vector ${i}`, () => {
|
|
345
|
-
const txbuf = toArray(vector[0], 'hex')
|
|
346
|
-
const scriptbuf = toArray(vector[1], 'hex')
|
|
347
|
-
const subScript = Script.fromBinary(scriptbuf)
|
|
348
|
-
const nIn = (vector[2]) as number
|
|
349
|
-
const nHashType = (vector[3]) as number
|
|
350
|
-
const sighashBuf = toArray(vector[4], 'hex')
|
|
351
|
-
const tx = Transaction.fromBinary(txbuf)
|
|
352
|
-
|
|
353
|
-
// make sure transacion to/from buffer is isomorphic
|
|
354
|
-
expect(toHex(tx.toBinary())).toEqual(toHex(txbuf))
|
|
355
|
-
|
|
356
|
-
// sighash ought to be correct
|
|
357
|
-
const valueBn = new BigNumber(0)
|
|
358
|
-
const otherInputs = [...tx.inputs]
|
|
359
|
-
const [input] = otherInputs.splice(nIn, 1)
|
|
360
|
-
const preimage = TransactionSignature.format({
|
|
361
|
-
sourceTXID: input.sourceTXID,
|
|
362
|
-
sourceOutputIndex: input.sourceOutputIndex,
|
|
363
|
-
sourceSatoshis: valueBn,
|
|
364
|
-
transactionVersion: tx.version,
|
|
365
|
-
otherInputs,
|
|
366
|
-
outputs: tx.outputs,
|
|
367
|
-
inputIndex: nIn,
|
|
368
|
-
subscript: subScript,
|
|
369
|
-
inputSequence: input.sequence,
|
|
370
|
-
lockTime: tx.lockTime,
|
|
371
|
-
scope: nHashType
|
|
372
|
-
})
|
|
373
|
-
const hash = hash256(preimage) as number[]
|
|
374
|
-
hash.reverse()
|
|
375
|
-
expect(toHex(hash)).toEqual(toHex(sighashBuf))
|
|
376
|
-
})
|
|
377
|
-
})
|
|
378
|
-
|
|
379
|
-
validTransactions.forEach((vector, i) => {
|
|
380
|
-
if (vector.length === 1) {
|
|
381
|
-
return
|
|
382
|
-
}
|
|
383
|
-
it(`should correctly serialized/deserialize tx_valid test vector ${i}`, () => {
|
|
384
|
-
const expectedHex = vector[1]
|
|
385
|
-
const expectedBin = toArray(vector[1], 'hex')
|
|
386
|
-
const actualTX = Transaction.fromBinary(expectedBin)
|
|
387
|
-
const actualBin = actualTX.toBinary()
|
|
388
|
-
const actualHex = toHex(actualBin)
|
|
389
|
-
expect(actualHex).toEqual(expectedHex)
|
|
390
|
-
})
|
|
391
|
-
})
|
|
392
|
-
|
|
393
|
-
invalidTransactions.forEach((vector, i) => {
|
|
394
|
-
if (vector.length === 1) {
|
|
395
|
-
return
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// 151, 142 and 25 have invalid Satoshi amounts that exceed 53 bits in length, causing exceptions that make serialization and deserialization impossible.
|
|
399
|
-
if (i === 151 || i === 142 || i === 25) {
|
|
400
|
-
return
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
it(`should correctly serialized/deserialize tx_invalid test vector ${i}`, () => {
|
|
404
|
-
const expectedHex = vector[1]
|
|
405
|
-
const expectedBin = toArray(vector[1], 'hex')
|
|
406
|
-
const actualTX = Transaction.fromBinary(expectedBin)
|
|
407
|
-
const actualBin = actualTX.toBinary()
|
|
408
|
-
const actualHex = toHex(actualBin)
|
|
409
|
-
expect(actualHex).toEqual(expectedHex)
|
|
410
|
-
})
|
|
411
|
-
})
|
|
412
|
-
})
|
|
413
|
-
})
|