@bsv/sdk 1.0.4 → 1.0.6

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 (86) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/primitives/BigNumber.js +1 -1
  3. package/dist/cjs/src/primitives/BigNumber.js.map +1 -1
  4. package/dist/cjs/src/primitives/Hash.js +98 -56
  5. package/dist/cjs/src/primitives/Hash.js.map +1 -1
  6. package/dist/cjs/src/primitives/PrivateKey.js +23 -0
  7. package/dist/cjs/src/primitives/PrivateKey.js.map +1 -1
  8. package/dist/cjs/src/primitives/PublicKey.js +19 -1
  9. package/dist/cjs/src/primitives/PublicKey.js.map +1 -1
  10. package/dist/cjs/src/primitives/SymmetricKey.js +14 -1
  11. package/dist/cjs/src/primitives/SymmetricKey.js.map +1 -1
  12. package/dist/cjs/src/primitives/index.js +3 -1
  13. package/dist/cjs/src/primitives/index.js.map +1 -1
  14. package/dist/cjs/src/primitives/utils.js +3 -3
  15. package/dist/cjs/src/primitives/utils.js.map +1 -1
  16. package/dist/cjs/src/script/templates/P2PKH.js +14 -3
  17. package/dist/cjs/src/script/templates/P2PKH.js.map +1 -1
  18. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  19. package/dist/esm/src/primitives/BigNumber.js +1 -1
  20. package/dist/esm/src/primitives/BigNumber.js.map +1 -1
  21. package/dist/esm/src/primitives/Hash.js +98 -56
  22. package/dist/esm/src/primitives/Hash.js.map +1 -1
  23. package/dist/esm/src/primitives/PrivateKey.js +23 -0
  24. package/dist/esm/src/primitives/PrivateKey.js.map +1 -1
  25. package/dist/esm/src/primitives/PublicKey.js +19 -1
  26. package/dist/esm/src/primitives/PublicKey.js.map +1 -1
  27. package/dist/esm/src/primitives/SymmetricKey.js +14 -1
  28. package/dist/esm/src/primitives/SymmetricKey.js.map +1 -1
  29. package/dist/esm/src/primitives/index.js +1 -0
  30. package/dist/esm/src/primitives/index.js.map +1 -1
  31. package/dist/esm/src/primitives/utils.js +3 -3
  32. package/dist/esm/src/primitives/utils.js.map +1 -1
  33. package/dist/esm/src/script/templates/P2PKH.js +14 -3
  34. package/dist/esm/src/script/templates/P2PKH.js.map +1 -1
  35. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  36. package/dist/types/src/primitives/BigNumber.d.ts +1 -1
  37. package/dist/types/src/primitives/BigNumber.d.ts.map +1 -1
  38. package/dist/types/src/primitives/Hash.d.ts +73 -34
  39. package/dist/types/src/primitives/Hash.d.ts.map +1 -1
  40. package/dist/types/src/primitives/PrivateKey.d.ts +16 -1
  41. package/dist/types/src/primitives/PrivateKey.d.ts.map +1 -1
  42. package/dist/types/src/primitives/PublicKey.d.ts +14 -2
  43. package/dist/types/src/primitives/PublicKey.d.ts.map +1 -1
  44. package/dist/types/src/primitives/SymmetricKey.d.ts +11 -0
  45. package/dist/types/src/primitives/SymmetricKey.d.ts.map +1 -1
  46. package/dist/types/src/primitives/index.d.ts +1 -0
  47. package/dist/types/src/primitives/index.d.ts.map +1 -1
  48. package/dist/types/src/primitives/utils.d.ts +2 -2
  49. package/dist/types/src/script/templates/P2PKH.d.ts +3 -3
  50. package/dist/types/src/script/templates/P2PKH.d.ts.map +1 -1
  51. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  52. package/docs/examples/EXAMPLE_BUILDING_CUSTOM_TX_BROADCASTER.md +89 -0
  53. package/docs/examples/EXAMPLE_COMPLEX_TX.md +164 -0
  54. package/docs/examples/EXAMPLE_ECIES.md +37 -0
  55. package/docs/examples/EXAMPLE_ENCRYPT_DECRYPT_MESSAGE.md +52 -0
  56. package/docs/examples/EXAMPLE_FEE_MODELING.md +199 -0
  57. package/docs/examples/EXAMPLE_HD_WALLETS.md +71 -0
  58. package/docs/examples/EXAMPLE_MESSAGE_SIGNING.md +63 -0
  59. package/docs/examples/EXAMPLE_PULSE_HEADERS.md +140 -0
  60. package/docs/examples/EXAMPLE_SCRIPT_TEMPLATES.md +170 -0
  61. package/docs/examples/EXAMPLE_SIMPLE_TX.md +64 -0
  62. package/docs/examples/EXAMPLE_TYPE_42.md +108 -0
  63. package/docs/examples/EXAMPLE_VERIFYING_BEEF.md +55 -0
  64. package/docs/examples/EXAMPLE_VERIFYING_SPENDS.md +69 -0
  65. package/docs/examples/GETTING_STARTED_NODE_CJS.md +73 -0
  66. package/docs/examples/GETTING_STARTED_REACT.md +121 -0
  67. package/docs/examples/README.md +19 -0
  68. package/docs/low-level/README.md +6 -0
  69. package/docs/low-level/TX_SIG.md +129 -0
  70. package/docs/low-level/TYPE_42.md +0 -0
  71. package/docs/primitives.md +679 -566
  72. package/docs/script.md +4 -4
  73. package/package.json +1 -1
  74. package/src/primitives/BigNumber.ts +2 -1
  75. package/src/primitives/Hash.ts +118 -64
  76. package/src/primitives/PrivateKey.ts +28 -1
  77. package/src/primitives/PublicKey.ts +24 -2
  78. package/src/primitives/SymmetricKey.ts +17 -3
  79. package/src/primitives/__tests/HMAC.test.ts +2 -2
  80. package/src/primitives/__tests/Hash.test.ts +2 -2
  81. package/src/primitives/index.ts +1 -0
  82. package/src/primitives/utils.ts +3 -3
  83. package/src/script/__tests/Script.test.ts +34 -0
  84. package/src/script/__tests/Spend.test.ts +7 -7
  85. package/src/script/templates/P2PKH.ts +13 -4
  86. package/src/transaction/__tests/Transaction.test.ts +1 -1
@@ -0,0 +1,170 @@
1
+ # Example: Creating the R-puzzle Script Template
2
+
3
+ This guide will provide information about the structure and functionality of script templates within the BSV SDK. Script templates are a powerful abstraction layer designed to simplify the creation and management of the scripts used in Bitcoin transactions. By understanding how these templates work, developers can leverage them to build more sophisticated and efficient blockchain applications. By the end of this example, you'll understand how the R-puzzle script template (P2RPH) was created.
4
+
5
+ ### Understanding Script Templates
6
+
7
+ A script template is essentially a blueprint for creating the locking and unlocking scripts that are crucial for securing and spending bitcoins. These templates encapsulate the logic needed to construct these scripts dynamically, based on the parameters passed to them. This approach allows for a modular and reusable codebase, where common scripting patterns can be defined once and then instantiated as needed across different transactions.
8
+
9
+ #### Locking Script
10
+
11
+ The locking script, or output script, specifies the conditions under which the bitcoins can be spent. In the BSV SDK, the `lock` function of a script template is responsible for generating this script. By abstracting the creation of locking scripts into a method that accepts parameters, developers can easily create diverse conditions for spending bitcoins without having to write the low-level script code each time.
12
+
13
+ For example, a locking script might require the presentation of a public key that matches a certain hash or the fulfillment of a multi-signature condition. The flexibility of passing parameters to the `lock` function enables the creation of locking scripts tailored to specific requirements. This example will require a signature created with a particular ephemeral K-value, [an R-puzzle](https://wiki.bitcoinsv.io/index.php/R-Puzzles).
14
+
15
+ #### Unlocking Script
16
+
17
+ The unlocking script, or input script, provides the evidence needed to satisfy the conditions set by the locking script. The `unlock` method in a script template not only generates this script but also offers two key functionalities — it's a function that returns an object with two properties:
18
+
19
+ 1. **`estimateLength`**: Before a transaction is signed and broadcast to the network, it's crucial to estimate its size to calculate the required fee accurately. The `estimateLength` function predicts the length of the unlocking script once it will be created, allowing developers to make informed decisions about fee estimation.
20
+
21
+ 2. **`sign`**: This function generates an unlocking script that includes the necessary signatures or data required to unlock the bitcoins. By accepting a transaction and an input index as arguments, it ensures that the unlocking script is correctly associated with the specific transaction input it intends to fund, allowing signatures to be scoped accordingly.
22
+
23
+ ### Creating a Script Template
24
+
25
+ To create a script template, developers define a class that adheres to the `ScriptTemplate` interface. This involves implementing the `lock` and `unlock` methods with the specific logic needed for their application.
26
+
27
+ Now that you understand the necessary components, here's the code for the R-puzzle script template:
28
+
29
+ ```javascript
30
+ import {
31
+ OP, ScriptTemplate, LockingScript, UnlockingScript, Transaction,
32
+ PrivateKey, TransactionSignature, sha256, ScriptChunk, BigNumber
33
+ } from '@bsv/sdk'
34
+
35
+ /**
36
+ * RPuzzle class implementing ScriptTemplate.
37
+ *
38
+ * This class provides methods to create R Puzzle and R Puzzle Hash locking and unlocking scripts, including the unlocking of UTXOs with the correct K value.
39
+ */
40
+ export default class RPuzzle implements ScriptTemplate {
41
+ type: 'raw' | 'SHA1' | 'SHA256' | 'HASH256' | 'RIPEMD160' | 'HASH160' = 'raw'
42
+
43
+ /**
44
+ * @constructor
45
+ * Constructs an R Puzzle template instance for a given puzzle type
46
+ *
47
+ * @param {'raw'|'SHA1'|'SHA256'|'HASH256'|'RIPEMD160'|'HASH160'} type Denotes the type of puzzle to create
48
+ */
49
+ constructor (type: 'raw' | 'SHA1' | 'SHA256' | 'HASH256' | 'RIPEMD160' | 'HASH160' = 'raw') {
50
+ this.type = type
51
+ }
52
+
53
+ /**
54
+ * Creates an R puzzle locking script for a given R value or R value hash.
55
+ *
56
+ * @param {number[]} value - An array representing the R value or its hash.
57
+ * @returns {LockingScript} - An R puzzle locking script.
58
+ */
59
+ lock (value: number[]): LockingScript {
60
+ const chunks: ScriptChunk[] = [
61
+ { op: OP.OP_OVER },
62
+ { op: OP.OP_3 },
63
+ { op: OP.OP_SPLIT },
64
+ { op: OP.OP_NIP },
65
+ { op: OP.OP_1 },
66
+ { op: OP.OP_SPLIT },
67
+ { op: OP.OP_SWAP },
68
+ { op: OP.OP_SPLIT },
69
+ { op: OP.OP_DROP }
70
+ ]
71
+ if (this.type !== 'raw') {
72
+ chunks.push({
73
+ op: OP['OP_' + this.type]
74
+ })
75
+ }
76
+ chunks.push({ op: value.length, data: value })
77
+ chunks.push({ op: OP.OP_EQUALVERIFY })
78
+ chunks.push({ op: OP.OP_CHECKSIG })
79
+ return new LockingScript(chunks)
80
+ }
81
+
82
+ /**
83
+ * Creates a function that generates an R puzzle unlocking script along with its signature and length estimation.
84
+ *
85
+ * The returned object contains:
86
+ * 1. `sign` - A function that, when invoked with a transaction and an input index,
87
+ * produces an unlocking script suitable for an R puzzle locked output.
88
+ * 2. `estimateLength` - A function that returns the estimated length of the unlocking script in bytes.
89
+ *
90
+ * @param {BigNumber} k — The K-value used to unlock the R-puzzle.
91
+ * @param {PrivateKey} privateKey - The private key used for signing the transaction. If not provided, a random key will be generated.
92
+ * @param {'all'|'none'|'single'} signOutputs - The signature scope for outputs.
93
+ * @param {boolean} anyoneCanPay - Flag indicating if the signature allows for other inputs to be added later.
94
+ * @returns {Object} - An object containing the `sign` and `estimateLength` functions.
95
+ */
96
+ unlock (
97
+ k: BigNumber,
98
+ privateKey: PrivateKey,
99
+ signOutputs: 'all' | 'none' | 'single' = 'all',
100
+ anyoneCanPay: boolean = false
101
+ ): {
102
+ sign: (tx: Transaction, inputIndex: number) => Promise<UnlockingScript>
103
+ estimateLength: () => Promise<106>
104
+ } {
105
+ return {
106
+ sign: async (tx: Transaction, inputIndex: number) => {
107
+ if (typeof privateKey === 'undefined') {
108
+ privateKey = PrivateKey.fromRandom()
109
+ }
110
+ let signatureScope = TransactionSignature.SIGHASH_FORKID
111
+ if (signOutputs === 'all') {
112
+ signatureScope |= TransactionSignature.SIGHASH_ALL
113
+ }
114
+ if (signOutputs === 'none') {
115
+ signatureScope |= TransactionSignature.SIGHASH_NONE
116
+ }
117
+ if (signOutputs === 'single') {
118
+ signatureScope |= TransactionSignature.SIGHASH_SINGLE
119
+ }
120
+ if (anyoneCanPay) {
121
+ signatureScope |= TransactionSignature.SIGHASH_ANYONECANPAY
122
+ }
123
+ const otherInputs = [...tx.inputs]
124
+ const [input] = otherInputs.splice(inputIndex, 1)
125
+ if (typeof input.sourceTransaction !== 'object') {
126
+ throw new Error(
127
+ 'The source transaction is needed for transaction signing.'
128
+ )
129
+ }
130
+ const preimage = TransactionSignature.format({
131
+ sourceTXID: input.sourceTransaction.id('hex') as string,
132
+ sourceOutputIndex: input.sourceOutputIndex,
133
+ sourceSatoshis: input.sourceTransaction.outputs[input.sourceOutputIndex].satoshis,
134
+ transactionVersion: tx.version,
135
+ otherInputs,
136
+ inputIndex,
137
+ outputs: tx.outputs,
138
+ inputSequence: input.sequence,
139
+ subscript: input.sourceTransaction.outputs[input.sourceOutputIndex].lockingScript,
140
+ lockTime: tx.lockTime,
141
+ scope: signatureScope
142
+ })
143
+ const rawSignature = privateKey.sign(sha256(preimage), undefined, true, k)
144
+ const sig = new TransactionSignature(
145
+ rawSignature.r,
146
+ rawSignature.s,
147
+ signatureScope
148
+ )
149
+ const sigForScript = sig.toChecksigFormat()
150
+ const pubkeyForScript = privateKey.toPublicKey().encode(true) as number[]
151
+ return new UnlockingScript([
152
+ { op: sigForScript.length, data: sigForScript },
153
+ { op: pubkeyForScript.length, data: pubkeyForScript }
154
+ ])
155
+ },
156
+ estimateLength: async () => {
157
+ // public key (1+33) + signature (1+71)
158
+ // Note: We add 1 to each element's length because of the associated OP_PUSH
159
+ return 106
160
+ }
161
+ }
162
+ }
163
+ }
164
+ ```
165
+
166
+ In this example, `RPuzzle` defines custom logic for creating both locking and unlocking scripts. The opcodes, intermixed with the various template fields, enable end-users to implement R-puzzles into their applications without being concerned with these low-level details. Check out [this guide](./EXAMPLE_COMPLEX_TX.md) to see an example of this template used in a transaction.
167
+
168
+ ### Conclusion
169
+
170
+ Script templates in the BSV SDK offer a structured and efficient way to handle the creation of locking and unlocking scripts in Bitcoin transactions. By encapsulating the logic for script generation and providing essential functionalities like signature creation and length estimation, script templates make it easier for developers to implement complex transactional logic. With these tools, template consumers can focus on the higher-level aspects of their blockchain applications, relying on the SDK to manage the intricacies of script handling.
@@ -0,0 +1,64 @@
1
+ # Example: Creating a Simple Transaction
2
+
3
+ This guide walks you through the steps of creating a simple Bitcoin transaction. To get started, let's explain some basic concepts around Bitcoin transactions.
4
+
5
+ ## Understanding and Creating Transactions
6
+
7
+ Transactions in Bitcoin are mechanisms for transferring value and invoking smart contract logic. The `Transaction` class in the BSV SDK encapsulates the creation, signing, and broadcasting of transactions, also enabling the use of Bitcoin's scripting language for locking and unlocking coins.
8
+
9
+ ## Creating and Signing a Transaction
10
+
11
+ Consider the scenario where you need to create a transaction. The process involves specifying inputs (where the bitcoins are coming from) and outputs (where they're going). Here's a simplified example:
12
+
13
+ ```typescript
14
+ import { Transaction, PrivateKey, PublicKey, P2PKH, ARC } from '@bsv/sdk'
15
+
16
+ const privKey = PrivateKey.fromWif('...') // Your P2PKH private key
17
+ const changePrivKey = PrivateKey.fromWif('...') // Change private key (never re-use addresses)
18
+ const recipientAddress = '1Fd5F7XR8LYHPmshLNs8cXSuVAAQzGp7Hc' // Address of the recipient
19
+
20
+ const tx = new Transaction()
21
+
22
+ // Add the input
23
+ tx.addInput({
24
+ sourceTransaction: Transaction.fromHex('...'), // The source transaction where the output you are spending was created,
25
+ sourceOutputIndex: 0, // The output index in the source transaction
26
+ unlockingScriptTemplate: new P2PKH().unlock(privKey), // The script template you are using to unlock the output, in this case P2PKH
27
+ })
28
+
29
+ // Pay an output to a recipient using the P2PKH locking template
30
+ tx.addOutput({
31
+ lockingScript: new P2PKH().lock(recipientAddress),
32
+ satoshis: 2500
33
+ })
34
+
35
+ // Send remainder back the change
36
+ tx.addOutput({
37
+ lockingScript: new P2PKH().lock(changePrivKey.toPublicKey().toHash()),
38
+ change: true
39
+ })
40
+
41
+ // Now we can compute the fee and sign the transaction
42
+ await tx.fee()
43
+ await tx.sign()
44
+
45
+ // Finally, we broadcast it with ARC.
46
+ // get your api key from https://console.taal.com
47
+ const apiKey = 'mainnet_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' // replace
48
+ await tx.broadcast(new ARC('https://api.taal.com/arc', apiKey))
49
+ ```
50
+
51
+ This code snippet demonstrates creating a transaction, adding an input and an output, setting a change script, configuring the fee, signing the transaction, and broadcasting with the ARC broadcaster. It uses the P2PKH Template, which is a specific type of Bitcoin locking program. To learn more about templates, check out this example (link to be provided once cmpplete).
52
+
53
+ ## Handling Hex Locking Scripts
54
+
55
+ Moving beyond this basic example into more advanced use-cases enables you to start dealing with custom scripts. If you're provided with a hex-encoded locking script for an output, you can set it directly in the transaction's output as follows:
56
+
57
+ ```typescript
58
+ transaction.addOutput({
59
+ lockingScript: Script.fromHex('76a9....88ac'), // Hex-encoded locking script
60
+ satoshis: 2500 // Number of satoshis
61
+ })
62
+ ```
63
+
64
+ The `Transaction` class abstracts the complexity of Bitcoin's transaction structure. It handles inputs, outputs, scripts, and serialization, offering methods to easily modify and interrogate the transaction. Check out the full code-level documentation, refer to other examples, or reach out to the community to learn more.
@@ -0,0 +1,108 @@
1
+ # Example: Using Type 42 Key Derivation for Bitcoin Wallet Management
2
+
3
+ Welcome to this type-42 key derivation guide! We're glad you're here, especially if you're migrating from an older key derivation system. Type-42 is more private, more elegant and it's easy to understand.
4
+
5
+ This guide will walk you through using type-42 keys in the context of a Bitcoin wallet.
6
+
7
+ ## Generating keys
8
+
9
+ Generating type-42 keys with the SDK is identical to generating normal private keys. Secretly, every private key (and public key) in the SDK is already a type-42 key!
10
+
11
+ ```typescript
12
+ import { PrivateKey } from '@bsv/sdk'
13
+
14
+ const privateKey = PrivateKey.fromRandom()
15
+ ```
16
+
17
+ Now, we can move on to key derivation.
18
+
19
+ ## Type 42 Key Derivation
20
+
21
+ In type-42 systems, you provide a counterparty key when deriving, as well as your own. There is always one public key and one private key. It's either:
22
+
23
+ - Your private key and the public key of your counterparty are used to derive one of your private keys, or
24
+ - Your private key and the public key of your counterparty are used to derive one of their public keys
25
+
26
+ When you and your counterparty use the same invoice number to derive keys, the public key you derive for them will correspond to the private key they derive for themselves. A private key that you derive for yourself will correspond to the public key they derived for you.
27
+
28
+ Once you understand those concepts, we're ready to jump into some code!
29
+
30
+ ### Alice and Bob
31
+
32
+ Let's consider the scenario of Alice and Bob, who want to exchange some Bitcoin. How can Alice send Bitcoins to Bob?
33
+
34
+ 1. Alice learns Bob's master public key, and they agree on the Bitcoin aount to exchange.
35
+ 2. They also agree on an invoice number.
36
+ 3. Alice uses Bob's master public key with her private key to derive the payment key she will use.
37
+ 4. Alice creates a Bitcoin transaction and pays Bob the money.
38
+ 5. Bob uses Alice's public key and his own private key to derive the corresponding private key, verifying it matches the transaction Alice sent him.
39
+
40
+ Here's an example:
41
+
42
+ ```typescript
43
+ // Alice and Bob have master private keys...
44
+ const alice = PrivateKey.fromRandom()
45
+ const bob = PrivateKey.fromRandom()
46
+ alice.toString()
47
+ '106674548343907642146062962636638307981249604845652704224160905817279514790351'
48
+ bob.toString()
49
+ '108446104340374144960104248963000752145648236191076545713737995455205583156408'
50
+
51
+ // ... and master public keys
52
+ const alicePub = alice.toPublicKey()
53
+ const bobPub = bob.toPublicKey()
54
+ alicePub.toString()
55
+ '0260846fbaf8e950c1896d360954a716f26699252b879fea1743a9f78a0950d167'
56
+ bobPub.toString()
57
+ '0258bfa42bd832c4ab655295cac5e2f64daefb2b4cd9a2b72bdd3c3f9ba5076cb7'
58
+
59
+ // To pay Alice, they agree on an invoice number and then Bob derives a key where he can pay Alice
60
+ const paymentKey = alicePub.deriveChild(bob, 'AMZN-44-1191213')
61
+
62
+ // The key can be converted to an address if desired
63
+ paymentKey2.toAddress()
64
+ '1HqfEfHNF9ji9p3AEC66mj8fhGA7sy2WYT'
65
+
66
+ // To unlock the coins, Alice derives the private key with the same invoice number, using Bob's public key
67
+ const paymentPriv = alice.deriveChild(bobPub, 'AMZN-44-1191213')
68
+
69
+ // The key can be converted to WIF if desired
70
+ paymentPriv.toWif()
71
+ 'L22stYh323a8DfBNunLvxrcrxudT2YXjdKxe1q9ecARYT9XfFGGc'
72
+
73
+ // To check, Alice can convert the private key back into an address.
74
+ paymentPriv.toPublicKey().toAddress()
75
+ '1HqfEfHNF9ji9p3AEC66mj8fhGA7sy2WYT'
76
+ ```
77
+
78
+ This provides privacy for Alice and Bob, even if eeryone in the world knows Alice and Bob's master public keys.
79
+
80
+ ## Going Further: Public Derivation
81
+
82
+ Sometimes, there is a legitimate reason to do "public key derivation" from a key, so that anyone can link a master key to a child key, like in BIP32. To accomplish this, rather than creating a new algorithm, we just use a private key that everyone already knows: the number `1`.
83
+
84
+ ```typescript
85
+ alicePub.deriveChild(new PrivateKey(1), '1').toString()
86
+ '0391ff4958a6629be3176330bed0efd99d860f2b7630c21b2e33a42f3cd1740544'
87
+ alicePub.deriveChild(new PrivateKey(1), '2').toString()
88
+ '022ea65d6d66754dc7d94e197dab31a4a8854cdb28d57f216e765af7dfddb5322d'
89
+ alicePub.deriveChild(new PrivateKey(1), 'Bitcoin SV').toString()
90
+ '039e9bf79f4cf7accc061d570b1282bd24d2045be44584e8c6744cd3ff42e1758c'
91
+ alicePub.deriveChild(new PrivateKey(1), '2-tempo-1').toString() // BRC-43 :)
92
+ '02fd1e62689b7faaa718fabe9593da718fb2f966a9b391e5c48f25b1f9fbd4e770'
93
+ ```
94
+
95
+ Because everyone knows the number `1`, everyone can derive Alice's public keys with these invoice numbers. But only Alice can derive the corresponding private keys:
96
+
97
+ ```typescript
98
+ alice.deriveChild(new PrivateKey(1).toPublicKey(), '1').toString()
99
+ '5097922263303694608415912843049723146488598519566487750842578489217455687866'
100
+ alice.deriveChild(new PrivateKey(1).toPublicKey(), '2').toString()
101
+ '30335387255051916743526252561695774618041865683431443265879198629898915116869'
102
+ alice.deriveChild(new PrivateKey(1).toPublicKey(), 'Bitcoin SV').toString()
103
+ '78577766545688955856149390014909118010252835780550951683873199149559002824861'
104
+ alice.deriveChild(new PrivateKey(1).toPublicKey(), '2-tempo-1').toString() // BRC-43 :)
105
+ '85481526811941870977151386860102277207605069038305420293413543998866547111586'
106
+ ```
107
+
108
+ The type-42 system enables both public and private key derivation, all while providing a more flexible and open-ended invoice numbering scheme than BIP32.
@@ -0,0 +1,55 @@
1
+ # Example: Verifying a BEEF Structure
2
+
3
+ The BSV SDK comes with advanced capabilities around the SPV architecture. In Bitcoin, SPV refers to the process of creating, exchanging, and verifying transactions in a way that anchors them to the blockchain. One of the standard formats for representing the necessary SPV data is known as BEEF (background-evaluated extended format), representing a transaction and its parents together with needed merkle proofs. This example will show you how to verify the legitimacy of a BEEF-formatted SPV structure you've received, checking to ensure the target transaction and its ancestors are well-anchored to the blockchain based on the current chain of block headers. First we'll unpack these concepts, then we'll dive into the code.
4
+
5
+ ## Block Headers and Merkle Proofs
6
+
7
+ In Bitcoin, miners create blocks. These blocks comprise merkle trees of the included transactions. The root of the merkle tree, together with other useful information, is collected together into a block header that can be used to verify the block's proof-of-work. This merkle tree structure enables anyone to keep track of the chain of block headers without keeping a copy of every Bitcoin transaction.
8
+
9
+ Merkle proofs are simply a way for someone to prove the existence of a given transaction within a given merkle tree, and by extension, its inclusion by the miners in a particular block of the blockchain. This becomes extremely important and useful when we think about Simplified Payment Verification (SPV).
10
+
11
+ ## Simplified Payment Verification (SPV)
12
+
13
+ The process for SPV is detailed in [BRC-67](https://github.com/bitcoin-sv/BRCs/blob/master/transactions/0067.md), but the main idea is that when a sender sends a transaction, they include merkle proofs on all of the input transactions. This allows anyone with a copy of the Bitcoin block headers to check that the input transactions are included in the blockchain. Verifiers then check that all the input and output scripts correctly transfer value from one party to the next, ensuring an unbroken chain of spends. The [BEEF data structure](https://github.com/bitcoin-sv/BRCs/blob/master/transactions/0062.md) provides a compact and efficient way for people to represent the data required to perform SPV.
14
+
15
+ ## Block Headers Client
16
+
17
+ To verify BEEF structures with the BSV SDK, you'll need to provide a block headers client that, given a merkle root, will indicate to the library whether the merkle root is correct for the block that's in the active chain at the given block height.
18
+
19
+ For simplicity in this example, we are going to use a mock headers client that always indicates every merkle root as valid no matter what. However, in any real project, **you MUST always use an actual block headers client or attackers will be able to easily fool you with fraudulent transactions!**
20
+
21
+ The TypeScript BSV SDK does not ship with a block headers client, but check out this example (link to be provided once complete) for setting up Pulse.
22
+
23
+ Here is the gullible block headers client we will be using:
24
+
25
+ ```typescript
26
+ const gullibleHeadersClient = {
27
+ // DO NOT USE IN A REAL PROJECT due to security risks of accepting any merkle root as valid without verification
28
+ isValidRootForHeight: async (merkleRoot, height) => {
29
+ console.log({ merkleRoot, height })
30
+ return true
31
+ }
32
+ }
33
+ ```
34
+
35
+ ## Verifying a BEEF Structure
36
+
37
+ Now that you have access to a block headers client (either Pulse on a real project or the above code for a toy example), we can proceed to verifying the BEEF structure with the following code:
38
+
39
+ ```typescript
40
+ import { Transaction } from '@bsv/sdk'
41
+
42
+ // Replace with the BEEF structure you'd like to check
43
+ const BEEFHex = '0100beef01fe636d0c0007021400fe507c0c7aa754cef1f7889d5fd395cf1f785dd7de98eed895dbedfe4e5bc70d1502ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e010b00bc4ff395efd11719b277694cface5aa50d085a0bb81f613f70313acd28cf4557010400574b2d9142b8d28b61d88e3b2c3f44d858411356b49a28a4643b6d1a6a092a5201030051a05fc84d531b5d250c23f4f886f6812f9fe3f402d61607f977b4ecd2701c19010000fd781529d58fc2523cf396a7f25440b409857e7e221766c57214b1d38c7b481f01010062f542f45ea3660f86c013ced80534cb5fd4c19d66c56e7e8c5d4bf2d40acc5e010100b121e91836fd7cd5102b654e9f72f3cf6fdbfd0b161c53a9c54b12c841126331020100000001cd4e4cac3c7b56920d1e7655e7e260d31f29d9a388d04910f1bbd72304a79029010000006b483045022100e75279a205a547c445719420aa3138bf14743e3f42618e5f86a19bde14bb95f7022064777d34776b05d816daf1699493fcdf2ef5a5ab1ad710d9c97bfb5b8f7cef3641210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013e660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000001000100000001ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e000000006a47304402203a61a2e931612b4bda08d541cfb980885173b8dcf64a3471238ae7abcd368d6402204cbf24f04b9aa2256d8901f0ed97866603d2be8324c2bfb7a37bf8fc90edd5b441210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013c660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000000'
44
+
45
+ // You can create a Transaction from BEEF hex directly
46
+ const tx = Transaction.fromHexBEEF(BEEFHex)
47
+
48
+ // This ensures the BEEF structure is legitimate
49
+ const verified = await tx.verify(gullibleHeadersClient)
50
+
51
+ // Print the results
52
+ console.log(verified)
53
+ ```
54
+
55
+ The above code allows you to ensure that a given BEEF structure is valid according to the rules of SPV.
@@ -0,0 +1,69 @@
1
+ # Example: Verifying Spends with Script Intrepreter
2
+
3
+ The SDK comes with a script interpreter that allows you to verify the chain of spends within Bitcoin. When coins are spent from one transaction to another, the process is carried out between a particular output of the source transaction and a particular input of the spending transaction. The `Spend` class sets up the necessary contextual information for this process, and then evaluates the scripts to determine if the transfer is legitimate.
4
+
5
+ This guide will walk you through the verification of a real spend, with real data. You can apply this code to your own transactions to ensure the transfer of coins from one state into the next is legitimate.
6
+
7
+ ## Pre-requisites
8
+
9
+ We will need two transactions: a source transaction and a spending transaction, in order to set up the `Spend` context in which the transfer of coins occurs between them. When you construct an instance of the `Spend` class, you'll need to provide this information in the correct format. In a new file, let's set up som basic things we'll need:
10
+
11
+ ```typescript
12
+ import { Spend, LockingScript, UnlockingScript } from '@bsv/sdk'
13
+
14
+ const spend = new Spend({
15
+
16
+ // Replace with the TXID of the transaction where you are spending from
17
+ sourceTXID: '0000000000000000000000000000000000000000000000000000000000000000',
18
+
19
+ // Replace with the output index you are redeeming
20
+ sourceOutputIndex: 0,
21
+
22
+ // Replace with the number of satoshis in the output you are redeeming
23
+ sourceSatoshis: 1,
24
+
25
+ // Replace with the locking script you are spending
26
+ lockingScript: LockingScript.fromASM('OP_3 OP_ADD OP_7 OP_EQUAL'),
27
+
28
+ // Replace with the version of the new spending transaction
29
+ transactionVersion: 1,
30
+
31
+ // Other inputs from the spending transaction that are needed for verification.
32
+ // The SIGHASH flags used in signatures may not require this (if SIGHASH_ANYONECANPAY was used).
33
+ // This is an ordered array of TransactionInputs with the input whose script we're currently evaluating missing.
34
+ otherInputs: [],
35
+
36
+ // TransactionOutputs from the spending transaction that are needed for verification.
37
+ // The SIGHASH flags used in signatures may nnt require this (if SIGHASH_NONE was used).
38
+ // If SIGHASH_SINGLE is used, it's possible for this to be a sparse array, with only the index corresponding to
39
+ // the inputIndex populated.
40
+ outputs: [],
41
+
42
+ // This is the index of the input whose script we are currently evaluating.
43
+ inputIndex: 0,
44
+
45
+ // This is the unlocking script that we are evaluating, to see if it unlocks the source output.
46
+ unlockingScript: UnlockingScript.fromASM('OP_4'),
47
+
48
+ // This is the sequence number of the input whose script we are currently evaluating.
49
+ inputSequence: 0xffffffff,
50
+
51
+ // This is the lock time of the spending transaction.
52
+ lockTime: 0
53
+ })
54
+ ```
55
+
56
+ Once you've provided the context and constructed the Spend, you should have a new spend instance ready for verification.
57
+
58
+ ## Validating the Spend
59
+
60
+ You can use the `validate()` method to run the scripts and validate the spend, as follows:
61
+
62
+ ```typescript
63
+ const validated = spend.validate()
64
+ // console.log(validated) => true
65
+ ```
66
+
67
+ The result will be a boolean indicating the result of the script. If there is an error thrown, or if the boolean is false, the script is not valid. If the boolean is true, the spend is considered valid.
68
+
69
+ Errors from the spend will contain useful information, such as the specific opcode and context in which the error occurred (in either the locking or unlocking script).
@@ -0,0 +1,73 @@
1
+ # Getting Started with BSV SDK in NodeJS (CommonJS)
2
+
3
+ Welcome to the BSV SDK! This guide is tailored for developers working in a NodeJS environment, specifically those who are using the CommonJS module system. We'll walk you through the installation process and show you how to get started with creating and signing a Bitcoin SV transaction using the SDK. Whether you're building on BSV for the first time or transitioning an existing project to use the SDK, this guide is for you.
4
+
5
+ ## Prerequisites
6
+
7
+ Before we begin, make sure you have Node.js installed on your system. You can download and install Node.js from [nodejs.org](https://nodejs.org/). This guide assumes you have basic knowledge of JavaScript and the Node.js environment.
8
+
9
+ ## Installation
10
+
11
+ First, you'll need to install the BSV SDK package in your project. Open your terminal, navigate to your project directory, and run the following command:
12
+
13
+ ```bash
14
+ npm install @bsv/sdk
15
+ ```
16
+
17
+ This command installs the BSV SDK in your project, making it ready for use. There are no external runtime dependencies.
18
+
19
+ ## Requiring the SDK
20
+
21
+ To use the BSV SDK in a NodeJS project with CommonJS, you'll import modules using the `require` syntax. Here's how you set up a basic script to use the BSV SDK:
22
+
23
+ 1. Create a new JavaScript file in your project. For example, `index.js`.
24
+ 2. At the top of your file, require the SDK modules you plan to use. For instance:
25
+
26
+ ```javascript
27
+ const { PrivateKey, P2PKH, Transaction, ARC } = require('@bsv/sdk');
28
+ ```
29
+
30
+ ## Creating and Signing a Transaction
31
+
32
+ Now, let's create and sign a transaction. We'll follow the example provided in the README. This example demonstrates how to create a transaction from a source to a recipient, including calculating fees, signing the transaction, and broadcasting it to ARC.
33
+
34
+ Copy and paste the following code into your `index.js` file below your `require` statement:
35
+
36
+ ```javascript
37
+ const privKey = PrivateKey.fromWif('...')
38
+
39
+ const sourceTransaction = Transaction.fromHex('...')
40
+
41
+ const version = 1
42
+ const input = {
43
+ sourceTransaction,
44
+ sourceOutputIndex: 0,
45
+ unlockingScriptTemplate: new P2PKH().unlock(privKey),
46
+ }
47
+ const output = {
48
+ lockingScript: new P2PKH().lock(privKey.toPublicKey().toHash()),
49
+ change: true
50
+ }
51
+
52
+ const tx = new Transaction(version, [input], [output])
53
+ await tx.fee()
54
+ await tx.sign()
55
+
56
+ // get your api key from https://console.taal.com
57
+ const apiKey = 'mainnet_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' // replace
58
+ await tx.broadcast(new ARC('https://api.taal.com/arc', apiKey))
59
+ ```
60
+
61
+ This script demonstrates the entire process of creating a transaction, from initializing keys to signing and broadcast. When you run this script using Node.js (replacing the source transaction, private key, and ARC credentials), the spend will be signed and broadcast to the BSV network.
62
+
63
+ ## Running Your Script
64
+
65
+ To run your script, simply execute the following command in your terminal:
66
+
67
+ ```bash
68
+ node index.js
69
+ ```
70
+
71
+ ## Conclusion
72
+
73
+ Congratulations! You've successfully installed the BSV SDK in your NodeJS project and created a signed transaction. This guide covered the basics to get you started, but the BSV SDK is capable of much more. Explore the SDK documentation for detailed information on all the features and functionalities available to build scalable applications with the BSV blockchain.
@@ -0,0 +1,121 @@
1
+ Getting Started with BSV SDK using React and TypeScript
2
+ =======================================================
3
+
4
+ Welcome to the guide! This guide is designed for developers working in a React environment using TypeScript. We'll walk through the installation process and show you how to create and broadcast a Bitcoin SV transaction using the BSV SDK. Whether you're freshly starting on BSV or transitioning an existing project to use the SDK, this would be your go-to guide.
5
+
6
+ Prerequisites
7
+ -------------
8
+
9
+ Ensure that you have Node.js installed on your system. You can download and install Node.js from [nodejs.org](https://nodejs.org/). Basic knowledge of JavaScript, React and TypeScript is recommended for this guide.
10
+
11
+ Setting Up
12
+ ----------
13
+
14
+ Begin by creating a new project using Create React App with the TypeScript template:
15
+
16
+ ```bash
17
+ npx create-react-app my-bsv-app --template typescript
18
+ cd my-bsv-app
19
+ ```
20
+
21
+ Next, install the BSV SDK package in your project:
22
+
23
+ ```bash
24
+ npm install @bsv/sdk
25
+ ```
26
+
27
+ Writing the Component
28
+ ---------------------
29
+
30
+ Let's now create a Button component that builds and broadcasts a transaction when clicked.
31
+
32
+ 1. Create a new file in your project, such as `src/components/BsvButton.tsx`.
33
+ 2. At the top of your component file, import the necessary modules from the BSV SDK:
34
+
35
+ ```
36
+ import React from 'react';
37
+ import { PrivateKey, Transaction, ARC, P2PKH } from '@bsv/sdk';
38
+ ```
39
+
40
+ 3. Define a new component function, `BsvButton`, that handles the creation and broadcast of a transaction upon a button click:
41
+
42
+ ```typescript
43
+ const BsvButton: React.FC = () => {
44
+ const handleClick = async () => {
45
+ const privKey = PrivateKey.fromWif('...')
46
+ const sourceTransaction = Transaction.fromHex('...') // your source transaction goes here
47
+
48
+ const version = 1
49
+ const input = {
50
+ sourceTransaction,
51
+ sourceOutputIndex: 0,
52
+ unlockingScriptTemplate: new P2PKH().unlock(privKey),
53
+ }
54
+ const output = {
55
+ lockingScript: new P2PKH().lock(privKey.toPublicKey().toHash()),
56
+ change: true
57
+ }
58
+
59
+ const tx = new Transaction(version, [input], [output])
60
+ await tx.fee()
61
+ await tx.sign()
62
+
63
+ // grab your api key from https://console.taal.com
64
+ const apiKey = 'mainnet_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' // replace
65
+ await tx.broadcast(new ARC('https://api.taal.com/arc', apiKey))
66
+ }
67
+
68
+ return (
69
+ <button onClick={handleClick}>
70
+ Create Transaction
71
+ </button>
72
+ );
73
+ }
74
+ ```
75
+
76
+ 4. Finally, export the `BsvButton` component:
77
+
78
+ ```typescript
79
+ export default BsvButton;
80
+ ```
81
+
82
+ Integrating into Application
83
+ ----------------------------
84
+
85
+ Now, let's integrate our `BsvButton` component into our app:
86
+
87
+ 1. Open `src/App.tsx`.
88
+ 2. Delete all of its content and replace it with the following:
89
+
90
+ ```typescript
91
+ import React from 'react';
92
+ import BsvButton from './components/BsvButton';
93
+
94
+ function App() {
95
+ return (
96
+ <div className="App">
97
+ <header className="App-header">
98
+ <BsvButton />
99
+ </header>
100
+ </div>
101
+ );
102
+ }
103
+
104
+ export default App;
105
+ ```
106
+
107
+ Running the App
108
+ ---------------
109
+
110
+ To run your application, just type the following command in your terminal:
111
+
112
+ ```bash
113
+ npm run start
114
+ ```
115
+
116
+ Now when you click the button, a transaction will be created, signed, and broadcast to the BSV network.
117
+
118
+ Conclusion
119
+ ----------
120
+
121
+ Congratulations! You've successfully integrated the BSV SDK into your TypeScript & React application and created a button which broadcasts a bitcoin transaction on click. This guide covered the basic steps needed to get you started, but the BSV SDK can do a lot more. Explore the SDK documentation to dive deep into all the features and functionalities available to build scalable applications on the BSV blockchain.