@bsv/wallet-toolbox 1.3.27 → 1.3.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/docs/client.md +550 -172
  3. package/docs/monitor.md +25 -7
  4. package/docs/services.md +134 -23
  5. package/docs/storage.md +53 -22
  6. package/docs/wallet.md +550 -172
  7. package/mobile/out/src/monitor/Monitor.js +1 -1
  8. package/mobile/out/src/monitor/Monitor.js.map +1 -1
  9. package/mobile/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
  10. package/mobile/out/src/services/ServiceCollection.d.ts +2 -2
  11. package/mobile/out/src/services/ServiceCollection.d.ts.map +1 -1
  12. package/mobile/out/src/services/ServiceCollection.js.map +1 -1
  13. package/mobile/out/src/services/Services.d.ts.map +1 -1
  14. package/mobile/out/src/services/Services.js.map +1 -1
  15. package/mobile/out/src/services/createDefaultWalletServicesOptions.d.ts.map +1 -1
  16. package/mobile/out/src/services/createDefaultWalletServicesOptions.js +1 -3
  17. package/mobile/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
  18. package/mobile/out/src/signer/methods/completeSignedTransaction.d.ts +10 -0
  19. package/mobile/out/src/signer/methods/completeSignedTransaction.d.ts.map +1 -0
  20. package/mobile/out/src/signer/methods/completeSignedTransaction.js +104 -0
  21. package/mobile/out/src/signer/methods/completeSignedTransaction.js.map +1 -0
  22. package/mobile/out/src/signer/methods/createAction.d.ts +2 -3
  23. package/mobile/out/src/signer/methods/createAction.d.ts.map +1 -1
  24. package/mobile/out/src/signer/methods/createAction.js +8 -46
  25. package/mobile/out/src/signer/methods/createAction.js.map +1 -1
  26. package/mobile/out/src/signer/methods/signAction.d.ts +2 -4
  27. package/mobile/out/src/signer/methods/signAction.d.ts.map +1 -1
  28. package/mobile/out/src/signer/methods/signAction.js +7 -54
  29. package/mobile/out/src/signer/methods/signAction.js.map +1 -1
  30. package/mobile/out/src/storage/methods/createAction.d.ts.map +1 -1
  31. package/mobile/out/src/storage/methods/createAction.js.map +1 -1
  32. package/mobile/package-lock.json +2 -2
  33. package/mobile/package.json +1 -1
  34. package/out/src/monitor/Monitor.js +1 -1
  35. package/out/src/monitor/Monitor.js.map +1 -1
  36. package/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
  37. package/out/src/services/ServiceCollection.d.ts +2 -2
  38. package/out/src/services/ServiceCollection.d.ts.map +1 -1
  39. package/out/src/services/ServiceCollection.js.map +1 -1
  40. package/out/src/services/Services.d.ts.map +1 -1
  41. package/out/src/services/Services.js.map +1 -1
  42. package/out/src/services/createDefaultWalletServicesOptions.d.ts.map +1 -1
  43. package/out/src/services/createDefaultWalletServicesOptions.js +1 -3
  44. package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
  45. package/out/src/signer/methods/completeSignedTransaction.d.ts +10 -0
  46. package/out/src/signer/methods/completeSignedTransaction.d.ts.map +1 -0
  47. package/out/src/signer/methods/completeSignedTransaction.js +104 -0
  48. package/out/src/signer/methods/completeSignedTransaction.js.map +1 -0
  49. package/out/src/signer/methods/createAction.d.ts +2 -3
  50. package/out/src/signer/methods/createAction.d.ts.map +1 -1
  51. package/out/src/signer/methods/createAction.js +8 -46
  52. package/out/src/signer/methods/createAction.js.map +1 -1
  53. package/out/src/signer/methods/signAction.d.ts +2 -4
  54. package/out/src/signer/methods/signAction.d.ts.map +1 -1
  55. package/out/src/signer/methods/signAction.js +7 -54
  56. package/out/src/signer/methods/signAction.js.map +1 -1
  57. package/out/src/storage/StorageKnex.d.ts.map +1 -1
  58. package/out/src/storage/StorageKnex.js +7 -2
  59. package/out/src/storage/StorageKnex.js.map +1 -1
  60. package/out/src/storage/methods/createAction.d.ts.map +1 -1
  61. package/out/src/storage/methods/createAction.js.map +1 -1
  62. package/out/test/Wallet/support/operations.man.test.js +23 -5
  63. package/out/test/Wallet/support/operations.man.test.js.map +1 -1
  64. package/out/test/wallet/action/createAction2.test.d.ts.map +1 -1
  65. package/out/test/wallet/action/createAction2.test.js +1 -0
  66. package/out/test/wallet/action/createAction2.test.js.map +1 -1
  67. package/out/tsconfig.all.tsbuildinfo +1 -1
  68. package/package.json +1 -1
  69. package/src/monitor/Monitor.ts +1 -1
  70. package/src/sdk/WalletServices.interfaces.ts +2 -2
  71. package/src/services/ServiceCollection.ts +9 -6
  72. package/src/services/Services.ts +13 -25
  73. package/src/services/createDefaultWalletServicesOptions.ts +1 -4
  74. package/src/signer/methods/completeSignedTransaction.ts +115 -0
  75. package/src/signer/methods/createAction.ts +9 -68
  76. package/src/signer/methods/signAction.ts +11 -78
  77. package/src/storage/StorageKnex.ts +45 -14
  78. package/src/storage/StorageProvider.ts +1 -1
  79. package/src/storage/methods/createAction.ts +4 -1
  80. package/test/Wallet/support/operations.man.test.ts +29 -10
  81. package/test/wallet/action/createAction2.test.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/wallet-toolbox",
3
- "version": "1.3.27",
3
+ "version": "1.3.29",
4
4
  "description": "BRC100 conforming wallet, wallet storage and wallet signer components",
5
5
  "main": "./out/src/index.js",
6
6
  "types": "./out/src/index.d.ts",
@@ -221,7 +221,7 @@ export class Monitor {
221
221
  if (this.storage.getActive().isStorageProvider()) {
222
222
  const log = await ttr.runTask()
223
223
  if (log && log.length > 0) {
224
- console.log(`Task${ttr.name} ${log}`)
224
+ console.log(`Task${ttr.name} ${log.slice(0, 80)}`)
225
225
  await this.logEvent(ttr.name, log)
226
226
  }
227
227
  }
@@ -173,7 +173,7 @@ export interface WalletServices {
173
173
  * @param reset if true, ends current interval and starts a new one.
174
174
  * @returns a history of service calls made to the configured services.
175
175
  */
176
- getServicesCallHistory(reset?: boolean) : ServicesCallHistory
176
+ getServicesCallHistory(reset?: boolean): ServicesCallHistory
177
177
  }
178
178
 
179
179
  export type ScriptHashFormat = 'hashLE' | 'hashBE' | 'script'
@@ -539,7 +539,7 @@ export interface ServiceCall {
539
539
  /**
540
540
  * Error code and message iff success is false and a exception was thrown.
541
541
  */
542
- error?: { message: string, code: string }
542
+ error?: { message: string; code: string }
543
543
  }
544
544
 
545
545
  /**
@@ -1,5 +1,5 @@
1
- import { WalletError } from "../sdk/WalletError";
2
- import { ProviderCallHistory, ServiceCallHistory } from "../sdk/WalletServices.interfaces";
1
+ import { WalletError } from '../sdk/WalletError'
2
+ import { ProviderCallHistory, ServiceCallHistory } from '../sdk/WalletServices.interfaces'
3
3
 
4
4
  const MAX_RESET_COUNTS = 32
5
5
  const MAX_CALL_HISTORY = 32
@@ -14,7 +14,10 @@ export class ServiceCollection<T> {
14
14
  readonly since: Date
15
15
  _historyByProvider: Record<string, ProviderCallHistory> = {}
16
16
 
17
- constructor(public serviceName: string, services?: { name: string; service: T }[]) {
17
+ constructor(
18
+ public serviceName: string,
19
+ services?: { name: string; service: T }[]
20
+ ) {
18
21
  this.services = services || []
19
22
  this._index = 0
20
23
  this.since = new Date()
@@ -92,7 +95,7 @@ export class ServiceCollection<T> {
92
95
  this._historyByProvider[providerName] = h
93
96
  }
94
97
  h.calls.unshift(call)
95
- h.calls = h.calls.slice(0,MAX_CALL_HISTORY)
98
+ h.calls = h.calls.slice(0, MAX_CALL_HISTORY)
96
99
  h.totalCounts.until = now
97
100
  h.resetCounts[0].until = now
98
101
  return h
@@ -220,7 +223,7 @@ export interface ServiceCall {
220
223
  /**
221
224
  * Error code and message iff success is false and a exception was thrown.
222
225
  */
223
- error?: { message: string, code: string }
226
+ error?: { message: string; code: string }
224
227
  }
225
228
 
226
229
  export interface ServiceToCall<T> {
@@ -228,4 +231,4 @@ export interface ServiceToCall<T> {
228
231
  serviceName: string
229
232
  service: T
230
233
  call: ServiceCall
231
- }
234
+ }
@@ -84,7 +84,7 @@ export class Services implements sdk.WalletServices {
84
84
  .add({ name: 'exchangeratesapi', service: updateExchangeratesapi })
85
85
  }
86
86
 
87
- getServicesCallHistory(reset?: boolean) : ServicesCallHistory {
87
+ getServicesCallHistory(reset?: boolean): ServicesCallHistory {
88
88
  return {
89
89
  version: 2,
90
90
  getMerklePath: this.getMerklePathServices.getServiceCallHistory(reset),
@@ -155,10 +155,8 @@ export class Services implements sdk.WalletServices {
155
155
  r0 = r
156
156
  break
157
157
  } else {
158
- if (r.error)
159
- services.addServiceCallError(stc, r.error)
160
- else
161
- services.addServiceCallFailure(stc)
158
+ if (r.error) services.addServiceCallError(stc, r.error)
159
+ else services.addServiceCallFailure(stc)
162
160
  }
163
161
  } catch (eu: unknown) {
164
162
  const e = sdk.WalletError.fromUnknown(eu)
@@ -217,10 +215,8 @@ export class Services implements sdk.WalletServices {
217
215
  r0 = r
218
216
  break
219
217
  } else {
220
- if (r.error)
221
- services.addServiceCallError(stc, r.error)
222
- else
223
- services.addServiceCallFailure(stc)
218
+ if (r.error) services.addServiceCallError(stc, r.error)
219
+ else services.addServiceCallFailure(stc)
224
220
  }
225
221
  } catch (eu: unknown) {
226
222
  const e = sdk.WalletError.fromUnknown(eu)
@@ -253,10 +249,8 @@ export class Services implements sdk.WalletServices {
253
249
  r0 = r
254
250
  break
255
251
  } else {
256
- if (r.error)
257
- services.addServiceCallError(stc, r.error)
258
- else
259
- services.addServiceCallFailure(stc)
252
+ if (r.error) services.addServiceCallError(stc, r.error)
253
+ else services.addServiceCallFailure(stc)
260
254
  }
261
255
  } catch (eu: unknown) {
262
256
  const e = sdk.WalletError.fromUnknown(eu)
@@ -319,17 +313,13 @@ export class Services implements sdk.WalletServices {
319
313
  r.rawTx = undefined
320
314
  }
321
315
 
322
- if (r.error)
323
- services.addServiceCallError(stc, r.error)
324
- else if (!r.rawTx)
325
- services.addServiceCallSuccess(stc, `not found`)
326
- else
327
- services.addServiceCallFailure(stc)
316
+ if (r.error) services.addServiceCallError(stc, r.error)
317
+ else if (!r.rawTx) services.addServiceCallSuccess(stc, `not found`)
318
+ else services.addServiceCallFailure(stc)
328
319
 
329
320
  if (r.error && !r0.error && !r0.rawTx)
330
321
  // If we have an error and didn't before...
331
322
  r0.error = r.error
332
-
333
323
  } catch (eu: unknown) {
334
324
  const e = sdk.WalletError.fromUnknown(eu)
335
325
  services.addServiceCallError(stc, e)
@@ -401,11 +391,9 @@ export class Services implements sdk.WalletServices {
401
391
  services.addServiceCallSuccess(stc)
402
392
  break
403
393
  }
404
-
405
- if (r.error)
406
- services.addServiceCallError(stc, r.error)
407
- else
408
- services.addServiceCallFailure(stc)
394
+
395
+ if (r.error) services.addServiceCallError(stc, r.error)
396
+ else services.addServiceCallFailure(stc)
409
397
 
410
398
  if (r.error && !r0.error) {
411
399
  // If we have an error and didn't before...
@@ -7,10 +7,7 @@ export function createDefaultWalletServicesOptions(chain: sdk.Chain): sdk.Wallet
7
7
  chain === 'main'
8
8
  ? 'mainnet_9596de07e92300c6287e4393594ae39c' // no plan
9
9
  : 'testnet_0e6cf72133b43ea2d7861da2a38684e3' // personal "starter" key
10
- const gorillaPoolApiKey =
11
- chain === 'main'
12
- ? ''
13
- : ''
10
+ const gorillaPoolApiKey = chain === 'main' ? '' : ''
14
11
 
15
12
  const o: sdk.WalletServicesOptions = {
16
13
  chain,
@@ -0,0 +1,115 @@
1
+ import { Beef, SignActionResult, SignActionSpend, Spend, Transaction } from '@bsv/sdk'
2
+ import { PendingSignAction, Wallet } from '../../Wallet'
3
+ import { asBsvSdkScript, ScriptTemplateBRC29, sdk } from '../../index.client'
4
+ import { WalletError, WERR_INTERNAL, WERR_INVALID_PARAMETER } from '../../sdk'
5
+
6
+ export async function completeSignedTransaction(
7
+ prior: PendingSignAction,
8
+ spends: Record<number, SignActionSpend>,
9
+ wallet: Wallet
10
+ ): Promise<Transaction> {
11
+ /////////////////////
12
+ // Insert the user provided unlocking scripts from "spends" arg
13
+ /////////////////////
14
+ for (const [key, spend] of Object.entries(spends)) {
15
+ const vin = Number(key)
16
+ const createInput = prior.args.inputs[vin]
17
+ const input = prior.tx.inputs[vin]
18
+ if (!createInput || !input || createInput.unlockingScript || !Number.isInteger(createInput.unlockingScriptLength))
19
+ throw new sdk.WERR_INVALID_PARAMETER(
20
+ 'args',
21
+ `spend does not correspond to prior input with valid unlockingScriptLength.`
22
+ )
23
+ if (spend.unlockingScript.length / 2 > createInput.unlockingScriptLength!)
24
+ throw new sdk.WERR_INVALID_PARAMETER(
25
+ 'args',
26
+ `spend unlockingScript length ${spend.unlockingScript.length} exceeds expected length ${createInput.unlockingScriptLength}`
27
+ )
28
+ input.unlockingScript = asBsvSdkScript(spend.unlockingScript)
29
+ if (spend.sequenceNumber !== undefined) input.sequence = spend.sequenceNumber
30
+ }
31
+
32
+ const results = {
33
+ sdk: <SignActionResult>{}
34
+ }
35
+
36
+ /////////////////////
37
+ // Insert SABPPP unlock templates for wallet signed inputs
38
+ /////////////////////
39
+ for (const pdi of prior.pdi) {
40
+ const sabppp = new ScriptTemplateBRC29({
41
+ derivationPrefix: pdi.derivationPrefix,
42
+ derivationSuffix: pdi.derivationSuffix,
43
+ keyDeriver: wallet.keyDeriver
44
+ })
45
+ const keys = wallet.getClientChangeKeyPair()
46
+ const lockerPrivKey = keys.privateKey
47
+ const unlockerPubKey = pdi.unlockerPubKey || keys.publicKey
48
+ const sourceSatoshis = pdi.sourceSatoshis
49
+ const lockingScript = asBsvSdkScript(pdi.lockingScript)
50
+ const unlockTemplate = sabppp.unlock(lockerPrivKey, unlockerPubKey, sourceSatoshis, lockingScript)
51
+ const input = prior.tx.inputs[pdi.vin]
52
+ input.unlockingScriptTemplate = unlockTemplate
53
+ }
54
+
55
+ /////////////////////
56
+ // Sign wallet signed inputs making transaction fully valid.
57
+ /////////////////////
58
+ await prior.tx.sign()
59
+
60
+ return prior.tx
61
+ }
62
+
63
+ /**
64
+ * @param txid The TXID of a transaction in the beef for which all unlocking scripts must be valid.
65
+ * @param beef Must contain transactions for txid and all its inputs.
66
+ * @throws WERR_INVALID_PARAMETER if any unlocking script is invalid, if sourceTXID is invalid, if beef doesn't contain required transactions.
67
+ */
68
+ export function verifyUnlockScripts(txid: string, beef: Beef): void {
69
+ const tx = beef.findTxid(txid)?.tx
70
+ if (!tx) throw new WERR_INVALID_PARAMETER(`txid`, `contained in beef, txid ${txid}`)
71
+
72
+ for (let i = 0; i < tx.inputs.length; i++) {
73
+ const input = tx.inputs[i]
74
+ if (!input.sourceTXID) throw new WERR_INVALID_PARAMETER(`inputs[${i}].sourceTXID`, `valid`)
75
+ if (!input.unlockingScript) throw new WERR_INVALID_PARAMETER(`inputs[${i}].unlockingScript`, `valid`)
76
+ input.sourceTransaction = beef.findTxid(input.sourceTXID)?.tx
77
+ if (!input.sourceTransaction) {
78
+ // The beef doesn't contain all the source transactions only if advanced features
79
+ // such as knownTxids are used.
80
+ // Skip unlock script checks.
81
+ return
82
+ // throw new WERR_INVALID_PARAMETER(`inputs[${i}].sourceTXID`, `contained in beef`)
83
+ }
84
+ }
85
+
86
+ for (let i = 0; i < tx.inputs.length; i++) {
87
+ const input = tx.inputs[i]
88
+ const sourceOutput = input.sourceTransaction!.outputs[input.sourceOutputIndex]
89
+
90
+ const otherInputs = tx.inputs.filter((_, idx) => idx !== i)
91
+
92
+ const spend = new Spend({
93
+ sourceTXID: input.sourceTXID!,
94
+ sourceOutputIndex: input.sourceOutputIndex,
95
+ lockingScript: sourceOutput.lockingScript,
96
+ sourceSatoshis: sourceOutput.satoshis ?? 0,
97
+ transactionVersion: tx.version,
98
+ otherInputs,
99
+ unlockingScript: input.unlockingScript!,
100
+ inputSequence: input.sequence ?? 0,
101
+ inputIndex: i,
102
+ outputs: tx.outputs,
103
+ lockTime: tx.lockTime
104
+ })
105
+
106
+ try {
107
+ const spendValid = spend.validate()
108
+
109
+ if (!spendValid) throw new WERR_INVALID_PARAMETER(`inputs[${i}].unlockScript`, `valid`)
110
+ } catch (eu: unknown) {
111
+ const e = WalletError.fromUnknown(eu)
112
+ throw new WERR_INVALID_PARAMETER(`inputs[${i}].unlockScript`, `valid. ${e.message}`)
113
+ }
114
+ }
115
+ }
@@ -5,22 +5,13 @@ import {
5
5
  OutpointString,
6
6
  SendWithResult,
7
7
  SignableTransaction,
8
- SignActionResult,
9
- SignActionSpend,
10
8
  TXIDHexString
11
9
  } from '@bsv/sdk'
12
10
  import { Script, Transaction } from '@bsv/sdk'
13
- import {
14
- asBsvSdkScript,
15
- makeAtomicBeef,
16
- PendingSignAction,
17
- ScriptTemplateBRC29,
18
- sdk,
19
- verifyTruthy,
20
- Wallet
21
- } from '../../index.client'
11
+ import { makeAtomicBeef, PendingSignAction, ScriptTemplateBRC29, sdk, verifyTruthy, Wallet } from '../../index.client'
22
12
  import { buildSignableTransaction } from './buildSignableTransaction'
23
13
  import { ReviewActionResult } from '../../sdk/WalletStorage.interfaces'
14
+ import { completeSignedTransaction, verifyUnlockScripts } from './completeSignedTransaction'
24
15
 
25
16
  export interface CreateActionResultX extends CreateActionResult {
26
17
  txid?: TXIDHexString
@@ -50,8 +41,14 @@ export async function createAction(
50
41
  prior.tx = await completeSignedTransaction(prior, {}, wallet)
51
42
 
52
43
  r.txid = prior.tx.id('hex')
44
+ const beef = new Beef()
45
+ if (prior.dcr.inputBeef) beef.mergeBeef(prior.dcr.inputBeef)
46
+ beef.mergeTransaction(prior.tx)
47
+
48
+ verifyUnlockScripts(r.txid, beef)
49
+
53
50
  r.noSendChange = prior.dcr.noSendChangeOutputVouts?.map(vout => `${r.txid}.${vout}`)
54
- if (!vargs.options.returnTXIDOnly) r.tx = makeAtomicBeef(prior.tx, prior.dcr.inputBeef!)
51
+ if (!vargs.options.returnTXIDOnly) r.tx = beef.toBinaryAtomic(r.txid)
55
52
  }
56
53
 
57
54
  const { sendWithResults, notDelayedResults } = await processAction(prior, wallet, auth, vargs)
@@ -131,62 +128,6 @@ export function makeChangeLock(
131
128
  return lockingScript
132
129
  }
133
130
 
134
- export async function completeSignedTransaction(
135
- prior: PendingSignAction,
136
- spends: Record<number, SignActionSpend>,
137
- wallet: Wallet
138
- ): Promise<Transaction> {
139
- /////////////////////
140
- // Insert the user provided unlocking scripts from "spends" arg
141
- /////////////////////
142
- for (const [key, spend] of Object.entries(spends)) {
143
- const vin = Number(key)
144
- const createInput = prior.args.inputs[vin]
145
- const input = prior.tx.inputs[vin]
146
- if (!createInput || !input || createInput.unlockingScript || !Number.isInteger(createInput.unlockingScriptLength))
147
- throw new sdk.WERR_INVALID_PARAMETER(
148
- 'args',
149
- `spend does not correspond to prior input with valid unlockingScriptLength.`
150
- )
151
- if (spend.unlockingScript.length / 2 > createInput.unlockingScriptLength!)
152
- throw new sdk.WERR_INVALID_PARAMETER(
153
- 'args',
154
- `spend unlockingScript length ${spend.unlockingScript.length} exceeds expected length ${createInput.unlockingScriptLength}`
155
- )
156
- input.unlockingScript = asBsvSdkScript(spend.unlockingScript)
157
- if (spend.sequenceNumber !== undefined) input.sequence = spend.sequenceNumber
158
- }
159
-
160
- const results = {
161
- sdk: <SignActionResult>{}
162
- }
163
-
164
- /////////////////////
165
- // Insert SABPPP unlock templates for storage signed inputs
166
- /////////////////////
167
- for (const pdi of prior.pdi) {
168
- const sabppp = new ScriptTemplateBRC29({
169
- derivationPrefix: pdi.derivationPrefix,
170
- derivationSuffix: pdi.derivationSuffix,
171
- keyDeriver: wallet.keyDeriver
172
- })
173
- const keys = wallet.getClientChangeKeyPair()
174
- const lockerPrivKey = keys.privateKey
175
- const unlockerPubKey = pdi.unlockerPubKey || keys.publicKey
176
- const sourceSatoshis = pdi.sourceSatoshis
177
- const lockingScript = asBsvSdkScript(pdi.lockingScript)
178
- const unlockTemplate = sabppp.unlock(lockerPrivKey, unlockerPubKey, sourceSatoshis, lockingScript)
179
- const input = prior.tx.inputs[pdi.vin]
180
- input.unlockingScriptTemplate = unlockTemplate
181
- }
182
-
183
- /////////////////////
184
- // Sign storage signed inputs making transaction fully valid.
185
- /////////////////////
186
- await prior.tx.sign()
187
-
188
- return prior.tx
189
- }
190
131
  function removeUnlockScripts(args: sdk.ValidCreateActionArgs) {
191
132
  let storageArgs = args
192
133
  if (!storageArgs.inputs.every(i => i.unlockingScript === undefined)) {
@@ -1,20 +1,10 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */
2
-
3
- import {
4
- AtomicBEEF,
5
- Beef,
6
- Transaction as BsvTransaction,
7
- SendWithResult,
8
- SignActionArgs,
9
- SignActionOptions,
10
- SignActionResult,
11
- SignActionSpend,
12
- TXIDHexString
13
- } from '@bsv/sdk'
14
- import { asBsvSdkScript, PendingSignAction, ScriptTemplateBRC29, sdk, Wallet } from '../../index.client'
1
+ import { AtomicBEEF, Beef, SendWithResult, SignActionArgs, SignActionResult, TXIDHexString } from '@bsv/sdk'
2
+ import { sdk, Wallet } from '../../index.client'
15
3
  import { processAction } from './createAction'
16
4
  import { ReviewActionResult } from '../../sdk/WalletStorage.interfaces'
17
5
  import { validateSignActionArgs } from '../../sdk'
6
+ import { completeSignedTransaction, verifyUnlockScripts } from './completeSignedTransaction'
7
+ import { makeAtomicBeef } from '../../utility/utilityHelpers'
18
8
 
19
9
  export interface SignActionResultX extends SignActionResult {
20
10
  txid?: TXIDHexString
@@ -35,9 +25,15 @@ export async function signAction(wallet: Wallet, auth: sdk.AuthId, args: SignAct
35
25
 
36
26
  const { sendWithResults, notDelayedResults } = await processAction(prior, wallet, auth, vargs)
37
27
 
28
+ const txid = prior.tx.id('hex')
29
+ const beef = Beef.fromBinary(prior.dcr.inputBeef)
30
+ beef.mergeTransaction(prior.tx)
31
+
32
+ verifyUnlockScripts(txid, beef)
33
+
38
34
  const r: SignActionResultX = {
39
35
  txid: prior.tx.id('hex'),
40
- tx: vargs.options.returnTXIDOnly ? undefined : makeAtomicBeef(prior.tx, prior.dcr.inputBeef),
36
+ tx: vargs.options.returnTXIDOnly ? undefined : beef.toBinaryAtomic(txid),
41
37
  sendWithResults,
42
38
  notDelayedResults
43
39
  }
@@ -45,69 +41,6 @@ export async function signAction(wallet: Wallet, auth: sdk.AuthId, args: SignAct
45
41
  return r
46
42
  }
47
43
 
48
- export function makeAtomicBeef(tx: BsvTransaction, beef: number[] | Beef): number[] {
49
- if (Array.isArray(beef)) beef = Beef.fromBinary(beef)
50
- beef.mergeTransaction(tx)
51
- return beef.toBinaryAtomic(tx.id('hex'))
52
- }
53
-
54
- export async function completeSignedTransaction(
55
- prior: PendingSignAction,
56
- spends: Record<number, SignActionSpend>,
57
- wallet: Wallet
58
- ): Promise<BsvTransaction> {
59
- /////////////////////
60
- // Insert the user provided unlocking scripts from "spends" arg
61
- /////////////////////
62
- for (const [key, spend] of Object.entries(spends)) {
63
- const vin = Number(key)
64
- const createInput = prior.args.inputs[vin]
65
- const input = prior.tx.inputs[vin]
66
- if (!createInput || !input || createInput.unlockingScript || !Number.isInteger(createInput.unlockingScriptLength))
67
- throw new sdk.WERR_INVALID_PARAMETER(
68
- 'args',
69
- `spend does not correspond to prior input with valid unlockingScriptLength.`
70
- )
71
- if (spend.unlockingScript.length / 2 > createInput.unlockingScriptLength!)
72
- throw new sdk.WERR_INVALID_PARAMETER(
73
- 'args',
74
- `spend unlockingScript length ${spend.unlockingScript.length} exceeds expected length ${createInput.unlockingScriptLength}`
75
- )
76
- input.unlockingScript = asBsvSdkScript(spend.unlockingScript)
77
- if (spend.sequenceNumber !== undefined) input.sequence = spend.sequenceNumber
78
- }
79
-
80
- const results = {
81
- sdk: <SignActionResult>{}
82
- }
83
-
84
- /////////////////////
85
- // Insert SABPPP unlock templates for wallet signed inputs
86
- /////////////////////
87
- for (const pdi of prior.pdi) {
88
- const sabppp = new ScriptTemplateBRC29({
89
- derivationPrefix: pdi.derivationPrefix,
90
- derivationSuffix: pdi.derivationSuffix,
91
- keyDeriver: wallet.keyDeriver
92
- })
93
- const keys = wallet.getClientChangeKeyPair()
94
- const lockerPrivKey = keys.privateKey
95
- const unlockerPubKey = pdi.unlockerPubKey || keys.publicKey
96
- const sourceSatoshis = pdi.sourceSatoshis
97
- const lockingScript = asBsvSdkScript(pdi.lockingScript)
98
- const unlockTemplate = sabppp.unlock(lockerPrivKey, unlockerPubKey, sourceSatoshis, lockingScript)
99
- const input = prior.tx.inputs[pdi.vin]
100
- input.unlockingScriptTemplate = unlockTemplate
101
- }
102
-
103
- /////////////////////
104
- // Sign wallet signed inputs making transaction fully valid.
105
- /////////////////////
106
- await prior.tx.sign()
107
-
108
- return prior.tx
109
- }
110
-
111
44
  function mergePriorOptions(caVargs: sdk.ValidCreateActionArgs, saArgs: SignActionArgs): sdk.ValidSignActionArgs {
112
45
  const saOptions = (saArgs.options ||= {})
113
46
  if (saOptions.acceptDelayedBroadcast === undefined)
@@ -492,19 +492,44 @@ export class StorageKnex extends StorageProvider implements sdk.WalletStoragePro
492
492
  if (args.orderDescending) {
493
493
  let sortColumn = ''
494
494
  switch (table) {
495
- case 'certificates': sortColumn = 'certificateId'; break
496
- case 'commissions': sortColumn = 'commissionId'; break
497
- case 'output_baskets': sortColumn = 'basketId'; break
498
- case 'outputs': sortColumn = 'outputId'; break
499
- case 'output_tags': sortColumn = 'outputTagId'; break
500
- case 'proven_tx_reqs': sortColumn = 'provenTxReqId'; break
501
- case 'proven_txs': sortColumn = 'provenTxId'; break
502
- case 'sync_states': sortColumn = 'syncStateId'; break
503
- case 'transactions': sortColumn = 'transactionId'; break
504
- case 'tx_labels': sortColumn = 'txLabelId'; break
505
- case 'users': sortColumn = 'userId'; break
506
- case 'monitor_events': sortColumn = 'id'; break
507
- default: break;
495
+ case 'certificates':
496
+ sortColumn = 'certificateId'
497
+ break
498
+ case 'commissions':
499
+ sortColumn = 'commissionId'
500
+ break
501
+ case 'output_baskets':
502
+ sortColumn = 'basketId'
503
+ break
504
+ case 'outputs':
505
+ sortColumn = 'outputId'
506
+ break
507
+ case 'output_tags':
508
+ sortColumn = 'outputTagId'
509
+ break
510
+ case 'proven_tx_reqs':
511
+ sortColumn = 'provenTxReqId'
512
+ break
513
+ case 'proven_txs':
514
+ sortColumn = 'provenTxId'
515
+ break
516
+ case 'sync_states':
517
+ sortColumn = 'syncStateId'
518
+ break
519
+ case 'transactions':
520
+ sortColumn = 'transactionId'
521
+ break
522
+ case 'tx_labels':
523
+ sortColumn = 'txLabelId'
524
+ break
525
+ case 'users':
526
+ sortColumn = 'userId'
527
+ break
528
+ case 'monitor_events':
529
+ sortColumn = 'id'
530
+ break
531
+ default:
532
+ break
508
533
  }
509
534
  if (sortColumn !== '') {
510
535
  q.orderBy(sortColumn, 'desc')
@@ -1156,7 +1181,13 @@ export class StorageKnex extends StorageProvider implements sdk.WalletStoragePro
1156
1181
  async adminStats(adminIdentityKey: string): Promise<AdminStatsResult> {
1157
1182
  if (this.dbtype !== 'MySQL') throw new sdk.WERR_NOT_IMPLEMENTED('adminStats, only MySQL is supported')
1158
1183
 
1159
- const monitorEvent = verifyOneOrNone(await this.findMonitorEvents({ partial: { event: 'ServiceCallHistory'}, orderDescending: true, paged: { limit: 1 } }))
1184
+ const monitorEvent = verifyOneOrNone(
1185
+ await this.findMonitorEvents({
1186
+ partial: { event: 'MonitorCallHistory' },
1187
+ orderDescending: true,
1188
+ paged: { limit: 1 }
1189
+ })
1190
+ )
1160
1191
  const monitorStats: ServicesCallHistory | undefined = monitorEvent ? JSON.parse(monitorEvent.details!) : undefined
1161
1192
  const servicesStats = this.getServices().getServicesCallHistory(true)
1162
1193
  await this.insertMonitorEvent({
@@ -778,4 +778,4 @@ export interface StorageAdminStats {
778
778
  export interface AdminStatsResult extends StorageAdminStats {
779
779
  servicesStats?: ServicesCallHistory
780
780
  monitorStats?: ServicesCallHistory
781
- }
781
+ }
@@ -603,7 +603,10 @@ async function validateRequiredInputs(
603
603
  const output = verifyOneOrNone(await storage.findOutputs({ partial: { userId, txid, vout } }))
604
604
  if (output) {
605
605
  if (output.change) {
606
- throw new sdk.WERR_INVALID_PARAMETER(`inputs[${input.vin}]`, 'an unmanaged input. Change outputs are managed by your wallet.')
606
+ throw new sdk.WERR_INVALID_PARAMETER(
607
+ `inputs[${input.vin}]`,
608
+ 'an unmanaged input. Change outputs are managed by your wallet.'
609
+ )
607
610
  }
608
611
  input.output = output
609
612
  if (!Array.isArray(output.lockingScript) || !Number.isInteger(output.satoshis))