@bsv/sdk 1.1.1 → 1.1.3
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/dist/cjs/package.json +1 -1
- package/dist/cjs/src/transaction/MerklePath.js +2 -1
- package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/transaction/MerklePath.js +2 -1
- package/dist/esm/src/transaction/MerklePath.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/transaction/MerklePath.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/transaction/MerklePath.ts +2 -1
- package/src/transaction/__tests/Transaction.test.ts +2 -2
- package/docs/concepts/42.md +0 -35
- package/docs/concepts/BEEF.md +0 -38
- package/docs/concepts/CHAIN_SPV.md +0 -38
- package/docs/concepts/FEE.md +0 -35
- package/docs/concepts/HASHES.md +0 -19
- package/docs/concepts/HOW_TX.md +0 -60
- package/docs/concepts/OP.md +0 -38
- package/docs/concepts/README.md +0 -14
- package/docs/concepts/TEMPLATES.md +0 -42
- package/docs/concepts/TX_SIG.md +0 -34
- package/docs/concepts/TX_VALID.md +0 -35
- package/docs/examples/EXAMPLE_BUILDING_CUSTOM_TX_BROADCASTER.md +0 -91
- package/docs/examples/EXAMPLE_COMPLEX_TX.md +0 -162
- package/docs/examples/EXAMPLE_ECIES.md +0 -37
- package/docs/examples/EXAMPLE_ENCRYPT_DECRYPT_MESSAGE.md +0 -52
- package/docs/examples/EXAMPLE_FEE_MODELING.md +0 -199
- package/docs/examples/EXAMPLE_HD_WALLETS.md +0 -71
- package/docs/examples/EXAMPLE_MESSAGE_SIGNING.md +0 -63
- package/docs/examples/EXAMPLE_SCRIPT_TEMPLATES.md +0 -170
- package/docs/examples/EXAMPLE_SIMPLE_TX.md +0 -145
- package/docs/examples/EXAMPLE_TYPE_42.md +0 -108
- package/docs/examples/EXAMPLE_UTXOS_TX.md +0 -85
- package/docs/examples/EXAMPLE_VERIFYING_BEEF.md +0 -62
- package/docs/examples/EXAMPLE_VERIFYING_ROOTS.md +0 -97
- package/docs/examples/EXAMPLE_VERIFYING_SPENDS.md +0 -69
- package/docs/examples/GETTING_STARTED_NODE_CJS.md +0 -71
- package/docs/examples/GETTING_STARTED_REACT.md +0 -119
- package/docs/examples/README.md +0 -19
- package/docs/low-level/AES_SYMMETRIC_ENCRYPTION.md +0 -40
- package/docs/low-level/ECDH.md +0 -64
- package/docs/low-level/NUMBERS_POINTS.md +0 -116
- package/docs/low-level/README.md +0 -13
- package/docs/low-level/TX_SIG.md +0 -132
- package/docs/low-level/TYPE_42.md +0 -53
- package/docs/low-level/USING_ECDSA.md +0 -30
- package/docs/low-level/USING_HASHES_AND_HMACS.md +0 -79
- package/docs/low-level/USING_PRIVATE_PUBLIC_KEYS.md +0 -70
- package/docs/low-level/USING_SCRIPTS.md +0 -71
- package/docs/low-level/images/symmetric_encryption_diagram.png +0 -0
|
@@ -1,108 +0,0 @@
|
|
|
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.
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# Example: Creating a Transaction from UTXOs
|
|
2
|
-
|
|
3
|
-
This guide shows how to create a transaction from UTXOs fetched from WhatsOnChain.
|
|
4
|
-
It also shows how to set a fixed fee and build OP_RETURN outputs.
|
|
5
|
-
|
|
6
|
-
## The UTXOs format
|
|
7
|
-
|
|
8
|
-
Although its not a standard, UTXOs can be fetched from apis like [WhatsOnChain](https://whatsonchain.com/) in a similar format.
|
|
9
|
-
|
|
10
|
-
```typescript
|
|
11
|
-
/** Utxos from whatsonchain api*/
|
|
12
|
-
const utxos = [
|
|
13
|
-
{
|
|
14
|
-
height: 1600000,
|
|
15
|
-
tx_pos: 0,
|
|
16
|
-
tx_hash: '672dd6a93fa5d7ba6794e0bdf8b479440b95a55ec10ad3d9e03585ecb5628d8f',
|
|
17
|
-
value: 10000
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
height: 1600000,
|
|
21
|
-
tx_pos: 0,
|
|
22
|
-
tx_hash: 'f33505acf37a7726cc37d391bc6f889b8684ac2a2d581c4be2a4b1c8b46609bb',
|
|
23
|
-
value: 10000
|
|
24
|
-
},
|
|
25
|
-
]
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Building a transaction from UTXOs
|
|
29
|
-
|
|
30
|
-
The first step is to build a transaction and add inputs from the utxos related to the private key `priv`.
|
|
31
|
-
|
|
32
|
-
```typescript
|
|
33
|
-
import { Transaction, PrivateKey, P2PKH, LockingScript, Utils, OP } from '@bsv/sdk'
|
|
34
|
-
|
|
35
|
-
const priv = PrivateKey.fromWif('...')
|
|
36
|
-
const tx = new Transaction()
|
|
37
|
-
|
|
38
|
-
utxos.forEach(utxo => {
|
|
39
|
-
const script = new P2PKH().lock(priv.toPublicKey().toHash())
|
|
40
|
-
tx.addInput({
|
|
41
|
-
sourceTXID: utxo.tx_hash,
|
|
42
|
-
sourceOutputIndex: utxo.tx_pos,
|
|
43
|
-
sourceSatoshis: utxo.value,
|
|
44
|
-
unlockingScriptTemplate: new P2PKH()
|
|
45
|
-
.unlock(priv, 'all', false, utxo.value, script)
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Adding the outputs
|
|
51
|
-
|
|
52
|
-
Next an OP_RETURN output script is added along with a change address to the original `priv`, note that addresses should not be reused as its not a good practice.
|
|
53
|
-
|
|
54
|
-
```typescript
|
|
55
|
-
const data = Utils.toArray('some data')
|
|
56
|
-
const script = [
|
|
57
|
-
{ op: OP.OP_FALSE },
|
|
58
|
-
{ op: OP.OP_RETURN },
|
|
59
|
-
{ op: data.length, data }
|
|
60
|
-
]
|
|
61
|
-
|
|
62
|
-
// Add the new OP_RETURN script as output
|
|
63
|
-
tx.addOutput({
|
|
64
|
-
lockingScript: new LockingScript(script),
|
|
65
|
-
satoshis: 0
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
// Add a change output to the used private key
|
|
69
|
-
tx.addOutput({
|
|
70
|
-
lockingScript: new P2PKH().lock(priv.toAddress()),
|
|
71
|
-
change: true
|
|
72
|
-
})
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Finalize the transaction
|
|
76
|
-
|
|
77
|
-
Last step is to set the transaction fee, sign the transaction and broadcast it.
|
|
78
|
-
|
|
79
|
-
```typescript
|
|
80
|
-
await tx.fee(10) // a fixed fee of 10 sats is used
|
|
81
|
-
await tx.sign()
|
|
82
|
-
await tx.broadcast()
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
That concludes this basic example but common practice to create a transaction from UTXOs. Refer to other examples for instructions on how to calculate fees from transaction size, use different locking script templates, different broadcast services and more.
|
|
@@ -1,62 +0,0 @@
|
|
|
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
|
-
## Verifying a BEEF Structure
|
|
16
|
-
|
|
17
|
-
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:
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
import { Transaction } from '@bsv/sdk'
|
|
21
|
-
|
|
22
|
-
// Replace with the BEEF structure you'd like to check
|
|
23
|
-
const BEEFHex = '0100beef01fe636d0c0007021400fe507c0c7aa754cef1f7889d5fd395cf1f785dd7de98eed895dbedfe4e5bc70d1502ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e010b00bc4ff395efd11719b277694cface5aa50d085a0bb81f613f70313acd28cf4557010400574b2d9142b8d28b61d88e3b2c3f44d858411356b49a28a4643b6d1a6a092a5201030051a05fc84d531b5d250c23f4f886f6812f9fe3f402d61607f977b4ecd2701c19010000fd781529d58fc2523cf396a7f25440b409857e7e221766c57214b1d38c7b481f01010062f542f45ea3660f86c013ced80534cb5fd4c19d66c56e7e8c5d4bf2d40acc5e010100b121e91836fd7cd5102b654e9f72f3cf6fdbfd0b161c53a9c54b12c841126331020100000001cd4e4cac3c7b56920d1e7655e7e260d31f29d9a388d04910f1bbd72304a79029010000006b483045022100e75279a205a547c445719420aa3138bf14743e3f42618e5f86a19bde14bb95f7022064777d34776b05d816daf1699493fcdf2ef5a5ab1ad710d9c97bfb5b8f7cef3641210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013e660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000001000100000001ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e000000006a47304402203a61a2e931612b4bda08d541cfb980885173b8dcf64a3471238ae7abcd368d6402204cbf24f04b9aa2256d8901f0ed97866603d2be8324c2bfb7a37bf8fc90edd5b441210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013c660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000000'
|
|
24
|
-
|
|
25
|
-
// You can create a Transaction from BEEF hex directly
|
|
26
|
-
const tx = Transaction.fromHexBEEF(BEEFHex)
|
|
27
|
-
|
|
28
|
-
// This ensures the BEEF structure is legitimate
|
|
29
|
-
const verified = await tx.verify()
|
|
30
|
-
|
|
31
|
-
// Print the results
|
|
32
|
-
console.log(verified)
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
The above code allows you to ensure that a given BEEF structure is valid according to the rules of SPV.
|
|
36
|
-
|
|
37
|
-
## Chain tracker
|
|
38
|
-
|
|
39
|
-
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.
|
|
40
|
-
|
|
41
|
-
The TypeScript BSV SDK does provides default implementation of the chain tracker that use What's On Chain API.
|
|
42
|
-
|
|
43
|
-
### What's On Chain configuration
|
|
44
|
-
|
|
45
|
-
#### BSV network
|
|
46
|
-
|
|
47
|
-
The default network for the chain tracker is `main`. You can change it to other network by providing the instance of WhatsOnChain ChainTracker configured for other network to `.verify()` method.
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
tx.verify(new WhatsOnChain())
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
#### Api Key
|
|
54
|
-
|
|
55
|
-
It is possible to use WhatsOnChain ChainTracker with obtained API KEY of [WhatsOnChain](https://docs.taal.com/core-products/whatsonchain).
|
|
56
|
-
To do so, you need to provide to `.verify()` method the custom instance of WhatsOnChain ChainTracker with the API KEY.
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
import { Transaction, WhatsOnChain } from '@bsv/sdk'
|
|
60
|
-
|
|
61
|
-
tx.verify(new WhatsOnChain('main', {apiKey: 'YOUR_API_KEY'}))
|
|
62
|
-
```
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# Example: Building a Pulse Block Headers Client
|
|
2
|
-
|
|
3
|
-
When [verifying BEEF structures](EXAMPLE_VERIFYING_BEEF.md), it's necessary to ensure that all transactions are well-anchored: this is to say, that they come from inputs in the honest chain. The SDK doesn't ship with a headers client, but this guide shows an example of how to use it with [block-headers-service](https://github.com/bitcoin-sv/block-headers-service): a popular client suitable for a wide range of use-cases.
|
|
4
|
-
|
|
5
|
-
## Pre-requisites
|
|
6
|
-
|
|
7
|
-
As stated in the README, you will need to be running a Pulse instance. Get it up and running, and configure a level of authentication appropriate for your use-case:
|
|
8
|
-
|
|
9
|
-
```sh
|
|
10
|
-
docker pull bsvb/block-headers-service
|
|
11
|
-
docker run bsvb/block-headers-service:latest
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## Building our Client
|
|
15
|
-
|
|
16
|
-
The SDK's `ChainTracker` interface defines the required structure for our implementation, as follows:
|
|
17
|
-
|
|
18
|
-
```typescript
|
|
19
|
-
/**
|
|
20
|
-
* The Chain Tracker is responsible for verifying the validity of a given Merkle root
|
|
21
|
-
* for a specific block height within the blockchain.
|
|
22
|
-
*
|
|
23
|
-
* Chain Trackers ensure the integrity of the blockchain by
|
|
24
|
-
* validating new headers against the chain's history. They use accumulated
|
|
25
|
-
* proof-of-work and protocol adherence as metrics to assess the legitimacy of blocks.
|
|
26
|
-
*
|
|
27
|
-
* @interface ChainTracker
|
|
28
|
-
* @function isValidRootForHeight - A method to verify the validity of a Merkle root
|
|
29
|
-
* for a given block height.
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* const chainTracker = {
|
|
33
|
-
* isValidRootForHeight: async (root, height) => {
|
|
34
|
-
* // Implementation to check if the Merkle root is valid for the specified block height.
|
|
35
|
-
* }
|
|
36
|
-
* };
|
|
37
|
-
*/
|
|
38
|
-
export default interface ChainTracker {
|
|
39
|
-
isValidRootForHeight: (root: string, height: number) => Promise<boolean>
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Given an array of merkle roots and corresponding block heights, we return a boolean indicating whether they're all valid.
|
|
45
|
-
|
|
46
|
-
We can plug in the Block Header Service API with appropriate HTTP handling logic as follows:
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
import {defaultHttpClient} from "@bsv/sdk";
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Represents a Block Headers Client.
|
|
53
|
-
*/
|
|
54
|
-
export default class BlockHeadersClient implements ChainTracker {
|
|
55
|
-
URL: string
|
|
56
|
-
apiKey: string
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Constructs an instance of the Pulse chain tracker.
|
|
60
|
-
*
|
|
61
|
-
* @param {string} URL - The URL endpoint for the Pulse API.
|
|
62
|
-
* @param {string} apiKey - The API key used for authorization with the Pulse API.
|
|
63
|
-
*/
|
|
64
|
-
constructor(URL: string, apiKey: string) {
|
|
65
|
-
this.URL = URL
|
|
66
|
-
this.apiKey = apiKey
|
|
67
|
-
this.httpClient = defaultHttpClient()
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Checks a set of merkle roots with corresponding heights.
|
|
72
|
-
*
|
|
73
|
-
* @param root: string - The merkle root to check
|
|
74
|
-
* @param height: number - The corresponding height
|
|
75
|
-
* @returns {Promise<boolean>} A promise that resolves to either a success or failure response (true or false).
|
|
76
|
-
*/
|
|
77
|
-
async isValidRootForHeight(root: string, height: number): Promise<boolean> {
|
|
78
|
-
const response = await httpsClient(`${this.URL}/api/v1/chain/merkleroot/verify`, {
|
|
79
|
-
method: 'POST',
|
|
80
|
-
body: [{merkleRoot: root, blockHeight: height}],
|
|
81
|
-
headers: {
|
|
82
|
-
'Content-Type': 'application/json',
|
|
83
|
-
Authorization: `Bearer ${this.apiKey}`
|
|
84
|
-
}
|
|
85
|
-
})
|
|
86
|
-
if (response.ok) {
|
|
87
|
-
return response.data?.confirmationState === 'CONFIRMED'
|
|
88
|
-
} else {
|
|
89
|
-
throw new Error(`Failed to verify root at height ${height} with response ${response.status}`)
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Now, we can use our `BlockHeadersClient` as a `ChainTracker` when calling the `Transaction` object's `.verify()` method. You can see an example in the [BEEF verification guide](EXAMPLE_VERIFYING_BEEF.md).
|
|
96
|
-
|
|
97
|
-
This provides the ability to ensure that a transaction is well-anchored.
|
|
@@ -1,69 +0,0 @@
|
|
|
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).
|
|
@@ -1,71 +0,0 @@
|
|
|
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
|
-
await tx.broadcast()
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
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.
|
|
60
|
-
|
|
61
|
-
## Running Your Script
|
|
62
|
-
|
|
63
|
-
To run your script, simply execute the following command in your terminal:
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
node index.js
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Conclusion
|
|
70
|
-
|
|
71
|
-
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.
|
|
@@ -1,119 +0,0 @@
|
|
|
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
|
-
await tx.broadcast()
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return (
|
|
67
|
-
<button onClick={handleClick}>
|
|
68
|
-
Create Transaction
|
|
69
|
-
</button>
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
4. Finally, export the `BsvButton` component:
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
export default BsvButton;
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Integrating into Application
|
|
81
|
-
----------------------------
|
|
82
|
-
|
|
83
|
-
Now, let's integrate our `BsvButton` component into our app:
|
|
84
|
-
|
|
85
|
-
1. Open `src/App.tsx`.
|
|
86
|
-
2. Delete all of its content and replace it with the following:
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
import React from 'react';
|
|
90
|
-
import BsvButton from './components/BsvButton';
|
|
91
|
-
|
|
92
|
-
function App() {
|
|
93
|
-
return (
|
|
94
|
-
<div className="App">
|
|
95
|
-
<header className="App-header">
|
|
96
|
-
<BsvButton />
|
|
97
|
-
</header>
|
|
98
|
-
</div>
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export default App;
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Running the App
|
|
106
|
-
---------------
|
|
107
|
-
|
|
108
|
-
To run your application, just type the following command in your terminal:
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
npm run start
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Now when you click the button, a transaction will be created, signed, and broadcast to the BSV network.
|
|
115
|
-
|
|
116
|
-
Conclusion
|
|
117
|
-
----------
|
|
118
|
-
|
|
119
|
-
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.
|
package/docs/examples/README.md
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# Examples
|
|
2
|
-
|
|
3
|
-
Here, you will find documentation for common example usages of the library.
|
|
4
|
-
|
|
5
|
-
- [Getting Started (Node, CommonJS)](./GETTING_STARTED_NODE_CJS.md)
|
|
6
|
-
- [Getting Started (React)](./GETTING_STARTED_REACT.md)
|
|
7
|
-
- [Example: Creating a Simple Transaction](EXAMPLE_SIMPLE_TX.md)
|
|
8
|
-
- [Example: Verifying a BEEF Structure](EXAMPLE_VERIFYING_BEEF.md)
|
|
9
|
-
- [Example: Creating Transactions with Inputs, Outputs and Templates](EXAMPLE_COMPLEX_TX.md)
|
|
10
|
-
- [Example: Creating the R-puzzle Script Template](EXAMPLE_SCRIPT_TEMPLATES.md)
|
|
11
|
-
- [Example: Message Encryption and Decryption](EXAMPLE_ENCRYPT_DECRYPT_MESSAGE.md)
|
|
12
|
-
- [Example: Message Signing](EXAMPLE_MESSAGE_SIGNING.md)
|
|
13
|
-
- [Example: Building a Custom Transaction Broadcast Client](EXAMPLE_BUILDING_CUSTOM_TX_BROADCASTER.md)
|
|
14
|
-
- [Example: Verifying Spends with Script Intrepreter](EXAMPLE_VERIFYING_SPENDS.md)
|
|
15
|
-
- [Example: BIP32 Key Derivation with HD Wallets](EXAMPLE_HD_WALLETS.md)
|
|
16
|
-
- [Example: Using Type 42 Key Derivation for Bitcoin Wallet Management](EXAMPLE_TYPE_42.md)
|
|
17
|
-
- [Example: Creating a Custom Transaction Fee Model](EXAMPLE_FEE_MODELING.md)
|
|
18
|
-
- [Example: Building a Pulse Block Headers Client](EXAMPLE_PULSE_HEADERS.md)
|
|
19
|
-
- [Example: Using ECIES Encryption](EXAMPLE_ECIES.md)
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# Using AES for the Symmetric Encryption of Data
|
|
2
|
-
|
|
3
|
-
The goal of this tutorial is to explore the encryption of data using symmetric keys with the Advanced Encryption Standard (AES). We will make use of the functions provided by the SDK in order to encrypt data with a key, and then decrypt it again.
|
|
4
|
-
|
|
5
|
-
<img src="./images/symmetric_encryption_diagram.png" width="600" alt=""/>
|
|
6
|
-
|
|
7
|
-
If you would like to learn more about AES encryption, here are some general resources that may help:
|
|
8
|
-
|
|
9
|
-
- [AES - Wiki](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard)
|
|
10
|
-
- [GCM - Wiki](https://en.wikipedia.org/wiki/Galois/Counter_Mode)
|
|
11
|
-
|
|
12
|
-
The library supports GCM, a specific counter mode of AES that works well in many applications. The library also handles initialization vectors, automatically prepending them to ciphertext and removing them in the decryption process. Now that you know the basics, let's get started!
|
|
13
|
-
|
|
14
|
-
## Getting Started
|
|
15
|
-
|
|
16
|
-
First, let's import the `SymmetricKey` class from the SDK, and we'll also use `Utils` for human-readable messages.
|
|
17
|
-
|
|
18
|
-
```ts
|
|
19
|
-
import { SymmetricKey, Utils } from '@bsv/sdk'
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Next, we wil define the keys to be used and the data to encrypt. They `.encrypt()` method expects a parameter of type `number[]` so we will use the Utils `toArray` function to convert the UTF8 message to the correct type.
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
const symmetricKey = SymmetricKey.fromRandom()
|
|
26
|
-
const messageToEncrypt = 'Hello Alice, this is Bob!'
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### Encrypting and Decrypting
|
|
30
|
-
|
|
31
|
-
When you encrypt a message, an initialization vector is prepended to the message to prevent potential key re-use attacks. Conversely, when decrypting, the initialization vector that was initially added is spliced out and used in the AES-GSM decryption processes.
|
|
32
|
-
|
|
33
|
-
We will use the `encrypt` and `decrypt` methods of the SymmetricKey class to transform the message.
|
|
34
|
-
|
|
35
|
-
```ts
|
|
36
|
-
const encryptedMessage = SymmetricKey.encrypt(messageToEncrypt)
|
|
37
|
-
const plaintext = SymmetricKey.decrypt(encryptedMessage, 'utf8')
|
|
38
|
-
// console.log(plaintext) --> 'Hello Alice, this is Bob!'
|
|
39
|
-
|
|
40
|
-
This is just a basic demonstration of symmetric encryption/decryption using the BSV SDK, however the possibilities of what you can do are endless once you understand these fundamentals.
|