@bsv/wallet-toolbox 1.7.19 → 1.7.22
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/docs/client.md +26 -2
- package/docs/services.md +13 -1
- package/docs/storage.md +13 -1
- package/docs/wallet.md +26 -2
- package/out/src/WalletPermissionsManager.d.ts +6 -0
- package/out/src/WalletPermissionsManager.d.ts.map +1 -1
- package/out/src/WalletPermissionsManager.js +241 -74
- package/out/src/WalletPermissionsManager.js.map +1 -1
- package/out/src/services/__tests/getRawTx.test.js +3 -0
- package/out/src/services/__tests/getRawTx.test.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.d.ts +1 -1
- package/out/src/services/chaintracker/chaintracks/__tests/Chaintracks.test.js +3 -1
- package/out/src/services/chaintracker/chaintracks/__tests/Chaintracks.test.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.js +12 -0
- package/out/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.js.map +1 -1
- package/out/src/storage/StorageProvider.d.ts +16 -2
- package/out/src/storage/StorageProvider.d.ts.map +1 -1
- package/out/src/storage/StorageProvider.js +33 -4
- package/out/src/storage/StorageProvider.js.map +1 -1
- package/out/src/storage/methods/__test/offsetKey.test.js +266 -100
- package/out/src/storage/methods/__test/offsetKey.test.js.map +1 -1
- package/out/src/storage/methods/getBeefForTransaction.js +1 -1
- package/out/src/storage/methods/getBeefForTransaction.js.map +1 -1
- package/out/src/storage/methods/internalizeAction.d.ts.map +1 -1
- package/out/src/storage/methods/internalizeAction.js +2 -2
- package/out/src/storage/methods/internalizeAction.js.map +1 -1
- package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js +4 -0
- package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js.map +1 -1
- package/out/tsconfig.all.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/WalletPermissionsManager.ts +302 -71
- package/src/services/__tests/getRawTx.test.ts +2 -0
- package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.ts +1 -1
- package/src/services/chaintracker/chaintracks/__tests/Chaintracks.test.ts +2 -1
- package/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.ts +12 -0
- package/src/storage/StorageProvider.ts +38 -5
- package/src/storage/methods/__test/offsetKey.test.ts +299 -103
- package/src/storage/methods/getBeefForTransaction.ts +3 -1
- package/src/storage/methods/internalizeAction.ts +4 -3
- package/src/storage/schema/entities/__tests/ProvenTxTests.test.ts +2 -0
|
@@ -128,139 +128,335 @@ describe('offsetKey tests', () => {
|
|
|
128
128
|
|
|
129
129
|
// txid b6f72df4224efbacab42a16e1e88f48c217f03929c36987b9067d2556de47c10
|
|
130
130
|
// height 922107
|
|
131
|
-
// hash
|
|
131
|
+
// incorrect hash 000000000000000014d97d19bf82956c1f7ce3977da10b7fbdab9a10653c02e7
|
|
132
|
+
// correct hash 00000000000000001957bfadf841d1709d5039b3243c33ba58e4a6a97b44d2a8
|
|
132
133
|
const sm = new WalletStorageManager(setup.identityKey, storage)
|
|
133
134
|
sm.setServices(setup.services)
|
|
135
|
+
// This should correct invalid merkle proofs in proven_txs but currently does not because WoC returns invalid header info.
|
|
134
136
|
await sm.reproveHeader('000000000000000014d97d19bf82956c1f7ce3977da10b7fbdab9a10653c02e7')
|
|
135
137
|
|
|
136
|
-
const comms: TableCommission[] = []
|
|
137
|
-
const beef = new Beef()
|
|
138
|
-
const chainTracker = await setup.services.getChainTracker()
|
|
139
|
-
const inputs: CreateActionInput[] = []
|
|
140
|
-
|
|
141
138
|
const fca: FindCommissionsArgs = {
|
|
142
139
|
partial: { isRedeemed: false },
|
|
143
|
-
paged: { limit:
|
|
140
|
+
paged: { limit: 400, offset: 0 }
|
|
144
141
|
}
|
|
145
142
|
|
|
146
|
-
for (
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
143
|
+
for (;;) {
|
|
144
|
+
const comms: TableCommission[] = []
|
|
145
|
+
let beef = new Beef()
|
|
146
|
+
const chainTracker = await setup.services.getChainTracker()
|
|
147
|
+
const inputs: CreateActionInput[] = []
|
|
148
|
+
|
|
149
|
+
for (; comms.length < fca.paged!.limit; ) {
|
|
150
|
+
const unredeemedComms = await storage.findCommissions(fca)
|
|
151
|
+
if (unredeemedComms.length < 1) break
|
|
152
|
+
|
|
153
|
+
for (const comm of unredeemedComms) {
|
|
154
|
+
fca.paged!.offset! += 1
|
|
155
|
+
const tt = verifyTruthy(await storage.findTransactionById(comm.transactionId, undefined, true))
|
|
156
|
+
if (tt.provenTxId && tt.txid) {
|
|
157
|
+
await storage.getBeefForTransaction(tt.txid, { mergeToBeef: beef, chainTracker, skipInvalidProofs: true })
|
|
158
|
+
const tx = verifyTruthy(beef.findTxid(tt.txid)).tx!
|
|
159
|
+
const commVOut = tx.outputs.findIndex(
|
|
160
|
+
o => o.satoshis === comm.satoshis && o.lockingScript.toHex() === Utils.toHex(comm.lockingScript)
|
|
161
|
+
)
|
|
162
|
+
const commOut = tx.outputs[commVOut]
|
|
163
|
+
const input: CreateActionInput = {
|
|
164
|
+
outpoint: `${tt.txid}.${commVOut}`,
|
|
165
|
+
inputDescription: `commId:${comm.commissionId}`,
|
|
166
|
+
unlockingScriptLength: 108
|
|
167
|
+
}
|
|
168
|
+
inputs.push(input)
|
|
169
|
+
comms.push(comm)
|
|
170
|
+
if (comms.length === fca.paged!.limit) break
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (comms.length < fca.paged!.limit)
|
|
176
|
+
// Only redeem full quota of commissions per cycle to avoid paying higher percentage of fees.
|
|
177
|
+
break
|
|
178
|
+
|
|
179
|
+
if (comms.length > 0) {
|
|
180
|
+
fca.paged!.offset! -= comms.length
|
|
181
|
+
|
|
182
|
+
console.log(beef.toLogString())
|
|
183
|
+
const verified = await beef.verify(chainTracker, false)
|
|
184
|
+
expect(verified).toBe(true)
|
|
185
|
+
|
|
186
|
+
const cao: CreateActionOptions = {
|
|
187
|
+
randomizeOutputs: false,
|
|
188
|
+
//signAndProcess: false,
|
|
189
|
+
noSend: true
|
|
190
|
+
}
|
|
191
|
+
const ca: CreateActionArgs = {
|
|
192
|
+
description: 'redeem commissions',
|
|
193
|
+
inputs: inputs,
|
|
194
|
+
inputBEEF: beef.toBinary(),
|
|
195
|
+
options: cao
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const car = await setup.wallet.createAction(ca)
|
|
199
|
+
expect(car.signableTransaction).toBeTruthy()
|
|
200
|
+
|
|
201
|
+
const st = car.signableTransaction!
|
|
202
|
+
expect(st.reference).toBeTruthy()
|
|
203
|
+
const atomicBeef = Beef.fromBinary(st.tx)
|
|
204
|
+
const txid = atomicBeef.txs[atomicBeef.txs.length - 1].txid!
|
|
205
|
+
const tx = atomicBeef.findTransactionForSigning(txid)!
|
|
206
|
+
|
|
207
|
+
const priv = PrivateKey.fromHex(env.devKeys[env.commissionsIdentity])
|
|
208
|
+
const pub = priv.toPublicKey()
|
|
209
|
+
const curve = new Curve()
|
|
210
|
+
const p2pkh = new P2PKH()
|
|
211
|
+
const spends: Record<PositiveIntegerOrZero, SignActionSpend> = {}
|
|
212
|
+
let vin = 0
|
|
213
|
+
// set an unlockingScriptTemplate for each commission input being redeemed in unsigned tx
|
|
214
|
+
for (const comm of comms) {
|
|
215
|
+
const { hashedSecret } = keyOffsetToHashedSecret(pub, comm.keyOffset)
|
|
216
|
+
const bn = priv.add(hashedSecret).mod(curve.n)
|
|
217
|
+
const offsetPrivKey = new PrivateKey(bn)
|
|
218
|
+
const unlock = p2pkh.unlock(offsetPrivKey, 'all', false)
|
|
219
|
+
tx.inputs[vin].unlockingScriptTemplate = unlock
|
|
220
|
+
vin++
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// sign each input
|
|
224
|
+
await tx.sign()
|
|
225
|
+
|
|
226
|
+
vin = 0
|
|
227
|
+
// extract all the signed unlocking scripts
|
|
228
|
+
for (const comm of comms) {
|
|
229
|
+
const script = tx.inputs[vin].unlockingScript!
|
|
230
|
+
const unlockingScript = script.toHex()
|
|
231
|
+
spends[vin] = { unlockingScript }
|
|
232
|
+
vin++
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const signArgs: SignActionArgs = {
|
|
236
|
+
reference: st.reference,
|
|
237
|
+
spends,
|
|
238
|
+
options: {
|
|
239
|
+
returnTXIDOnly: true,
|
|
240
|
+
noSend: true
|
|
157
241
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Forward all the unlocking scripts to storage and create the ProvenTxReq for the noSend txid.
|
|
245
|
+
const sr = await setup.wallet.signAction(signArgs)
|
|
246
|
+
expect(sr.txid).toBeTruthy()
|
|
247
|
+
|
|
248
|
+
// Update the commissions as redeemed in storage
|
|
249
|
+
for (const comm of comms) {
|
|
250
|
+
await storage.updateCommission(comm.commissionId, { isRedeemed: true })
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
{
|
|
254
|
+
// Get the transaction broadcast
|
|
255
|
+
const createArgs: CreateActionArgs = {
|
|
256
|
+
description: `broadcasting noSend`,
|
|
257
|
+
options: {
|
|
258
|
+
acceptDelayedBroadcast: false,
|
|
259
|
+
sendWith: [sr.txid!]
|
|
260
|
+
}
|
|
167
261
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
262
|
+
|
|
263
|
+
const cr = await setup.wallet.createAction(createArgs)
|
|
264
|
+
|
|
265
|
+
expect(cr.noSendChange).not.toBeTruthy()
|
|
266
|
+
expect(cr.sendWithResults?.length).toBe(1)
|
|
267
|
+
const [swr] = cr.sendWithResults!
|
|
268
|
+
expect(swr.status !== 'failed').toBe(true)
|
|
171
269
|
}
|
|
172
270
|
}
|
|
173
|
-
fca.paged!.offset! += unredeemedComms.length
|
|
174
271
|
}
|
|
272
|
+
} catch (err) {
|
|
273
|
+
console.error('Error in 4_redeemServiceCharges test:', err)
|
|
274
|
+
throw err
|
|
275
|
+
}
|
|
175
276
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
expect(verified).toBe(true)
|
|
277
|
+
await storage.destroy()
|
|
278
|
+
await setup.wallet.destroy()
|
|
279
|
+
})
|
|
180
280
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
//signAndProcess: false,
|
|
184
|
-
noSend: true
|
|
185
|
-
}
|
|
186
|
-
const ca: CreateActionArgs = {
|
|
187
|
-
description: 'redeem commissions',
|
|
188
|
-
inputs: inputs,
|
|
189
|
-
inputBEEF: beef.toBinary(),
|
|
190
|
-
options: cao
|
|
191
|
-
}
|
|
281
|
+
test('4a_redeemServiceCharges optimized', async () => {
|
|
282
|
+
if (_tu.noEnv('main')) return
|
|
192
283
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
expect(st.reference).toBeTruthy()
|
|
198
|
-
const atomicBeef = Beef.fromBinary(st.tx)
|
|
199
|
-
const txid = atomicBeef.txs[atomicBeef.txs.length - 1].txid!
|
|
200
|
-
const tx = atomicBeef.findTransactionForSigning(txid)!
|
|
201
|
-
|
|
202
|
-
const priv = PrivateKey.fromHex(env.devKeys[env.commissionsIdentity])
|
|
203
|
-
const pub = priv.toPublicKey()
|
|
204
|
-
const curve = new Curve()
|
|
205
|
-
const p2pkh = new P2PKH()
|
|
206
|
-
const spends: Record<PositiveIntegerOrZero, SignActionSpend> = {}
|
|
207
|
-
let vin = 0
|
|
208
|
-
// set an unlockingScriptTemplate for each commission input being redeemed in unsigned tx
|
|
209
|
-
for (const comm of comms) {
|
|
210
|
-
const { hashedSecret } = keyOffsetToHashedSecret(pub, comm.keyOffset)
|
|
211
|
-
const bn = priv.add(hashedSecret).mod(curve.n)
|
|
212
|
-
const offsetPrivKey = new PrivateKey(bn)
|
|
213
|
-
const unlock = p2pkh.unlock(offsetPrivKey, 'all', false)
|
|
214
|
-
tx.inputs[vin].unlockingScriptTemplate = unlock
|
|
215
|
-
vin++
|
|
216
|
-
}
|
|
284
|
+
const env = _tu.getEnv('main')
|
|
285
|
+
if (!env.devKeys[env.commissionsIdentity]) {
|
|
286
|
+
throw new Error('No dev key for commissions identity')
|
|
287
|
+
}
|
|
217
288
|
|
|
218
|
-
|
|
219
|
-
|
|
289
|
+
const knex = Setup.createMySQLKnex(process.env.MAIN_CLOUD_MYSQL_CONNECTION!)
|
|
290
|
+
const storage = new StorageKnex({
|
|
291
|
+
chain: env.chain,
|
|
292
|
+
knex: knex,
|
|
293
|
+
commissionSatoshis: 0,
|
|
294
|
+
commissionPubKeyHex: undefined,
|
|
295
|
+
feeModel: { model: 'sat/kb', value: 1 }
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
let setup: TestWalletOnly
|
|
299
|
+
await storage.makeAvailable()
|
|
300
|
+
|
|
301
|
+
setup = await _tu.createTestWalletWithStorageClient({
|
|
302
|
+
chain: 'main',
|
|
303
|
+
rootKeyHex: env.devKeys[env.commissionsIdentity]
|
|
304
|
+
})
|
|
305
|
+
storage.setServices(setup.services)
|
|
220
306
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
307
|
+
try {
|
|
308
|
+
const fca: FindCommissionsArgs = {
|
|
309
|
+
partial: { isRedeemed: false },
|
|
310
|
+
paged: { limit: 400, offset: 0 }
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
for (;;) {
|
|
314
|
+
const comms: TableCommission[] = []
|
|
315
|
+
let beef = new Beef()
|
|
316
|
+
const chainTracker = await setup.services.getChainTracker()
|
|
317
|
+
const inputs: CreateActionInput[] = []
|
|
318
|
+
|
|
319
|
+
// This query would be much faster and allow valid proofs to be merged into beef directly...
|
|
320
|
+
// but will blow up if rawTx are large.
|
|
321
|
+
// This is really a case where a full Beef isn't needed.
|
|
322
|
+
// All the inputs will be from proven txs.
|
|
323
|
+
// Processors should accept the aggregate rawTx without any other input rawTxs or merkle proofs.
|
|
324
|
+
// i.e. All the input txids should be "known"
|
|
325
|
+
const r = await storage.knex.raw(
|
|
326
|
+
`
|
|
327
|
+
SELECT c.*, t.provenTxId, p.height, p.index, p.merklePath, p.rawTx, p.blockHash, p.merkleRoot
|
|
328
|
+
FROM commissions c
|
|
329
|
+
JOIN transactions t ON c.transactionId = t.transactionId
|
|
330
|
+
JOIN proven_txs p ON t.provenTxId = p.provenTxId
|
|
331
|
+
WHERE c.isRedeemed = 0
|
|
332
|
+
AND NOT t.provenTxId IS NOT NULL
|
|
333
|
+
ORDER BY c.commissionId
|
|
334
|
+
LIMIT ? OFFSET ?;
|
|
335
|
+
`,
|
|
336
|
+
[fca.paged!.limit, fca.paged!.offset!]
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
for (; comms.length < fca.paged!.limit; ) {
|
|
340
|
+
const unredeemedComms = await storage.findCommissions(fca)
|
|
341
|
+
if (unredeemedComms.length < 1) break
|
|
342
|
+
|
|
343
|
+
for (const comm of unredeemedComms) {
|
|
344
|
+
fca.paged!.offset! += 1
|
|
345
|
+
const tt = verifyTruthy(await storage.findTransactionById(comm.transactionId, undefined, true))
|
|
346
|
+
if (tt.provenTxId && tt.txid) {
|
|
347
|
+
await storage.getBeefForTransaction(tt.txid, { mergeToBeef: beef, chainTracker, skipInvalidProofs: true })
|
|
348
|
+
const tx = verifyTruthy(beef.findTxid(tt.txid)).tx!
|
|
349
|
+
const commVOut = tx.outputs.findIndex(
|
|
350
|
+
o => o.satoshis === comm.satoshis && o.lockingScript.toHex() === Utils.toHex(comm.lockingScript)
|
|
351
|
+
)
|
|
352
|
+
const commOut = tx.outputs[commVOut]
|
|
353
|
+
const input: CreateActionInput = {
|
|
354
|
+
outpoint: `${tt.txid}.${commVOut}`,
|
|
355
|
+
inputDescription: `commId:${comm.commissionId}`,
|
|
356
|
+
unlockingScriptLength: 108
|
|
357
|
+
}
|
|
358
|
+
inputs.push(input)
|
|
359
|
+
comms.push(comm)
|
|
360
|
+
if (comms.length === fca.paged!.limit) break
|
|
361
|
+
}
|
|
362
|
+
}
|
|
228
363
|
}
|
|
229
364
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
365
|
+
if (comms.length < fca.paged!.limit)
|
|
366
|
+
// Only redeem full quota of commissions per cycle to avoid paying higher percentage of fees.
|
|
367
|
+
break
|
|
368
|
+
|
|
369
|
+
if (comms.length > 0) {
|
|
370
|
+
fca.paged!.offset! -= comms.length
|
|
371
|
+
|
|
372
|
+
console.log(beef.toLogString())
|
|
373
|
+
const verified = await beef.verify(chainTracker, false)
|
|
374
|
+
expect(verified).toBe(true)
|
|
375
|
+
|
|
376
|
+
const cao: CreateActionOptions = {
|
|
377
|
+
randomizeOutputs: false,
|
|
378
|
+
//signAndProcess: false,
|
|
235
379
|
noSend: true
|
|
236
380
|
}
|
|
237
|
-
|
|
381
|
+
const ca: CreateActionArgs = {
|
|
382
|
+
description: 'redeem commissions',
|
|
383
|
+
inputs: inputs,
|
|
384
|
+
inputBEEF: beef.toBinary(),
|
|
385
|
+
options: cao
|
|
386
|
+
}
|
|
238
387
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
388
|
+
const car = await setup.wallet.createAction(ca)
|
|
389
|
+
expect(car.signableTransaction).toBeTruthy()
|
|
390
|
+
|
|
391
|
+
const st = car.signableTransaction!
|
|
392
|
+
expect(st.reference).toBeTruthy()
|
|
393
|
+
const atomicBeef = Beef.fromBinary(st.tx)
|
|
394
|
+
const txid = atomicBeef.txs[atomicBeef.txs.length - 1].txid!
|
|
395
|
+
const tx = atomicBeef.findTransactionForSigning(txid)!
|
|
396
|
+
|
|
397
|
+
const priv = PrivateKey.fromHex(env.devKeys[env.commissionsIdentity])
|
|
398
|
+
const pub = priv.toPublicKey()
|
|
399
|
+
const curve = new Curve()
|
|
400
|
+
const p2pkh = new P2PKH()
|
|
401
|
+
const spends: Record<PositiveIntegerOrZero, SignActionSpend> = {}
|
|
402
|
+
let vin = 0
|
|
403
|
+
// set an unlockingScriptTemplate for each commission input being redeemed in unsigned tx
|
|
404
|
+
for (const comm of comms) {
|
|
405
|
+
const { hashedSecret } = keyOffsetToHashedSecret(pub, comm.keyOffset)
|
|
406
|
+
const bn = priv.add(hashedSecret).mod(curve.n)
|
|
407
|
+
const offsetPrivKey = new PrivateKey(bn)
|
|
408
|
+
const unlock = p2pkh.unlock(offsetPrivKey, 'all', false)
|
|
409
|
+
tx.inputs[vin].unlockingScriptTemplate = unlock
|
|
410
|
+
vin++
|
|
411
|
+
}
|
|
242
412
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
413
|
+
// sign each input
|
|
414
|
+
await tx.sign()
|
|
415
|
+
|
|
416
|
+
vin = 0
|
|
417
|
+
// extract all the signed unlocking scripts
|
|
418
|
+
for (const comm of comms) {
|
|
419
|
+
const script = tx.inputs[vin].unlockingScript!
|
|
420
|
+
const unlockingScript = script.toHex()
|
|
421
|
+
spends[vin] = { unlockingScript }
|
|
422
|
+
vin++
|
|
423
|
+
}
|
|
247
424
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
description: `broadcasting noSend`,
|
|
425
|
+
const signArgs: SignActionArgs = {
|
|
426
|
+
reference: st.reference,
|
|
427
|
+
spends,
|
|
252
428
|
options: {
|
|
253
|
-
|
|
254
|
-
|
|
429
|
+
returnTXIDOnly: true,
|
|
430
|
+
noSend: true
|
|
255
431
|
}
|
|
256
432
|
}
|
|
257
433
|
|
|
258
|
-
|
|
434
|
+
// Forward all the unlocking scripts to storage and create the ProvenTxReq for the noSend txid.
|
|
435
|
+
const sr = await setup.wallet.signAction(signArgs)
|
|
436
|
+
expect(sr.txid).toBeTruthy()
|
|
437
|
+
|
|
438
|
+
// Update the commissions as redeemed in storage
|
|
439
|
+
for (const comm of comms) {
|
|
440
|
+
await storage.updateCommission(comm.commissionId, { isRedeemed: true })
|
|
441
|
+
}
|
|
259
442
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
443
|
+
{
|
|
444
|
+
// Get the transaction broadcast
|
|
445
|
+
const createArgs: CreateActionArgs = {
|
|
446
|
+
description: `broadcasting noSend`,
|
|
447
|
+
options: {
|
|
448
|
+
acceptDelayedBroadcast: false,
|
|
449
|
+
sendWith: [sr.txid!]
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const cr = await setup.wallet.createAction(createArgs)
|
|
454
|
+
|
|
455
|
+
expect(cr.noSendChange).not.toBeTruthy()
|
|
456
|
+
expect(cr.sendWithResults?.length).toBe(1)
|
|
457
|
+
const [swr] = cr.sendWithResults!
|
|
458
|
+
expect(swr.status !== 'failed').toBe(true)
|
|
459
|
+
}
|
|
264
460
|
}
|
|
265
461
|
}
|
|
266
462
|
} catch (err) {
|
|
@@ -5,7 +5,8 @@ import {
|
|
|
5
5
|
InternalizeActionArgs,
|
|
6
6
|
TransactionOutput,
|
|
7
7
|
Beef,
|
|
8
|
-
Validation
|
|
8
|
+
Validation,
|
|
9
|
+
Utils
|
|
9
10
|
} from '@bsv/sdk'
|
|
10
11
|
import { GetReqsAndBeefResult, shareReqsWithWorld } from './processAction'
|
|
11
12
|
import { StorageProvider } from '../StorageProvider'
|
|
@@ -152,7 +153,7 @@ class InternalizeActionContext {
|
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
async asyncSetup() {
|
|
155
|
-
;({ ab: this.ab, tx: this.tx, txid: this.txid } = await this.validateAtomicBeef(this.args.tx))
|
|
156
|
+
;({ ab: this.ab, tx: this.tx, txid: this.txid } = await this.validateAtomicBeef(Utils.toArray(this.args.tx)))
|
|
156
157
|
|
|
157
158
|
for (const o of this.args.outputs) {
|
|
158
159
|
if (o.outputIndex < 0 || o.outputIndex >= this.tx.outputs.length)
|
|
@@ -405,7 +406,7 @@ class InternalizeActionContext {
|
|
|
405
406
|
//
|
|
406
407
|
// Attempt to create a provenTxReq record for the txid to obtain a proof,
|
|
407
408
|
// while allowing for possible race conditions...
|
|
408
|
-
const newReq = EntityProvenTxReq.fromTxid(this.txid, this.tx.toBinary(), this.args.tx)
|
|
409
|
+
const newReq = EntityProvenTxReq.fromTxid(this.txid, this.tx.toBinary(), Utils.toArray(this.args.tx))
|
|
409
410
|
newReq.status = 'unsent'
|
|
410
411
|
// this history and notify will be merged into an existing req if it exists.
|
|
411
412
|
newReq.addHistoryNote({ what: 'internalizeAction', userId: this.userId })
|
|
@@ -168,6 +168,7 @@ describe('ProvenTx class method tests', () => {
|
|
|
168
168
|
})
|
|
169
169
|
|
|
170
170
|
test('1_fromTxid: txid with no rawTx available', async () => {
|
|
171
|
+
if (_tu.noEnv('test')) return
|
|
171
172
|
const ctx = ctxs[0]
|
|
172
173
|
const txid = 'missing-txid'
|
|
173
174
|
|
|
@@ -182,6 +183,7 @@ describe('ProvenTx class method tests', () => {
|
|
|
182
183
|
})
|
|
183
184
|
|
|
184
185
|
test('2_fromTxid: txid with no Merkle proof available', async () => {
|
|
186
|
+
if (_tu.noEnv('test')) return
|
|
185
187
|
const ctx = ctxs[0]
|
|
186
188
|
const txid = 'no-merkle-proof-txid'
|
|
187
189
|
const services: sdk.WalletServices = ctx.services
|