@bsv/sdk 1.0.32 → 1.0.34
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 +1 -3
- package/dist/cjs/mod.js +1 -0
- package/dist/cjs/mod.js.map +1 -1
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/primitives/PublicKey.js +36 -0
- package/dist/cjs/src/primitives/PublicKey.js.map +1 -1
- package/dist/cjs/src/primitives/Signature.js +6 -6
- package/dist/cjs/src/primitives/Signature.js.map +1 -1
- package/dist/cjs/src/script/Script.js.map +1 -1
- package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
- package/dist/cjs/src/transaction/Transaction.js +5 -3
- package/dist/cjs/src/transaction/Transaction.js.map +1 -1
- package/dist/cjs/src/transaction/broadcasters/ARC.js +39 -57
- package/dist/cjs/src/transaction/broadcasters/ARC.js.map +1 -1
- package/dist/cjs/src/transaction/broadcasters/DefaultBroadcaster.js +12 -0
- package/dist/cjs/src/transaction/broadcasters/DefaultBroadcaster.js.map +1 -0
- package/dist/cjs/src/transaction/broadcasters/WhatsOnChainBroadcaster.js +66 -0
- package/dist/cjs/src/transaction/broadcasters/WhatsOnChainBroadcaster.js.map +1 -0
- package/dist/cjs/src/transaction/broadcasters/index.js +5 -1
- package/dist/cjs/src/transaction/broadcasters/index.js.map +1 -1
- package/dist/cjs/src/transaction/chaintrackers/DefaultChainTracker.js +12 -0
- package/dist/cjs/src/transaction/chaintrackers/DefaultChainTracker.js.map +1 -0
- package/dist/cjs/src/transaction/chaintrackers/WhatsOnChain.js +49 -0
- package/dist/cjs/src/transaction/chaintrackers/WhatsOnChain.js.map +1 -0
- package/dist/cjs/src/transaction/chaintrackers/index.js +11 -0
- package/dist/cjs/src/transaction/chaintrackers/index.js.map +1 -0
- package/dist/cjs/src/transaction/http/DefaultHttpClient.js +37 -0
- package/dist/cjs/src/transaction/http/DefaultHttpClient.js.map +1 -0
- package/dist/cjs/src/transaction/http/FetchHttpClient.js +29 -0
- package/dist/cjs/src/transaction/http/FetchHttpClient.js.map +1 -0
- package/dist/cjs/src/transaction/http/HttpClient.js +3 -0
- package/dist/cjs/src/transaction/http/HttpClient.js.map +1 -0
- package/dist/cjs/src/transaction/http/NodejsHttpClient.js +41 -0
- package/dist/cjs/src/transaction/http/NodejsHttpClient.js.map +1 -0
- package/dist/cjs/src/transaction/http/index.js +10 -0
- package/dist/cjs/src/transaction/http/index.js.map +1 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/mod.js +1 -0
- package/dist/esm/mod.js.map +1 -1
- package/dist/esm/src/primitives/PublicKey.js +36 -0
- package/dist/esm/src/primitives/PublicKey.js.map +1 -1
- package/dist/esm/src/primitives/Signature.js +6 -6
- package/dist/esm/src/primitives/Signature.js.map +1 -1
- package/dist/esm/src/script/Script.js.map +1 -1
- package/dist/esm/src/transaction/MerklePath.js.map +1 -1
- package/dist/esm/src/transaction/Transaction.js +5 -3
- package/dist/esm/src/transaction/Transaction.js.map +1 -1
- package/dist/esm/src/transaction/broadcasters/ARC.js +37 -57
- package/dist/esm/src/transaction/broadcasters/ARC.js.map +1 -1
- package/dist/esm/src/transaction/broadcasters/DefaultBroadcaster.js +5 -0
- package/dist/esm/src/transaction/broadcasters/DefaultBroadcaster.js.map +1 -0
- package/dist/esm/src/transaction/broadcasters/WhatsOnChainBroadcaster.js +65 -0
- package/dist/esm/src/transaction/broadcasters/WhatsOnChainBroadcaster.js.map +1 -0
- package/dist/esm/src/transaction/broadcasters/index.js +2 -0
- package/dist/esm/src/transaction/broadcasters/index.js.map +1 -1
- package/dist/esm/src/transaction/chaintrackers/DefaultChainTracker.js +5 -0
- package/dist/esm/src/transaction/chaintrackers/DefaultChainTracker.js.map +1 -0
- package/dist/esm/src/transaction/chaintrackers/WhatsOnChain.js +50 -0
- package/dist/esm/src/transaction/chaintrackers/WhatsOnChain.js.map +1 -0
- package/dist/esm/src/transaction/chaintrackers/index.js +3 -0
- package/dist/esm/src/transaction/chaintrackers/index.js.map +1 -0
- package/dist/esm/src/transaction/http/DefaultHttpClient.js +33 -0
- package/dist/esm/src/transaction/http/DefaultHttpClient.js.map +1 -0
- package/dist/esm/src/transaction/http/FetchHttpClient.js +26 -0
- package/dist/esm/src/transaction/http/FetchHttpClient.js.map +1 -0
- package/dist/esm/src/transaction/http/HttpClient.js +2 -0
- package/dist/esm/src/transaction/http/HttpClient.js.map +1 -0
- package/dist/esm/src/transaction/http/NodejsHttpClient.js +38 -0
- package/dist/esm/src/transaction/http/NodejsHttpClient.js.map +1 -0
- package/dist/esm/src/transaction/http/index.js +4 -0
- package/dist/esm/src/transaction/http/index.js.map +1 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/mod.d.ts +1 -0
- package/dist/types/mod.d.ts.map +1 -1
- package/dist/types/src/primitives/PublicKey.d.ts +18 -0
- package/dist/types/src/primitives/PublicKey.d.ts.map +1 -1
- package/dist/types/src/primitives/Signature.d.ts +3 -3
- package/dist/types/src/script/Script.d.ts.map +1 -1
- package/dist/types/src/transaction/MerklePath.d.ts.map +1 -1
- package/dist/types/src/transaction/Transaction.d.ts +7 -7
- package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
- package/dist/types/src/transaction/broadcasters/ARC.d.ts +23 -7
- package/dist/types/src/transaction/broadcasters/ARC.d.ts.map +1 -1
- package/dist/types/src/transaction/broadcasters/DefaultBroadcaster.d.ts +3 -0
- package/dist/types/src/transaction/broadcasters/DefaultBroadcaster.d.ts.map +1 -0
- package/dist/types/src/transaction/broadcasters/WhatsOnChainBroadcaster.d.ts +26 -0
- package/dist/types/src/transaction/broadcasters/WhatsOnChainBroadcaster.d.ts.map +1 -0
- package/dist/types/src/transaction/broadcasters/index.d.ts +3 -0
- package/dist/types/src/transaction/broadcasters/index.d.ts.map +1 -1
- package/dist/types/src/transaction/chaintrackers/DefaultChainTracker.d.ts +3 -0
- package/dist/types/src/transaction/chaintrackers/DefaultChainTracker.d.ts.map +1 -0
- package/dist/types/src/transaction/chaintrackers/WhatsOnChain.d.ts +28 -0
- package/dist/types/src/transaction/chaintrackers/WhatsOnChain.d.ts.map +1 -0
- package/dist/types/src/transaction/chaintrackers/index.d.ts +4 -0
- package/dist/types/src/transaction/chaintrackers/index.d.ts.map +1 -0
- package/dist/types/src/transaction/http/DefaultHttpClient.d.ts +8 -0
- package/dist/types/src/transaction/http/DefaultHttpClient.d.ts.map +1 -0
- package/dist/types/src/transaction/http/FetchHttpClient.d.ts +31 -0
- package/dist/types/src/transaction/http/FetchHttpClient.d.ts.map +1 -0
- package/dist/types/src/transaction/http/HttpClient.d.ts +43 -0
- package/dist/types/src/transaction/http/HttpClient.d.ts.map +1 -0
- package/dist/types/src/transaction/http/NodejsHttpClient.d.ts +21 -0
- package/dist/types/src/transaction/http/NodejsHttpClient.d.ts.map +1 -0
- package/dist/types/src/transaction/http/index.d.ts +7 -0
- package/dist/types/src/transaction/http/index.d.ts.map +1 -0
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/docs/examples/EXAMPLE_BUILDING_CUSTOM_TX_BROADCASTER.md +2 -0
- package/docs/examples/EXAMPLE_COMPLEX_TX.md +2 -4
- package/docs/examples/EXAMPLE_SIMPLE_TX.md +83 -2
- package/docs/examples/EXAMPLE_VERIFYING_BEEF.md +29 -22
- package/docs/examples/EXAMPLE_VERIFYING_ROOTS.md +18 -63
- package/docs/examples/GETTING_STARTED_NODE_CJS.md +2 -4
- package/docs/examples/GETTING_STARTED_REACT.md +2 -4
- package/docs/primitives.md +36 -3
- package/docs/transaction.md +48 -0
- package/mod.ts +2 -1
- package/package.json +21 -1
- package/src/primitives/PublicKey.ts +39 -0
- package/src/primitives/Signature.ts +6 -6
- package/src/script/Script.ts +19 -19
- package/src/transaction/MerklePath.ts +9 -9
- package/src/transaction/Transaction.ts +13 -13
- package/src/transaction/__tests/Transaction.test.ts +62 -0
- package/src/transaction/broadcasters/ARC.ts +71 -57
- package/src/transaction/broadcasters/DefaultBroadcaster.ts +6 -0
- package/src/transaction/broadcasters/WhatsOnChainBroadcaster.ts +70 -0
- package/src/transaction/broadcasters/__tests/ARC.test.ts +152 -41
- package/src/transaction/broadcasters/__tests/WhatsOnChainBroadcaster.test.ts +165 -0
- package/src/transaction/broadcasters/index.ts +3 -0
- package/src/transaction/chaintrackers/DefaultChainTracker.ts +6 -0
- package/src/transaction/chaintrackers/WhatsOnChain.ts +70 -0
- package/src/transaction/chaintrackers/__tests/WhatsOnChainChainTracker.test.ts +135 -0
- package/src/transaction/chaintrackers/index.ts +3 -0
- package/src/transaction/http/DefaultHttpClient.ts +32 -0
- package/src/transaction/http/FetchHttpClient.ts +50 -0
- package/src/transaction/http/HttpClient.ts +45 -0
- package/src/transaction/http/NodejsHttpClient.ts +55 -0
- package/src/transaction/http/index.ts +6 -0
|
@@ -45,7 +45,7 @@ await tx.sign()
|
|
|
45
45
|
// Finally, we broadcast it with ARC.
|
|
46
46
|
// get your api key from https://console.taal.com
|
|
47
47
|
const apiKey = 'mainnet_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' // replace
|
|
48
|
-
await tx.broadcast(
|
|
48
|
+
await tx.broadcast()
|
|
49
49
|
```
|
|
50
50
|
|
|
51
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).
|
|
@@ -61,4 +61,85 @@ transaction.addOutput({
|
|
|
61
61
|
})
|
|
62
62
|
```
|
|
63
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.
|
|
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.
|
|
65
|
+
|
|
66
|
+
## Choosing broadcasting target (ARC or WhatsOnChain)
|
|
67
|
+
|
|
68
|
+
### ARC
|
|
69
|
+
|
|
70
|
+
You can broadcast via selected ARC by providing ARC instance to the `broadcast` method.
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
await tx.broadcast(new ARC('https://api.taal.com/arc', apiKey))
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### WhatsOnChain
|
|
77
|
+
|
|
78
|
+
You can broadcast via What's On Chain by providing WhatsOnChainBroadcaster instance to the `broadcast` method.
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const network = 'main' // or 'test'
|
|
82
|
+
await tx.broadcast(new WhatsOnChainBroadcaster(network))
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Use custom http client for broadcasting
|
|
86
|
+
|
|
87
|
+
The ARC broadcaster requires an HTTP client to broadcast transactions. By default, the SDK will try to search for `window.fetch` in browser or `https` module on Node.js.
|
|
88
|
+
If you want to use a custom (or preconfigured) HTTP client, you can pass it with use of the adapter the ARC constructor:
|
|
89
|
+
|
|
90
|
+
### fetch
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// In this example we're assuming you have variable fetch holding the fetch function`
|
|
94
|
+
|
|
95
|
+
const arc = new ARC('https://api.taal.com/arc', apiKey, new FetchHttpClient(mockFetch))
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### https
|
|
99
|
+
|
|
100
|
+
Because ARC is assuming concrete interface of the http client, we're providing an adapter for https module.
|
|
101
|
+
You can use it as follows:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// In this example we're assuming you have variable https holding the https module loaded for example with `require('https')`
|
|
105
|
+
|
|
106
|
+
const arc = new ARC('https://api.taal.com/arc', apiKey, new NodejsHttpClient(https))
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### axios
|
|
111
|
+
|
|
112
|
+
Although the SDK is not providing adapters for axios, it can be easily used with the ARC broadcaster.
|
|
113
|
+
You can make your own "adapter" for axios as follows:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const axiosHttpClient = const httpClient: HttpClient = {
|
|
117
|
+
request: async (...args) => {
|
|
118
|
+
let res;
|
|
119
|
+
try {
|
|
120
|
+
res = await axios(...args);
|
|
121
|
+
} catch (e: unknown) {
|
|
122
|
+
if (axios.isAxiosError(e)) {
|
|
123
|
+
res = e.response;
|
|
124
|
+
} else {
|
|
125
|
+
throw e;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!res) {
|
|
129
|
+
throw new Error('No response');
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
ok: res.status >= 200 && res.status <= 299,
|
|
133
|
+
...res
|
|
134
|
+
};
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
new ARC('https://api.taal.com/arc', apiKey, axiosHttpClient)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### other libraries
|
|
142
|
+
|
|
143
|
+
Although the SDK is not providing adapters for other libraries,
|
|
144
|
+
you can easily create your own adapter by implementing the `HttpClient` interface.
|
|
145
|
+
Please look at the example for axios above to see how easy it can be done.
|
|
@@ -12,26 +12,6 @@ Merkle proofs are simply a way for someone to prove the existence of a given tra
|
|
|
12
12
|
|
|
13
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
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
15
|
## Verifying a BEEF Structure
|
|
36
16
|
|
|
37
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:
|
|
@@ -46,10 +26,37 @@ const BEEFHex = '0100beef01fe636d0c0007021400fe507c0c7aa754cef1f7889d5fd395cf1f7
|
|
|
46
26
|
const tx = Transaction.fromHexBEEF(BEEFHex)
|
|
47
27
|
|
|
48
28
|
// This ensures the BEEF structure is legitimate
|
|
49
|
-
const verified = await tx.verify(
|
|
29
|
+
const verified = await tx.verify()
|
|
50
30
|
|
|
51
31
|
// Print the results
|
|
52
32
|
console.log(verified)
|
|
53
33
|
```
|
|
54
34
|
|
|
55
|
-
The above code allows you to ensure that a given BEEF structure is valid according to the rules of SPV.
|
|
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,6 +1,6 @@
|
|
|
1
1
|
# Example: Building a Pulse Block Headers Client
|
|
2
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 [
|
|
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
4
|
|
|
5
5
|
## Pre-requisites
|
|
6
6
|
|
|
@@ -41,59 +41,13 @@ export default interface ChainTracker {
|
|
|
41
41
|
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
We will hide the complexities of making an https request from browsers/node.js in an separate function, which you could then import into the files you need otherwise.
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
// httpsClient.ts
|
|
48
|
-
async function nodeFetch (https, url, requestOptions): Promise<any> {
|
|
49
|
-
return await new Promise((resolve, reject) => {
|
|
50
|
-
const req = https.request(url, requestOptions, res => {
|
|
51
|
-
let data = ''
|
|
52
|
-
res.on('data', (chunk: string) => {
|
|
53
|
-
data += chunk
|
|
54
|
-
})
|
|
55
|
-
res.on('end', () => {
|
|
56
|
-
resolve(data)
|
|
57
|
-
})
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
req.on('error', error => {
|
|
61
|
-
reject(error)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
if (requestOptions.body as boolean) {
|
|
65
|
-
req.write(requestOptions.body)
|
|
66
|
-
}
|
|
67
|
-
req.end()
|
|
68
|
-
})
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export async function httpsClient (url: string, options: any) : Promise<any> {
|
|
73
|
-
let response
|
|
74
|
-
let data: any = {}
|
|
75
|
-
if (typeof window !== 'undefined' && typeof window.fetch === 'function') {
|
|
76
|
-
// Use fetch in a browser environment
|
|
77
|
-
response = await window.fetch(url, options)
|
|
78
|
-
data = await response.json()
|
|
79
|
-
return data
|
|
80
|
-
}
|
|
81
|
-
if (typeof require === 'undefined') throw new Error('No method available to perform HTTP request')
|
|
82
|
-
// Use Node.js https module
|
|
83
|
-
// eslint-disable-next-line
|
|
84
|
-
const https = require('https')
|
|
85
|
-
response = await nodeFetch(https, url, requestOptions)
|
|
86
|
-
data = JSON.parse(response)
|
|
87
|
-
return data
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
|
|
92
44
|
Given an array of merkle roots and corresponding block heights, we return a boolean indicating whether they're all valid.
|
|
93
45
|
|
|
94
46
|
We can plug in the Block Header Service API with appropriate HTTP handling logic as follows:
|
|
95
47
|
|
|
96
48
|
```typescript
|
|
49
|
+
import {defaultHttpClient} from "@bsv/sdk";
|
|
50
|
+
|
|
97
51
|
/**
|
|
98
52
|
* Represents a Block Headers Client.
|
|
99
53
|
*/
|
|
@@ -107,9 +61,10 @@ export default class BlockHeadersClient implements ChainTracker {
|
|
|
107
61
|
* @param {string} URL - The URL endpoint for the Pulse API.
|
|
108
62
|
* @param {string} apiKey - The API key used for authorization with the Pulse API.
|
|
109
63
|
*/
|
|
110
|
-
constructor
|
|
64
|
+
constructor(URL: string, apiKey: string) {
|
|
111
65
|
this.URL = URL
|
|
112
66
|
this.apiKey = apiKey
|
|
67
|
+
this.httpClient = defaultHttpClient()
|
|
113
68
|
}
|
|
114
69
|
|
|
115
70
|
/**
|
|
@@ -119,19 +74,19 @@ export default class BlockHeadersClient implements ChainTracker {
|
|
|
119
74
|
* @param height: number - The corresponding height
|
|
120
75
|
* @returns {Promise<boolean>} A promise that resolves to either a success or failure response (true or false).
|
|
121
76
|
*/
|
|
122
|
-
async isValidRootForHeight
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return data?.confirmationState === 'CONFIRMED'
|
|
133
|
-
}
|
|
134
|
-
|
|
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}`)
|
|
135
90
|
}
|
|
136
91
|
}
|
|
137
92
|
}
|
|
@@ -53,9 +53,7 @@ const tx = new Transaction(version, [input], [output])
|
|
|
53
53
|
await tx.fee()
|
|
54
54
|
await tx.sign()
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
const apiKey = 'mainnet_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' // replace
|
|
58
|
-
await tx.broadcast(new ARC('https://api.taal.com/arc', apiKey))
|
|
56
|
+
await tx.broadcast()
|
|
59
57
|
```
|
|
60
58
|
|
|
61
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.
|
|
@@ -70,4 +68,4 @@ node index.js
|
|
|
70
68
|
|
|
71
69
|
## Conclusion
|
|
72
70
|
|
|
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.
|
|
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.
|
|
@@ -60,9 +60,7 @@ const BsvButton: React.FC = () => {
|
|
|
60
60
|
await tx.fee()
|
|
61
61
|
await tx.sign()
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
const apiKey = 'mainnet_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' // replace
|
|
65
|
-
await tx.broadcast(new ARC('https://api.taal.com/arc', apiKey))
|
|
63
|
+
await tx.broadcast()
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
return (
|
|
@@ -118,4 +116,4 @@ Now when you click the button, a transaction will be created, signed, and broadc
|
|
|
118
116
|
Conclusion
|
|
119
117
|
----------
|
|
120
118
|
|
|
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.
|
|
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/primitives.md
CHANGED
|
@@ -6178,9 +6178,9 @@ const publicKey = signature.RecoverPublicKey(0, msgHash);
|
|
|
6178
6178
|
Takes an array of numbers or a string and returns a new Signature instance.
|
|
6179
6179
|
This method will throw an error if the Compact encoding is invalid.
|
|
6180
6180
|
If a string is provided, it is assumed to represent a hexadecimal sequence.
|
|
6181
|
-
compactByte value 27-
|
|
6182
|
-
|
|
6183
|
-
The range represents the recovery param which can be 0,1,2,3
|
|
6181
|
+
compactByte value 27-30 means uncompressed public key.
|
|
6182
|
+
31-34 means compressed public key.
|
|
6183
|
+
The range represents the recovery param which can be 0,1,2,3.
|
|
6184
6184
|
We could support recovery functions in future if there's demand.
|
|
6185
6185
|
|
|
6186
6186
|
```ts
|
|
@@ -6704,6 +6704,7 @@ export default class PublicKey extends Point {
|
|
|
6704
6704
|
toHash(enc?: "hex"): number[] | string
|
|
6705
6705
|
toAddress(prefix: number[] = [0]): string
|
|
6706
6706
|
deriveChild(privateKey: PrivateKey, invoiceNumber: string): PublicKey
|
|
6707
|
+
static fromMsgHashAndCompactSignature(msgHash: BigNumber, signature: number[] | string, enc?: "hex" | "base64"): PublicKey
|
|
6707
6708
|
}
|
|
6708
6709
|
```
|
|
6709
6710
|
|
|
@@ -6781,6 +6782,38 @@ const myPrivKey = new PrivateKey(...)
|
|
|
6781
6782
|
const sharedSecret = myPubKey.deriveSharedSecret(myPrivKey)
|
|
6782
6783
|
```
|
|
6783
6784
|
|
|
6785
|
+
#### Method fromMsgHashAndCompactSignature
|
|
6786
|
+
|
|
6787
|
+
Takes an array of numbers or a string and returns a new PublicKey instance.
|
|
6788
|
+
This method will throw an error if the Compact encoding is invalid.
|
|
6789
|
+
If a string is provided, it is assumed to represent a hexadecimal sequence.
|
|
6790
|
+
compactByte value 27-30 means uncompressed public key.
|
|
6791
|
+
31-34 means compressed public key.
|
|
6792
|
+
The range represents the recovery param which can be 0,1,2,3.
|
|
6793
|
+
|
|
6794
|
+
```ts
|
|
6795
|
+
static fromMsgHashAndCompactSignature(msgHash: BigNumber, signature: number[] | string, enc?: "hex" | "base64"): PublicKey
|
|
6796
|
+
```
|
|
6797
|
+
|
|
6798
|
+
Returns
|
|
6799
|
+
|
|
6800
|
+
A PublicKey instance derived from the message hash and compact signature.
|
|
6801
|
+
|
|
6802
|
+
Argument Details
|
|
6803
|
+
|
|
6804
|
+
+ **msgHash**
|
|
6805
|
+
+ The message hash which was signed.
|
|
6806
|
+
+ **signature**
|
|
6807
|
+
+ The signature in compact format.
|
|
6808
|
+
+ **enc**
|
|
6809
|
+
+ The encoding of the signature string.
|
|
6810
|
+
|
|
6811
|
+
Example
|
|
6812
|
+
|
|
6813
|
+
```ts
|
|
6814
|
+
const publicKey = Signature.fromMsgHashAndCompactSignature(msgHash, 'IMOl2mVKfDgsSsHT4uIYBNN4e...', 'base64');
|
|
6815
|
+
```
|
|
6816
|
+
|
|
6784
6817
|
#### Method fromPrivateKey
|
|
6785
6818
|
|
|
6786
6819
|
Static factory method to derive a public key from a private key.
|
package/docs/transaction.md
CHANGED
|
@@ -426,6 +426,18 @@ export default class Transaction {
|
|
|
426
426
|
metadata: Record<string, any>;
|
|
427
427
|
merklePath?: MerklePath;
|
|
428
428
|
static fromBEEF(beef: number[]): Transaction
|
|
429
|
+
static parseScriptOffsets(bin: number[]): {
|
|
430
|
+
inputs: {
|
|
431
|
+
vin: number;
|
|
432
|
+
offset: number;
|
|
433
|
+
length: number;
|
|
434
|
+
}[];
|
|
435
|
+
outputs: {
|
|
436
|
+
vout: number;
|
|
437
|
+
offset: number;
|
|
438
|
+
length: number;
|
|
439
|
+
}[];
|
|
440
|
+
}
|
|
429
441
|
static fromBinary(bin: number[]): Transaction
|
|
430
442
|
static fromHex(hex: string): Transaction
|
|
431
443
|
static fromHexBEEF(hex: string): Transaction
|
|
@@ -651,6 +663,42 @@ Argument Details
|
|
|
651
663
|
+ **enc**
|
|
652
664
|
+ The encoding to use for the ID. If 'hex', returns a hexadecimal string; otherwise returns a binary array.
|
|
653
665
|
|
|
666
|
+
#### Method parseScriptOffsets
|
|
667
|
+
|
|
668
|
+
Since the validation of blockchain data is atomically transaction data validation,
|
|
669
|
+
any application seeking to validate data in output scripts must store the entire transaction as well.
|
|
670
|
+
Since the transaction data includes the output script data, saving a second copy of potentially
|
|
671
|
+
large scripts can bloat application storage requirements.
|
|
672
|
+
|
|
673
|
+
This function efficiently parses binary transaction data to determine the offsets and lengths of each script.
|
|
674
|
+
This supports the efficient retreival of script data from transaction data.
|
|
675
|
+
|
|
676
|
+
```ts
|
|
677
|
+
static parseScriptOffsets(bin: number[]): {
|
|
678
|
+
inputs: {
|
|
679
|
+
vin: number;
|
|
680
|
+
offset: number;
|
|
681
|
+
length: number;
|
|
682
|
+
}[];
|
|
683
|
+
outputs: {
|
|
684
|
+
vout: number;
|
|
685
|
+
offset: number;
|
|
686
|
+
length: number;
|
|
687
|
+
}[];
|
|
688
|
+
}
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
Returns
|
|
692
|
+
|
|
693
|
+
inputs: { vin: number, offset: number, length: number }[]
|
|
694
|
+
outputs: { vout: number, offset: number, length: number }[]
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
Argument Details
|
|
698
|
+
|
|
699
|
+
+ **bin**
|
|
700
|
+
+ binary transaction data
|
|
701
|
+
|
|
654
702
|
#### Method sign
|
|
655
703
|
|
|
656
704
|
Signs a transaction, hydrating all its unlocking scripts based on the provided script templates where they are available.
|
package/mod.ts
CHANGED
|
@@ -4,5 +4,6 @@ export * from "./src/script/templates/index.js"
|
|
|
4
4
|
export * from "./src/transaction/index.js"
|
|
5
5
|
export * from "./src/transaction/fee-models/index.js"
|
|
6
6
|
export * from "./src/transaction/broadcasters/index.js"
|
|
7
|
+
export * from "./src/transaction/http/index.js"
|
|
7
8
|
export * from "./src/messages/index.js"
|
|
8
|
-
export * from "./src/compat/index.js"
|
|
9
|
+
export * from "./src/compat/index.js"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bsv/sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.34",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "BSV Blockchain Software Development Kit",
|
|
6
6
|
"main": "dist/cjs/mod.js",
|
|
@@ -74,6 +74,26 @@
|
|
|
74
74
|
"require": "./dist/cjs/src/transaction/broadcaster/*.js",
|
|
75
75
|
"types": "./dist/types/src/transaction/broadcaster/*.d.ts"
|
|
76
76
|
},
|
|
77
|
+
"./transaction/chaintrackers": {
|
|
78
|
+
"import": "./dist/esm/src/transaction/chaintrackers/index.js",
|
|
79
|
+
"require": "./dist/cjs/src/transaction/chaintrackers/index.js",
|
|
80
|
+
"types": "./dist/types/src/transaction/chaintrackers/index.d.ts"
|
|
81
|
+
},
|
|
82
|
+
"./transaction/chaintrackers/*": {
|
|
83
|
+
"import": "./dist/esm/src/transaction/chaintrackers/*.js",
|
|
84
|
+
"require": "./dist/cjs/src/transaction/chaintrackers/*.js",
|
|
85
|
+
"types": "./dist/types/src/transaction/chaintrackers/*.d.ts"
|
|
86
|
+
},
|
|
87
|
+
"./transaction/http": {
|
|
88
|
+
"import": "./dist/esm/src/transaction/http/index.js",
|
|
89
|
+
"require": "./dist/cjs/src/transaction/http/index.js",
|
|
90
|
+
"types": "./dist/types/src/transaction/http/index.d.ts"
|
|
91
|
+
},
|
|
92
|
+
"./transaction/http/*": {
|
|
93
|
+
"import": "./dist/esm/src/transaction/http/*.js",
|
|
94
|
+
"require": "./dist/cjs/src/transaction/http/*.js",
|
|
95
|
+
"types": "./dist/types/src/transaction/http/*.d.ts"
|
|
96
|
+
},
|
|
77
97
|
"./transaction/fee-model": {
|
|
78
98
|
"import": "./dist/esm/src/transaction/fee-model/index.js",
|
|
79
99
|
"require": "./dist/cjs/src/transaction/fee-model/index.js",
|
|
@@ -172,4 +172,43 @@ export default class PublicKey extends Point {
|
|
|
172
172
|
const finalPoint = this.add(point)
|
|
173
173
|
return new PublicKey(finalPoint.x, finalPoint.y)
|
|
174
174
|
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Takes an array of numbers or a string and returns a new PublicKey instance.
|
|
178
|
+
* This method will throw an error if the Compact encoding is invalid.
|
|
179
|
+
* If a string is provided, it is assumed to represent a hexadecimal sequence.
|
|
180
|
+
* compactByte value 27-30 means uncompressed public key.
|
|
181
|
+
* 31-34 means compressed public key.
|
|
182
|
+
* The range represents the recovery param which can be 0,1,2,3.
|
|
183
|
+
*
|
|
184
|
+
* @static
|
|
185
|
+
* @method fromMsgHashAndCompactSignature
|
|
186
|
+
* @param msgHash - The message hash which was signed.
|
|
187
|
+
* @param signature - The signature in compact format.
|
|
188
|
+
* @param enc - The encoding of the signature string.
|
|
189
|
+
* @returns A PublicKey instance derived from the message hash and compact signature.
|
|
190
|
+
* @example
|
|
191
|
+
* const publicKey = Signature.fromMsgHashAndCompactSignature(msgHash, 'IMOl2mVKfDgsSsHT4uIYBNN4e...', 'base64');
|
|
192
|
+
*/
|
|
193
|
+
static fromMsgHashAndCompactSignature (msgHash: BigNumber, signature: number[] | string, enc?: 'hex' | 'base64'): PublicKey {
|
|
194
|
+
const data = toArray(signature, enc)
|
|
195
|
+
if (data.length !== 65) {
|
|
196
|
+
throw new Error('Invalid Compact Signature')
|
|
197
|
+
}
|
|
198
|
+
const compactByte = data[0]
|
|
199
|
+
if (compactByte < 27 || compactByte >= 35) {
|
|
200
|
+
throw new Error('Invalid Compact Byte')
|
|
201
|
+
}
|
|
202
|
+
let r = data[0] - 27
|
|
203
|
+
let compressed = false // we don't really use this in the modern era, always use compressed.
|
|
204
|
+
if (r > 3) {
|
|
205
|
+
compressed = true
|
|
206
|
+
r -= 4
|
|
207
|
+
}
|
|
208
|
+
const s = new Signature(
|
|
209
|
+
new BigNumber(data.slice(1, 33)),
|
|
210
|
+
new BigNumber(data.slice(33, 65))
|
|
211
|
+
)
|
|
212
|
+
return s.RecoverPublicKey(r, msgHash)
|
|
213
|
+
}
|
|
175
214
|
}
|
|
@@ -106,9 +106,9 @@ export default class Signature {
|
|
|
106
106
|
* Takes an array of numbers or a string and returns a new Signature instance.
|
|
107
107
|
* This method will throw an error if the Compact encoding is invalid.
|
|
108
108
|
* If a string is provided, it is assumed to represent a hexadecimal sequence.
|
|
109
|
-
* compactByte value 27-
|
|
110
|
-
*
|
|
111
|
-
* The range represents the recovery param which can be 0,1,2,3
|
|
109
|
+
* compactByte value 27-30 means uncompressed public key.
|
|
110
|
+
* 31-34 means compressed public key.
|
|
111
|
+
* The range represents the recovery param which can be 0,1,2,3.
|
|
112
112
|
* We could support recovery functions in future if there's demand.
|
|
113
113
|
*
|
|
114
114
|
* @static
|
|
@@ -339,9 +339,9 @@ export default class Signature {
|
|
|
339
339
|
const rInv = r.invm(n)
|
|
340
340
|
|
|
341
341
|
// const Q = R.multiplyTwo(s, G, eNeg).mul(rInv)
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
342
|
+
const srInv = rInv.mul(s).umod(n)
|
|
343
|
+
const eInvrInv = rInv.mul(eNeg).umod(n)
|
|
344
|
+
const Q = G.mul(eInvrInv).add(R.mul(srInv))
|
|
345
345
|
|
|
346
346
|
const pubKey = new PublicKey(Q)
|
|
347
347
|
pubKey.validate()
|