@bsv/wallet-toolbox 1.1.12 → 1.1.14
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/.github/workflows/push.yaml +2 -2
- package/README.md +3 -22
- package/docs/README.md +16 -10
- package/docs/client.md +490 -382
- package/docs/open-rpc/index.html +46 -0
- package/docs/services.md +236 -211
- package/docs/setup.md +51 -34
- package/docs/storage.md +30 -5
- package/docs/wallet.md +490 -382
- package/out/src/SetupClient.d.ts +9 -0
- package/out/src/SetupClient.d.ts.map +1 -1
- package/out/src/SetupClient.js +34 -18
- package/out/src/SetupClient.js.map +1 -1
- package/out/src/Wallet.d.ts +6 -0
- package/out/src/Wallet.d.ts.map +1 -1
- package/out/src/Wallet.js +57 -0
- package/out/src/Wallet.js.map +1 -1
- package/out/src/sdk/WalletServices.interfaces.d.ts +18 -13
- package/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
- package/out/src/services/Services.d.ts +4 -11
- package/out/src/services/Services.d.ts.map +1 -1
- package/out/src/services/Services.js +19 -37
- package/out/src/services/Services.js.map +1 -1
- package/out/src/services/__tests/ARC.test.d.ts +2 -0
- package/out/src/services/__tests/ARC.test.d.ts.map +1 -0
- package/out/src/services/__tests/ARC.test.js +98 -0
- package/out/src/services/__tests/ARC.test.js.map +1 -0
- package/out/src/services/__tests/arcServices.test.d.ts +2 -0
- package/out/src/services/__tests/arcServices.test.d.ts.map +1 -0
- package/out/src/services/__tests/arcServices.test.js +7 -0
- package/out/src/services/__tests/arcServices.test.js.map +1 -0
- package/out/src/services/__tests/postBeef.test.js +45 -7
- package/out/src/services/__tests/postBeef.test.js.map +1 -1
- package/out/src/services/createDefaultWalletServicesOptions.d.ts +1 -0
- package/out/src/services/createDefaultWalletServicesOptions.d.ts.map +1 -1
- package/out/src/services/createDefaultWalletServicesOptions.js +16 -4
- package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
- package/out/src/services/providers/ARC.d.ts +91 -0
- package/out/src/services/providers/ARC.d.ts.map +1 -0
- package/out/src/services/providers/ARC.js +192 -0
- package/out/src/services/providers/ARC.js.map +1 -0
- package/out/src/services/providers/SdkWhatsOnChain.d.ts +21 -0
- package/out/src/services/providers/SdkWhatsOnChain.d.ts.map +1 -0
- package/out/src/services/providers/SdkWhatsOnChain.js +67 -0
- package/out/src/services/providers/SdkWhatsOnChain.js.map +1 -0
- package/out/src/services/providers/WhatsOnChain.d.ts +35 -0
- package/out/src/services/providers/WhatsOnChain.d.ts.map +1 -0
- package/out/src/services/providers/WhatsOnChain.js +266 -0
- package/out/src/services/providers/WhatsOnChain.js.map +1 -0
- package/out/src/services/providers/__tests/WhatsOnChain.test.d.ts +2 -0
- package/out/src/services/providers/__tests/WhatsOnChain.test.d.ts.map +1 -0
- package/out/src/services/providers/__tests/WhatsOnChain.test.js +176 -0
- package/out/src/services/providers/__tests/WhatsOnChain.test.js.map +1 -0
- package/out/src/signer/methods/createAction.js +3 -3
- package/out/src/signer/methods/createAction.js.map +1 -1
- package/out/src/signer/methods/signAction.js +1 -1
- package/out/src/signer/methods/signAction.js.map +1 -1
- package/out/src/storage/methods/createAction.d.ts.map +1 -1
- package/out/src/storage/methods/createAction.js +9 -2
- package/out/src/storage/methods/createAction.js.map +1 -1
- package/out/src/storage/methods/generateChange.d.ts +12 -1
- package/out/src/storage/methods/generateChange.d.ts.map +1 -1
- package/out/src/storage/methods/generateChange.js +24 -1
- package/out/src/storage/methods/generateChange.js.map +1 -1
- package/out/src/storage/methods/processAction.d.ts.map +1 -1
- package/out/src/storage/methods/processAction.js +1 -1
- package/out/src/storage/methods/processAction.js.map +1 -1
- package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js +0 -1
- package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js.map +1 -1
- package/out/src/storage/sync/StorageMySQLDojoReader.js +1 -1
- package/out/src/storage/sync/StorageMySQLDojoReader.js.map +1 -1
- package/out/src/utility/{ScriptTemplateSABPPP.d.ts → ScriptTemplateBRC29.d.ts} +6 -6
- package/out/src/utility/ScriptTemplateBRC29.d.ts.map +1 -0
- package/out/src/utility/{ScriptTemplateSABPPP.js → ScriptTemplateBRC29.js} +4 -4
- package/out/src/utility/ScriptTemplateBRC29.js.map +1 -0
- package/out/src/utility/index.all.d.ts +1 -1
- package/out/src/utility/index.all.d.ts.map +1 -1
- package/out/src/utility/index.all.js +1 -1
- package/out/src/utility/index.all.js.map +1 -1
- package/out/src/utility/index.client.d.ts +1 -1
- package/out/src/utility/index.client.d.ts.map +1 -1
- package/out/src/utility/index.client.js +1 -1
- package/out/src/utility/index.client.js.map +1 -1
- package/out/src/utility/utilityHelpers.js +1 -1
- package/out/src/utility/utilityHelpers.js.map +1 -1
- package/out/test/Wallet/StorageClient/storageClient.man.test.js +22 -3
- package/out/test/Wallet/StorageClient/storageClient.man.test.js.map +1 -1
- package/out/test/Wallet/live/walletLive.man.test.js +2 -2
- package/out/test/Wallet/live/walletLive.man.test.js.map +1 -1
- package/out/test/Wallet/sync/Wallet.updateWalletLegacyTestData.man.test.js +40 -0
- package/out/test/Wallet/sync/Wallet.updateWalletLegacyTestData.man.test.js.map +1 -1
- package/out/test/services/Services.test.js +0 -31
- package/out/test/services/Services.test.js.map +1 -1
- package/out/test/utils/TestUtilsWalletStorage.d.ts +26 -18
- package/out/test/utils/TestUtilsWalletStorage.d.ts.map +1 -1
- package/out/test/utils/TestUtilsWalletStorage.js +135 -27
- package/out/test/utils/TestUtilsWalletStorage.js.map +1 -1
- package/out/test/wallet/list/listActions2.test.js +36 -2
- package/out/test/wallet/list/listActions2.test.js.map +1 -1
- package/out/tsconfig.all.tsbuildinfo +1 -1
- package/package.json +5 -7
- package/src/SetupClient.ts +41 -21
- package/src/Wallet.ts +66 -2
- package/src/sdk/WalletServices.interfaces.ts +19 -14
- package/src/services/Services.ts +23 -62
- package/src/services/__tests/ARC.test.ts +110 -0
- package/src/services/__tests/arcServices.test.ts +8 -0
- package/src/services/__tests/postBeef.test.ts +47 -9
- package/src/services/createDefaultWalletServicesOptions.ts +19 -6
- package/src/services/providers/ARC.ts +289 -0
- package/src/services/providers/SdkWhatsOnChain.ts +96 -0
- package/src/services/providers/WhatsOnChain.ts +369 -0
- package/src/services/providers/__tests/WhatsOnChain.test.ts +227 -0
- package/src/signer/methods/createAction.ts +4 -4
- package/src/signer/methods/signAction.ts +2 -2
- package/src/storage/methods/createAction.ts +26 -4
- package/src/storage/methods/generateChange.ts +42 -2
- package/src/storage/methods/processAction.ts +2 -1
- package/src/storage/schema/entities/__tests/ProvenTxTests.test.ts +0 -1
- package/src/storage/sync/StorageMySQLDojoReader.ts +1 -1
- package/src/utility/{ScriptTemplateSABPPP.ts → ScriptTemplateBRC29.ts} +6 -8
- package/src/utility/index.all.ts +1 -1
- package/src/utility/index.client.ts +1 -1
- package/src/utility/utilityHelpers.ts +1 -1
- package/test/Wallet/StorageClient/storageClient.man.test.ts +30 -4
- package/test/Wallet/live/walletLive.man.test.ts +3 -3
- package/test/Wallet/sync/Wallet.updateWalletLegacyTestData.man.test.ts +54 -0
- package/test/services/Services.test.ts +0 -30
- package/test/utils/TestUtilsWalletStorage.ts +175 -45
- package/test/wallet/list/listActions2.test.ts +4 -7
- package/out/src/services/__tests/postBeefToArcTaal.test.d.ts +0 -2
- package/out/src/services/__tests/postBeefToArcTaal.test.d.ts.map +0 -1
- package/out/src/services/__tests/postBeefToArcTaal.test.js +0 -479
- package/out/src/services/__tests/postBeefToArcTaal.test.js.map +0 -1
- package/out/src/services/__tests/postTxs.test.d.ts +0 -2
- package/out/src/services/__tests/postTxs.test.d.ts.map +0 -1
- package/out/src/services/__tests/postTxs.test.js +0 -28
- package/out/src/services/__tests/postTxs.test.js.map +0 -1
- package/out/src/services/providers/arcServices.d.ts +0 -62
- package/out/src/services/providers/arcServices.d.ts.map +0 -1
- package/out/src/services/providers/arcServices.js +0 -375
- package/out/src/services/providers/arcServices.js.map +0 -1
- package/out/src/services/providers/whatsonchain.d.ts +0 -17
- package/out/src/services/providers/whatsonchain.d.ts.map +0 -1
- package/out/src/services/providers/whatsonchain.js +0 -130
- package/out/src/services/providers/whatsonchain.js.map +0 -1
- package/out/src/utility/ScriptTemplateSABPPP.d.ts.map +0 -1
- package/out/src/utility/ScriptTemplateSABPPP.js.map +0 -1
- package/out/test/examples/README.man.test.d.ts +0 -2
- package/out/test/examples/README.man.test.d.ts.map +0 -1
- package/out/test/examples/README.man.test.js +0 -47
- package/out/test/examples/README.man.test.js.map +0 -1
- package/src/services/__tests/postBeefToArcTaal.test.ts +0 -487
- package/src/services/__tests/postTxs.test.ts +0 -28
- package/src/services/providers/arcServices.ts +0 -578
- package/src/services/providers/whatsonchain.ts +0 -170
- package/test/examples/README.man.test.ts +0 -53
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import { HexString, WhatsOnChainConfig } from '@bsv/sdk'
|
|
2
|
+
import {
|
|
3
|
+
asArray,
|
|
4
|
+
asString,
|
|
5
|
+
sdk,
|
|
6
|
+
validateScriptHash,
|
|
7
|
+
wait
|
|
8
|
+
} from '../../index.client'
|
|
9
|
+
import { convertProofToMerklePath } from '../../utility/tscProofToMerklePath'
|
|
10
|
+
import SdkWhatsOnChain from './SdkWhatsOnChain'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
export class WhatsOnChain extends SdkWhatsOnChain {
|
|
16
|
+
constructor(chain: sdk.Chain = 'main', config: WhatsOnChainConfig = {}) {
|
|
17
|
+
super(chain, config)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 2025-02-16 throwing internal server error 500.
|
|
22
|
+
* @param txid
|
|
23
|
+
* @returns
|
|
24
|
+
*/
|
|
25
|
+
async getTxPropagation(txid: string): Promise<number> {
|
|
26
|
+
const requestOptions = {
|
|
27
|
+
method: 'GET',
|
|
28
|
+
headers: this.getHttpHeaders()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const response = await this.httpClient.request<string>(
|
|
32
|
+
`${this.URL}/tx/hash/${txid}/propagation`,
|
|
33
|
+
requestOptions
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
if (
|
|
37
|
+
!response.data ||
|
|
38
|
+
!response.ok ||
|
|
39
|
+
response.status !== 200 ||
|
|
40
|
+
response.statusText !== 'OK'
|
|
41
|
+
)
|
|
42
|
+
throw new sdk.WERR_INVALID_PARAMETER(
|
|
43
|
+
'txid',
|
|
44
|
+
`valid transaction. '${txid}' response ${response.statusText}`
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
return 0
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* May return undefined for unmined transactions that are in the mempool.
|
|
52
|
+
* @param txid
|
|
53
|
+
* @returns raw transaction as hex string or undefined if txid not found in mined block.
|
|
54
|
+
*/
|
|
55
|
+
async getRawTx(txid: string): Promise<string | undefined> {
|
|
56
|
+
const headers = this.getHttpHeaders()
|
|
57
|
+
headers['Cache-Control'] = 'no-cache'
|
|
58
|
+
|
|
59
|
+
const requestOptions = {
|
|
60
|
+
method: 'GET',
|
|
61
|
+
headers
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
for (let retry = 0; retry < 2; retry++) {
|
|
65
|
+
const response = await this.httpClient.request<string>(
|
|
66
|
+
`${this.URL}/tx/${txid}/hex`,
|
|
67
|
+
requestOptions
|
|
68
|
+
)
|
|
69
|
+
if (response.statusText === 'Too Many Requests' && retry < 2) {
|
|
70
|
+
await wait(2000)
|
|
71
|
+
continue
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (response.status === 404 && response.statusText === 'Not Found')
|
|
75
|
+
return undefined
|
|
76
|
+
|
|
77
|
+
if (
|
|
78
|
+
!response.data ||
|
|
79
|
+
!response.ok ||
|
|
80
|
+
response.status !== 200 ||
|
|
81
|
+
response.statusText !== 'OK'
|
|
82
|
+
)
|
|
83
|
+
throw new sdk.WERR_INVALID_PARAMETER(
|
|
84
|
+
'txid',
|
|
85
|
+
`valid transaction. '${txid}' response ${response.statusText}`
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return response.data
|
|
89
|
+
}
|
|
90
|
+
throw new sdk.WERR_INTERNAL()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async getRawTxResult(txid: string): Promise<sdk.GetRawTxResult> {
|
|
94
|
+
const r: sdk.GetRawTxResult = { name: 'WoC', txid: asString(txid) }
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const rawTxHex = await this.getRawTx(txid)
|
|
98
|
+
if (rawTxHex) r.rawTx = asArray(rawTxHex)
|
|
99
|
+
} catch (err: unknown) {
|
|
100
|
+
r.error = sdk.WalletError.fromUnknown(err)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return r
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @param rawTx raw transaction to broadcast as hex string
|
|
108
|
+
* @returns txid returned by transaction processor of transaction broadcast
|
|
109
|
+
*/
|
|
110
|
+
async postRawTx(rawTx: HexString): Promise<string> {
|
|
111
|
+
const headers = this.getHttpHeaders()
|
|
112
|
+
headers['Content-Type'] = 'application/json'
|
|
113
|
+
headers['Accept'] = 'text/plain'
|
|
114
|
+
|
|
115
|
+
const requestOptions = {
|
|
116
|
+
method: 'POST',
|
|
117
|
+
headers,
|
|
118
|
+
data: { txhex: rawTx }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
for (let retry = 0; retry < 2; retry++) {
|
|
122
|
+
try {
|
|
123
|
+
const response = await this.httpClient.request<string>(
|
|
124
|
+
`${this.URL}/tx/raw`,
|
|
125
|
+
requestOptions
|
|
126
|
+
)
|
|
127
|
+
if (response.statusText === 'Too Many Requests' && retry < 2) {
|
|
128
|
+
await wait(2000)
|
|
129
|
+
continue
|
|
130
|
+
}
|
|
131
|
+
if (response.ok) {
|
|
132
|
+
const txid = response.data
|
|
133
|
+
return txid
|
|
134
|
+
} else {
|
|
135
|
+
if (typeof response.data === 'string')
|
|
136
|
+
throw new sdk.WERR_INVALID_PARAMETER(
|
|
137
|
+
'rawTx',
|
|
138
|
+
`valid. ${response.data}`
|
|
139
|
+
)
|
|
140
|
+
else
|
|
141
|
+
throw new sdk.WERR_INVALID_PARAMETER(
|
|
142
|
+
'rawTx',
|
|
143
|
+
`valid. ${response.status} ${response.statusText}`
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
} catch (eu: unknown) {
|
|
147
|
+
if (eu instanceof sdk.WERR_INVALID_PARAMETER) throw eu
|
|
148
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
149
|
+
throw new sdk.WERR_INVALID_PARAMETER(
|
|
150
|
+
'rawTx',
|
|
151
|
+
`valid rawTx. error ${e.code} ${e.message} ${rawTx}`
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
throw new sdk.WERR_INTERNAL()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @param txid
|
|
160
|
+
* @returns
|
|
161
|
+
*/
|
|
162
|
+
async getMerklePath(
|
|
163
|
+
txid: string,
|
|
164
|
+
services: sdk.WalletServices
|
|
165
|
+
): Promise<sdk.GetMerklePathResult> {
|
|
166
|
+
const r: sdk.GetMerklePathResult = { name: 'WoCTsc' }
|
|
167
|
+
|
|
168
|
+
const headers = this.getHttpHeaders()
|
|
169
|
+
const requestOptions = {
|
|
170
|
+
method: 'GET',
|
|
171
|
+
headers
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
for (let retry = 0; retry < 2; retry++) {
|
|
175
|
+
try {
|
|
176
|
+
const response = await this.httpClient.request<
|
|
177
|
+
WhatsOnChainTscProof | WhatsOnChainTscProof[]
|
|
178
|
+
>(`${this.URL}/tx/${txid}/proof/tsc`, requestOptions)
|
|
179
|
+
if (response.statusText === 'Too Many Requests' && retry < 2) {
|
|
180
|
+
await wait(2000)
|
|
181
|
+
continue
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (response.status === 404 && response.statusText === 'Not Found')
|
|
185
|
+
return r
|
|
186
|
+
|
|
187
|
+
if (
|
|
188
|
+
!response.ok ||
|
|
189
|
+
response.status !== 200 ||
|
|
190
|
+
response.statusText !== 'OK'
|
|
191
|
+
)
|
|
192
|
+
throw new sdk.WERR_INVALID_PARAMETER(
|
|
193
|
+
'txid',
|
|
194
|
+
`valid transaction. '${txid}' response ${response.statusText}`
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
if (!response.data) {
|
|
198
|
+
// Unmined, proof not yet available.
|
|
199
|
+
return r
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!Array.isArray(response.data)) response.data = [response.data]
|
|
203
|
+
|
|
204
|
+
if (response.data.length != 1) return r
|
|
205
|
+
|
|
206
|
+
const p = response.data[0]
|
|
207
|
+
const header = await services.hashToHeader(p.target)
|
|
208
|
+
if (header) {
|
|
209
|
+
const proof = {
|
|
210
|
+
index: p.index,
|
|
211
|
+
nodes: p.nodes,
|
|
212
|
+
height: header.height
|
|
213
|
+
}
|
|
214
|
+
r.merklePath = convertProofToMerklePath(txid, proof)
|
|
215
|
+
r.header = header
|
|
216
|
+
} else {
|
|
217
|
+
throw new sdk.WERR_INVALID_PARAMETER(
|
|
218
|
+
'blockhash',
|
|
219
|
+
'a valid on-chain block hash'
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
} catch (err: unknown) {
|
|
223
|
+
r.error = sdk.WalletError.fromUnknown(err)
|
|
224
|
+
}
|
|
225
|
+
return r
|
|
226
|
+
}
|
|
227
|
+
throw new sdk.WERR_INTERNAL()
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async updateBsvExchangeRate(
|
|
231
|
+
rate?: sdk.BsvExchangeRate,
|
|
232
|
+
updateMsecs?: number
|
|
233
|
+
): Promise<sdk.BsvExchangeRate> {
|
|
234
|
+
if (rate) {
|
|
235
|
+
// Check if the rate we know is stale enough to update.
|
|
236
|
+
updateMsecs ||= 1000 * 60 * 15
|
|
237
|
+
if (new Date(Date.now() - updateMsecs) < rate.timestamp) return rate
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const requestOptions = {
|
|
241
|
+
method: 'GET',
|
|
242
|
+
headers: this.getHttpHeaders()
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
for (let retry = 0; retry < 2; retry++) {
|
|
246
|
+
const response = await this.httpClient.request<{
|
|
247
|
+
rate: number
|
|
248
|
+
time: number
|
|
249
|
+
currency: string
|
|
250
|
+
}>(`${this.URL}/exchangerate`, requestOptions)
|
|
251
|
+
if (response.statusText === 'Too Many Requests' && retry < 2) {
|
|
252
|
+
await wait(2000)
|
|
253
|
+
continue
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (
|
|
257
|
+
!response.data ||
|
|
258
|
+
!response.ok ||
|
|
259
|
+
response.status !== 200 ||
|
|
260
|
+
response.statusText !== 'OK'
|
|
261
|
+
)
|
|
262
|
+
throw new sdk.WERR_INVALID_OPERATION(
|
|
263
|
+
`WoC exchangerate response ${response.statusText}`
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
const wocrate = response.data
|
|
267
|
+
if (wocrate.currency !== 'USD') wocrate.rate = NaN
|
|
268
|
+
|
|
269
|
+
const newRate: sdk.BsvExchangeRate = {
|
|
270
|
+
timestamp: new Date(),
|
|
271
|
+
base: 'USD',
|
|
272
|
+
rate: wocrate.rate
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return newRate
|
|
276
|
+
}
|
|
277
|
+
throw new sdk.WERR_INTERNAL()
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async getUtxoStatus(
|
|
281
|
+
output: string,
|
|
282
|
+
outputFormat?: sdk.GetUtxoStatusOutputFormat
|
|
283
|
+
): Promise<sdk.GetUtxoStatusResult> {
|
|
284
|
+
const r: sdk.GetUtxoStatusResult = {
|
|
285
|
+
name: 'WoC',
|
|
286
|
+
status: 'error',
|
|
287
|
+
error: new sdk.WERR_INTERNAL(),
|
|
288
|
+
details: []
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
for (let retry = 0; ; retry++) {
|
|
292
|
+
let url: string = ''
|
|
293
|
+
|
|
294
|
+
try {
|
|
295
|
+
const scriptHash = validateScriptHash(output, outputFormat)
|
|
296
|
+
|
|
297
|
+
const requestOptions = {
|
|
298
|
+
method: 'GET',
|
|
299
|
+
headers: this.getHttpHeaders()
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const response = await this.httpClient.request<
|
|
303
|
+
WhatsOnChainUtxoStatus[]
|
|
304
|
+
>(`${this.URL}/script/${scriptHash}/unspent`, requestOptions)
|
|
305
|
+
if (response.statusText === 'Too Many Requests' && retry < 2) {
|
|
306
|
+
await wait(2000)
|
|
307
|
+
continue
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (
|
|
311
|
+
!response.data ||
|
|
312
|
+
!response.ok ||
|
|
313
|
+
response.status !== 200 ||
|
|
314
|
+
response.statusText !== 'OK'
|
|
315
|
+
)
|
|
316
|
+
throw new sdk.WERR_INVALID_OPERATION(
|
|
317
|
+
`WoC exchangerate response ${response.statusText}`
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
if (Array.isArray(response.data)) {
|
|
321
|
+
const data = response.data
|
|
322
|
+
if (data.length === 0) {
|
|
323
|
+
r.status = 'success'
|
|
324
|
+
r.error = undefined
|
|
325
|
+
r.isUtxo = false
|
|
326
|
+
} else {
|
|
327
|
+
r.status = 'success'
|
|
328
|
+
r.error = undefined
|
|
329
|
+
r.isUtxo = true
|
|
330
|
+
for (const s of data) {
|
|
331
|
+
r.details.push({
|
|
332
|
+
txid: s.tx_hash,
|
|
333
|
+
satoshis: s.value,
|
|
334
|
+
height: s.height,
|
|
335
|
+
index: s.tx_pos
|
|
336
|
+
})
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
} else {
|
|
340
|
+
throw new sdk.WERR_INTERNAL('data is not an array')
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return r
|
|
344
|
+
} catch (eu: unknown) {
|
|
345
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
346
|
+
if (e.code !== 'ECONNRESET' || retry > 2) {
|
|
347
|
+
r.error = new sdk.WERR_INTERNAL(
|
|
348
|
+
`service failure: ${url}, error: ${JSON.stringify(sdk.WalletError.fromUnknown(eu))}`
|
|
349
|
+
)
|
|
350
|
+
return r
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
interface WhatsOnChainTscProof {
|
|
358
|
+
index: number
|
|
359
|
+
nodes: string[]
|
|
360
|
+
target: string
|
|
361
|
+
txOrId: string
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
interface WhatsOnChainUtxoStatus {
|
|
365
|
+
value: number
|
|
366
|
+
height: number
|
|
367
|
+
tx_pos: number
|
|
368
|
+
tx_hash: string
|
|
369
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { WhatsOnChainBroadcaster, WhatsOnChainConfig } from '@bsv/sdk'
|
|
2
|
+
import { _tu } from '../../../../test/utils/TestUtilsWalletStorage'
|
|
3
|
+
import { WhatsOnChain } from '../WhatsOnChain'
|
|
4
|
+
import { Services } from '../../Services'
|
|
5
|
+
import { sdk, wait } from '../../../index.client'
|
|
6
|
+
import { Setup, StorageKnex } from '../../../index.all'
|
|
7
|
+
describe('whatsonchain tests', () => {
|
|
8
|
+
jest.setTimeout(99999999)
|
|
9
|
+
|
|
10
|
+
const envTest = _tu.getEnv('test')
|
|
11
|
+
const wocTest = new WhatsOnChain(envTest.chain, {
|
|
12
|
+
apiKey: envTest.taalApiKey
|
|
13
|
+
})
|
|
14
|
+
const envMain = _tu.getEnv('main')
|
|
15
|
+
const wocMain = new WhatsOnChain(envMain.chain, {
|
|
16
|
+
apiKey: envMain.taalApiKey
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('0 getRawTx testnet', async () => {
|
|
20
|
+
const rawTx = await wocTest.getRawTx(
|
|
21
|
+
'7e5b797b86abd31a654bf296900d6cb14d04ef0811568ff4675494af2d92166b'
|
|
22
|
+
)
|
|
23
|
+
expect(
|
|
24
|
+
rawTx ===
|
|
25
|
+
'010000000158EED5DBBB7E2F7D70C79A11B9B61AABEECFA5A7CEC679BEDD00F42C48A4BD45010000006B483045022100AE8BB45498A40E2AC797775C405C108168804CD84E8C09A9D42D280D18EDDB6D022024863BFAAC5FF3C24CA65E2F3677EDA092BC3CC5D2EFABA73264B8FF55CF416B412102094AAF520E14E1C4D68496822800BCC7D3B3B26CA368E004A2CB70B398D82FACFFFFFFFF0203000000000000007421020A624B72B34BC192851C5D8890926BBB70B31BC10FDD4E3BC6534E41B1C81B93AC03010203030405064630440220013B4984F4054C2FBCD2F448AB896CCA5C4E234BF765B0C7FB27EDE572A7F7DA02201A5C8D0D023F94C209046B9A2B96B2882C5E43B72D8115561DF8C07442010EEA6D7592090000000000001976A9146511FCE2F7EF785A2102142FBF381AD1291C918688AC00000000'
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
expect(await wocTest.getRawTx('1'.repeat(64))).toBeUndefined()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('1 getRawTx mainnet', async () => {
|
|
32
|
+
const rawTx = await wocMain.getRawTx(
|
|
33
|
+
'd9978ffc6676523208f7b33bebf1b176388bbeace2c7ef67ce35c2eababa1805'
|
|
34
|
+
)
|
|
35
|
+
expect(
|
|
36
|
+
rawTx ===
|
|
37
|
+
'0100000001026A66A5F724EB490A55E0E08553286F08AD57E92C4BF34B5C44EA6BC0A49828020000006B483045022100C3D9A5ACA30C1F2E1A54532162E7AFE5AA69150E4C06D760414A16D1EA1BABD602205E0D9191838B0911A1E7328554A2B22EFAA80CF52B15FBA37C3046A0996C7AAD412103FA3CF488CA98D9F2DB91843F36BAF6BE39F6C947976C02394602D09FBC5F4CF4FFFFFFFF0210270000000000001976A91444C04354E88975C4BEF30CFE89D300CC7659F7E588AC96BC0000000000001976A9149A53E5CF5F1876924D98A8B35CA0BC693618682488AC00000000'
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
expect(await wocMain.getRawTx('1'.repeat(64))).toBeUndefined()
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('2 getMerklePath testnet', async () => {
|
|
44
|
+
const services = new Services(envTest.chain)
|
|
45
|
+
{
|
|
46
|
+
const r = await wocTest.getMerklePath(
|
|
47
|
+
'7e5b797b86abd31a654bf296900d6cb14d04ef0811568ff4675494af2d92166b',
|
|
48
|
+
services
|
|
49
|
+
)
|
|
50
|
+
const s = JSON.stringify(r)
|
|
51
|
+
expect(s).toBe(
|
|
52
|
+
'{"name":"WoCTsc","merklePath":{"blockHeight":1661398,"path":[[{"offset":6,"hash":"7e5b797b86abd31a654bf296900d6cb14d04ef0811568ff4675494af2d92166b","txid":true},{"offset":7,"hash":"97dd9d9080394d52338588732d9f84e1debca93f171f674ac3beac1e75495568"}],[{"offset":2,"hash":"81beedcd219d9e03255bde2ee479db34b9fed04d30373ba8bc264a64af2515b9"}],[{"offset":0,"hash":"9965f9aaeea33f6878335e6f7e6bdb544c3a8550c84e2f0daca54e9cd912111c"}]]},"header":{"version":536870912,"previousHash":"000000000688340a14b77e49bb0fca5ac7b624f7f79a5517583d1aae61c4e658","merkleRoot":"edbc07082ca0a31d5ec89d1f503a9cd41112c0d8f3221a96acfb8a9d16f8e82b","time":1739624725,"bits":486604799,"nonce":1437884974,"height":1661398,"hash":"00000000d8a73bf9a37272a71886ea92a25376bed1c1916f2b5cfbec4d6f6a25"}}'
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
{
|
|
57
|
+
const r = await wocTest.getMerklePath('1'.repeat(64), services)
|
|
58
|
+
const s = JSON.stringify(r)
|
|
59
|
+
expect(s).toBe('{"name":"WoCTsc"}')
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test('3 getMerklePath mainnet', async () => {
|
|
64
|
+
const services = new Services(envMain.chain)
|
|
65
|
+
{
|
|
66
|
+
const r = await wocMain.getMerklePath(
|
|
67
|
+
'd9978ffc6676523208f7b33bebf1b176388bbeace2c7ef67ce35c2eababa1805',
|
|
68
|
+
services
|
|
69
|
+
)
|
|
70
|
+
const s = JSON.stringify(r)
|
|
71
|
+
expect(s).toBe(
|
|
72
|
+
'{"name":"WoCTsc","merklePath":{"blockHeight":883637,"path":[[{"offset":46,"hash":"d9978ffc6676523208f7b33bebf1b176388bbeace2c7ef67ce35c2eababa1805","txid":true},{"offset":47,"hash":"066f6fa6fa988f2e3a9d6fe35fa0d3666c652dac35cabaeebff3738a4e67f68f"}],[{"offset":22,"hash":"232089a6f77c566151bc4701fda394b5cc5bf17073140d46a73c4c3ed0a7b911"}],[{"offset":10,"hash":"c639b3a6ce127f67dbd01c7331a6fca62a4b429830387bd68ac6ac05e162116d"}],[{"offset":4,"hash":"730cec44be97881530947d782bb328d25f1122fdae206296937fffb03e936d48"}],[{"offset":3,"hash":"28b681f8ab8db0fa4d5d20cb1532b95184a155346b0b8447bde580b2406d51e6"}],[{"offset":0,"hash":"c49a18028e230dd1439b26794c08c339506f24a450f067c4facd4e0d5a346490"}],[{"offset":1,"hash":"0ba57d1b1fad6874de3640c01088e3dedad3507e5b3a3102b9a8a8055f3df88b"}],[{"offset":1,"hash":"c830edebe5565c19ba584ec73d49129344d17539f322509b7c314ae641c2fcdb"}],[{"offset":1,"hash":"ff62d5ed2a94eb93a2b7d084b8f15b12083573896b6a58cf871507e3352c75f5"}]]},"header":{"version":1040187392,"previousHash":"00000000000000000d9f6889dd6743500adee204ea25d8a57225ecd48b111769","merkleRoot":"59c1efd79fae0d9c29dd8da63f8eeec0aadde048f4491c6bfa324fcfd537156d","time":1739329877,"bits":403818359,"nonce":596827153,"height":883637,"hash":"0000000000000000060ac8d63b78d41f58c9aba0b09f81db7d51fa4905a47263"}}'
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
{
|
|
77
|
+
const r = await wocMain.getMerklePath('1'.repeat(64), services)
|
|
78
|
+
const s = JSON.stringify(r)
|
|
79
|
+
expect(s).toBe('{"name":"WoCTsc"}')
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
test('4 updateBsvExchangeRate', async () => {
|
|
84
|
+
{
|
|
85
|
+
const r = await wocMain.updateBsvExchangeRate()
|
|
86
|
+
expect(r.base).toBe('USD')
|
|
87
|
+
expect(r.rate).toBeGreaterThan(0)
|
|
88
|
+
expect(r.timestamp).toBeTruthy()
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
test('5 getTxPropagation testnet', async () => {
|
|
93
|
+
return
|
|
94
|
+
// throwing internal server error 500 when tested.
|
|
95
|
+
const count = await wocTest.getTxPropagation(
|
|
96
|
+
'7e5b797b86abd31a654bf296900d6cb14d04ef0811568ff4675494af2d92166b'
|
|
97
|
+
)
|
|
98
|
+
expect(count > 0)
|
|
99
|
+
|
|
100
|
+
expect((await wocTest.getTxPropagation('1'.repeat(64))) === 0)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test('6 getTxPropagation mainnet', async () => {})
|
|
104
|
+
|
|
105
|
+
test.skip('7 postRawTx testnet', async () => {
|
|
106
|
+
if (Setup.noEnv('test')) return
|
|
107
|
+
const woc = wocTest
|
|
108
|
+
const c = await _tu.createNoSendTxPair('test')
|
|
109
|
+
|
|
110
|
+
const rawTxDo = c.beef.findTxid(c.txidDo)!.tx!.toHex()
|
|
111
|
+
const rawTxUndo = c.beef.findTxid(c.txidUndo)!.tx!.toHex()
|
|
112
|
+
|
|
113
|
+
const txidDo = await woc.postRawTx(rawTxDo)
|
|
114
|
+
expect(txidDo).toBe(c.txidDo)
|
|
115
|
+
|
|
116
|
+
await wait(1000)
|
|
117
|
+
|
|
118
|
+
const txidUndo = await woc.postRawTx(rawTxUndo)
|
|
119
|
+
expect(txidUndo).toBe(c.txidUndo)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
test.skip('7a nosend cleanup testnet', async () => {
|
|
123
|
+
const c = await _tu.createWalletSetupEnv('test')
|
|
124
|
+
|
|
125
|
+
const actions = await c.wallet.listActions({ labels: [], limit: 1000 })
|
|
126
|
+
const nosends = actions.actions.filter(a => a.status === 'nosend')
|
|
127
|
+
|
|
128
|
+
const refs = ['yUfgNVaFcBNyP2Xv']
|
|
129
|
+
for (const ref of refs) {
|
|
130
|
+
try {
|
|
131
|
+
await c.wallet.abortAction({ reference: ref })
|
|
132
|
+
} catch (eu: unknown) {
|
|
133
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
test.skip('8 postRawTx mainnet', async () => {
|
|
139
|
+
if (Setup.noEnv('main')) return
|
|
140
|
+
const woc = wocMain
|
|
141
|
+
const c = await _tu.createNoSendTxPair('main')
|
|
142
|
+
|
|
143
|
+
const rawTxDo = c.beef.findTxid(c.txidDo)!.tx!.toHex()
|
|
144
|
+
const rawTxUndo = c.beef.findTxid(c.txidUndo)!.tx!.toHex()
|
|
145
|
+
|
|
146
|
+
const txidDo = await woc.postRawTx(rawTxDo)
|
|
147
|
+
expect(txidDo).toBe(c.txidDo)
|
|
148
|
+
|
|
149
|
+
/*
|
|
150
|
+
try {
|
|
151
|
+
// This method is broken as of 2025-02-16
|
|
152
|
+
const count = await woc.getTxPropagation(txidDo)
|
|
153
|
+
} catch {}
|
|
154
|
+
// getRawTx returns undefined for unmined transactions, sometimes.
|
|
155
|
+
let rawTx = await woc.getRawTx(txidDo)
|
|
156
|
+
let i = 0
|
|
157
|
+
while (!rawTx) {
|
|
158
|
+
console.log(`${i++} waiting for WhatsOnChain to acknowledge new transaction exists.`)
|
|
159
|
+
await wait(5000)
|
|
160
|
+
rawTx = await woc.getRawTx(txidDo)
|
|
161
|
+
}
|
|
162
|
+
expect(rawTx).toBe(rawTxDo)
|
|
163
|
+
*/
|
|
164
|
+
|
|
165
|
+
// allow for propagation...
|
|
166
|
+
await wait(1000)
|
|
167
|
+
|
|
168
|
+
const txidUndo = await woc.postRawTx(rawTxUndo)
|
|
169
|
+
expect(txidUndo).toBe(c.txidUndo)
|
|
170
|
+
|
|
171
|
+
await wait(1000)
|
|
172
|
+
|
|
173
|
+
// Confirm double spend detection.
|
|
174
|
+
// 'The rawTx parameter must be valid. unexpected response code 500: 258: txn-mempool-conflict'
|
|
175
|
+
// 'The rawTx parameter must be valid. unexpected response code 500: Missing inputs'
|
|
176
|
+
try {
|
|
177
|
+
await woc.postRawTx(c.doubleSpendTx.toHex())
|
|
178
|
+
expect(false)
|
|
179
|
+
} catch (eu: unknown) {
|
|
180
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
181
|
+
expect(
|
|
182
|
+
e.message ===
|
|
183
|
+
'The rawTx parameter must be valid. unexpected response code 500: 258: txn-mempool-conflict' ||
|
|
184
|
+
'The rawTx parameter must be valid. unexpected response code 500: Missing inputs'
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
test.skip('8a nosend cleanup mainnet', async () => {
|
|
190
|
+
const c = await _tu.createWalletSetupEnv('main')
|
|
191
|
+
|
|
192
|
+
const actions = await c.wallet.listActions({ labels: [], limit: 1000 })
|
|
193
|
+
const nosends = actions.actions.filter(a => a.status === 'nosend')
|
|
194
|
+
// No way to get from actions to reference string values for use with abortAction...
|
|
195
|
+
|
|
196
|
+
if (c['activeStorage']) {
|
|
197
|
+
const s = c['activeStorage'] as StorageKnex
|
|
198
|
+
const userId = c['userId'] as number
|
|
199
|
+
const txs = await s.findTransactions({
|
|
200
|
+
partial: { userId, status: 'nosend' }
|
|
201
|
+
})
|
|
202
|
+
const refs = txs.map(tx => tx.reference)
|
|
203
|
+
for (const ref of refs) {
|
|
204
|
+
try {
|
|
205
|
+
await c.wallet.abortAction({ reference: ref })
|
|
206
|
+
} catch (eu: unknown) {
|
|
207
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
await c.wallet.destroy()
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
test.skip('8b run monitor mainnet', async () => {
|
|
216
|
+
if (Setup.noEnv('main')) return
|
|
217
|
+
if (!Setup.getEnv('main').filePath) return
|
|
218
|
+
|
|
219
|
+
// Only run if `Setup` style .env is present with a sqlite filePath...
|
|
220
|
+
|
|
221
|
+
const c = await _tu.createWalletSetupEnv('main')
|
|
222
|
+
|
|
223
|
+
await c.monitor.runOnce()
|
|
224
|
+
|
|
225
|
+
await c.wallet.destroy()
|
|
226
|
+
})
|
|
227
|
+
})
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
makeAtomicBeef,
|
|
11
11
|
PendingSignAction,
|
|
12
12
|
PendingStorageInput,
|
|
13
|
-
|
|
13
|
+
ScriptTemplateBRC29,
|
|
14
14
|
sdk,
|
|
15
15
|
verifyTruthy,
|
|
16
16
|
Wallet
|
|
@@ -100,7 +100,7 @@ function makeChangeLock(
|
|
|
100
100
|
): Script {
|
|
101
101
|
const derivationPrefix = dctr.derivationPrefix
|
|
102
102
|
const derivationSuffix = verifyTruthy(out.derivationSuffix)
|
|
103
|
-
const sabppp = new
|
|
103
|
+
const sabppp = new ScriptTemplateBRC29({
|
|
104
104
|
derivationPrefix,
|
|
105
105
|
derivationSuffix,
|
|
106
106
|
keyDeriver: wallet.keyDeriver
|
|
@@ -149,7 +149,7 @@ export async function completeSignedTransaction(
|
|
|
149
149
|
// Insert SABPPP unlock templates for storage signed inputs
|
|
150
150
|
/////////////////////
|
|
151
151
|
for (const pdi of prior.pdi) {
|
|
152
|
-
const sabppp = new
|
|
152
|
+
const sabppp = new ScriptTemplateBRC29({
|
|
153
153
|
derivationPrefix: pdi.derivationPrefix,
|
|
154
154
|
derivationSuffix: pdi.derivationSuffix,
|
|
155
155
|
keyDeriver: wallet.keyDeriver
|
|
@@ -321,7 +321,7 @@ function buildSignableTransaction(
|
|
|
321
321
|
}
|
|
322
322
|
tx.addInput(inputToAdd)
|
|
323
323
|
} else {
|
|
324
|
-
// Type2: SABPPP protocol inputs which are signed using
|
|
324
|
+
// Type2: SABPPP protocol inputs which are signed using ScriptTemplateBRC29.
|
|
325
325
|
if (storageInput.type !== 'P2PKH')
|
|
326
326
|
throw new sdk.WERR_INVALID_PARAMETER(
|
|
327
327
|
'type',
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
asBsvSdkScript,
|
|
11
11
|
PendingSignAction,
|
|
12
|
-
|
|
12
|
+
ScriptTemplateBRC29,
|
|
13
13
|
sdk,
|
|
14
14
|
Wallet
|
|
15
15
|
} from '../../index.client'
|
|
@@ -92,7 +92,7 @@ export async function completeSignedTransaction(
|
|
|
92
92
|
// Insert SABPPP unlock templates for wallet signed inputs
|
|
93
93
|
/////////////////////
|
|
94
94
|
for (const pdi of prior.pdi) {
|
|
95
|
-
const sabppp = new
|
|
95
|
+
const sabppp = new ScriptTemplateBRC29({
|
|
96
96
|
derivationPrefix: pdi.derivationPrefix,
|
|
97
97
|
derivationSuffix: pdi.derivationSuffix,
|
|
98
98
|
keyDeriver: wallet.keyDeriver
|