@bsv/wallet-toolbox 1.6.38 → 1.6.39

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 (29) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/mobile/out/src/sdk/WalletError.d.ts.map +1 -1
  3. package/mobile/out/src/sdk/WalletError.js +14 -5
  4. package/mobile/out/src/sdk/WalletError.js.map +1 -1
  5. package/mobile/out/src/services/chaintracker/chaintracks/Chaintracks.js +1 -1
  6. package/mobile/out/src/services/chaintracker/chaintracks/Chaintracks.js.map +1 -1
  7. package/mobile/out/src/storage/WalletStorageManager.d.ts +15 -4
  8. package/mobile/out/src/storage/WalletStorageManager.d.ts.map +1 -1
  9. package/mobile/out/src/storage/WalletStorageManager.js +29 -19
  10. package/mobile/out/src/storage/WalletStorageManager.js.map +1 -1
  11. package/mobile/package-lock.json +2 -2
  12. package/mobile/package.json +1 -1
  13. package/out/src/sdk/WalletError.d.ts.map +1 -1
  14. package/out/src/sdk/WalletError.js +14 -5
  15. package/out/src/sdk/WalletError.js.map +1 -1
  16. package/out/src/services/chaintracker/chaintracks/Chaintracks.js +1 -1
  17. package/out/src/services/chaintracker/chaintracks/Chaintracks.js.map +1 -1
  18. package/out/src/storage/WalletStorageManager.d.ts +15 -4
  19. package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
  20. package/out/src/storage/WalletStorageManager.js +29 -19
  21. package/out/src/storage/WalletStorageManager.js.map +1 -1
  22. package/out/test/Wallet/support/operations.man.test.js +10 -1
  23. package/out/test/Wallet/support/operations.man.test.js.map +1 -1
  24. package/out/tsconfig.all.tsbuildinfo +1 -1
  25. package/package.json +1 -1
  26. package/src/sdk/WalletError.ts +13 -5
  27. package/src/services/chaintracker/chaintracks/Chaintracks.ts +1 -1
  28. package/src/storage/WalletStorageManager.ts +38 -20
  29. package/test/Wallet/support/operations.man.test.ts +11 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/wallet-toolbox",
3
- "version": "1.6.38",
3
+ "version": "1.6.39",
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",
@@ -147,14 +147,22 @@ export class WalletError extends Error implements WalletErrorObject {
147
147
  static unknownToJson(error: unknown | WalletError): string {
148
148
  let json: string | undefined
149
149
  let e: WalletError | undefined
150
- if (error instanceof WalletError || (typeof error === 'object' && error?.constructor.name.startsWith('WERR_'))) {
151
- e = error as WalletError
152
- } else if (error instanceof Error) {
153
- e = new WalletError(error.name, error.message)
150
+ const t = typeof error
151
+ const ctor = t === 'object' && error !== null ? (error as any).constructor?.name : undefined
152
+ const name = t === 'object' && error !== null && typeof (error as any).name === 'string' ? (error as any).name : ''
153
+ const message = t === 'object' && error !== null && typeof (error as any).message === 'string' ? (error as any).message : ''
154
+ const toJson = t === 'object' && error !== null && typeof (error as any).toJson === 'function' ? (error as any).toJson : undefined
155
+ console.log(`WalletError.unknownToJson: error type=${t} ctor=${ctor} name=${name} message=${message} hasToJson=${toJson ? 'yes' : 'no'}`)
156
+ if (ctor && ctor.startsWith('WERR_') && toJson !== undefined) {
157
+ json = (error as WalletError).toJson()
158
+ } else if (name && message) {
159
+ e = new WalletError(name, message)
160
+ json = e.toJson()
154
161
  } else {
155
162
  e = new WalletError('WERR_UNKNOWN', String(error))
163
+ json = e.toJson()
156
164
  }
157
- json = e.toJson()
165
+ console.log(`WalletError.unknownToJson: json=${json}`)
158
166
  return json
159
167
  }
160
168
  }
@@ -462,7 +462,7 @@ export class Chaintracks implements ChaintracksManagementApi {
462
462
  let skipBulkSync =
463
463
  !before.live.isEmpty && before.live.maxHeight >= presentHeight - this.addLiveRecursionLimit / 2
464
464
 
465
- if (skipBulkSync && now - lastSyncCheck > cdnSyncRepeatMsecs) {
465
+ if (skipBulkSync && now - lastBulkSync > cdnSyncRepeatMsecs) {
466
466
  // If we haven't re-synced in a long time, do it just to check for a CDN update.
467
467
  skipBulkSync = false
468
468
  }
@@ -565,50 +565,62 @@ export class WalletStorageManager implements sdk.WalletStorage {
565
565
  }
566
566
 
567
567
  /**
568
- * Extends the Beef `verify` function to handle BUMPs that have become invalid due to a chain reorg.
569
- *
568
+ * Extends the Beef `verify` function to handle BUMPs that have become invalid due to a chain reorg,
569
+ * and originated from proven_txs records tracked by this storage.
570
+ *
571
+ * This method is optimized for making sure outgoing beefs are valid before sharing them externally.
572
+ * In particular, it only "repairs" proofs previously tracked by this storage.
573
+ *
570
574
  * Any merkle root that fails `isValidRootForHeight` triggers a reprove attempt for that block header.
571
575
  * This results in proven_txs with invalid proofs being updated with new valid proofs where possible.
572
- * Finally, a new beef is generated and verified against the chaintracker.
573
576
  *
574
577
  * @param beef
575
578
  * @param allowTxidOnly
576
- * @returns
579
+ * @returns VerifyAndRepairBeefResult, in particular `verifiedBeef` is valid only verify and repair succeeded fully.
577
580
  */
578
- async verifyAndRepairBeef(beef: Beef, allowTxidOnly?: boolean): Promise<boolean> {
581
+ async verifyAndRepairBeef(beef: Beef, allowTxidOnly?: boolean): Promise<VerifyAndRepairBeefResult> {
579
582
  throw new sdk.WERR_NOT_IMPLEMENTED()
580
583
 
584
+ const r: VerifyAndRepairBeefResult = {
585
+ isStructurallyValid: false,
586
+ originalRoots: {},
587
+ invalidRoots: {}
588
+ }
581
589
  const services = this.getServices()
582
590
  const chaintracker = await services.getChainTracker()
583
- const verified = await beef.verify(chaintracker)
584
591
 
585
- const r = beef.verifyValid(allowTxidOnly)
586
- if (!r.valid) return false
592
+ ;({ valid: r.isStructurallyValid, roots: r.originalRoots } = beef.verifyValid(allowTxidOnly))
587
593
 
588
- const invalidRoots: Record<number, string> = {}
589
- for (const height of Object.keys(r.roots)) {
590
- const isValid = await chaintracker.isValidRootForHeight(r.roots[height], Number(height))
594
+ if (!r.isStructurallyValid) return r
595
+
596
+ for (const [heightStr, root] of Object.entries(r.originalRoots)) {
597
+ const height = Number(heightStr)
598
+ const isValid = await chaintracker.isValidRootForHeight(root, height)
591
599
  if (!isValid) {
592
- invalidRoots[height] = r.roots[height]
600
+ // root is not currently the valid hash for this height according to the chaintracker.
601
+ // What beef txids depended on this root:
602
+ const txids = beef.txs.filter(tx => tx.bumpIndex !== undefined && beef.bumps[tx.bumpIndex].blockHeight === height).map(tx => tx.txid)
603
+ const reproveResults = await this.reproveHeader(root)
604
+ r.invalidRoots[height] = { root, reproveResults }
593
605
  }
594
606
  }
595
607
 
596
- if (Object.keys(invalidRoots).length === 0) {
597
- // There are no invalid merkle roots and the beef is structurally valid,
598
- // the beef is fully verified.
599
- return true
608
+ if (Object.keys(r.invalidRoots).length === 0) {
609
+ // There are no invalid merkle roots and the beef is structurally valid.
610
+ // The beef is fully verified.
611
+ return r
600
612
  }
601
613
 
602
- for (const heightStr of Object.keys(invalidRoots)) {
603
- const hash = invalidRoots[Number(heightStr)]
604
- const r = await this.reproveHeader(hash)
605
- }
614
+ // beef is structurally valid but has invalid merkle roots.
615
+ // Attempt to repair the invalid roots by reproving all txids in this beef that relied on them.
606
616
 
607
617
  // All invalid BUMPs must be removed from the beef
608
618
  // and all txid's that were proven by those BUMPs need
609
619
  // new beefs merged into the beef.
610
620
  // In most cases, this will be a replacement BUMP,
611
621
  // but it may also require a deeper proof.
622
+
623
+ return r
612
624
  }
613
625
 
614
626
  /**
@@ -922,3 +934,9 @@ export class WalletStorageManager implements sdk.WalletStorage {
922
934
  return stores
923
935
  }
924
936
  }
937
+
938
+ export interface VerifyAndRepairBeefResult {
939
+ isStructurallyValid: boolean
940
+ originalRoots: Record<number, string>
941
+ invalidRoots: Record<number, { root: string, reproveResults: sdk.ReproveHeaderResult }>
942
+ }
@@ -11,7 +11,7 @@ describe('operations.man tests', () => {
11
11
 
12
12
  test('0 review and release all production invalid change utxos', async () => {
13
13
  const { env, storage } = await _tu.createMainReviewSetup()
14
- const users = await storage.findUsers({ partial: {} })
14
+ const users = await storage.findUsers({ partial: { userId: 124 } })
15
15
  const withInvalid: Record<number, { user: TableUser; outputs: WalletOutput[]; total: number }> = {}
16
16
  const vargs: ValidListOutputsArgs = {
17
17
  basket: specOpInvalidChange,
@@ -326,6 +326,16 @@ describe('operations.man tests', () => {
326
326
  logger(log)
327
327
  await storage.destroy()
328
328
  })
329
+
330
+ test('15 abort a transaction', async () => {
331
+ const { env, storage } = await _tu.createMainReviewSetup()
332
+ const refOrTxid = '42671b6c9b79cec03bf5be9105203589b8b092774a40b459fbd835e5fd582202'
333
+ const userId = 496
334
+ const auth = { userId, identityKey: '' }
335
+ const r = await storage.abortAction(auth, { reference: refOrTxid })
336
+ console.log(r)
337
+ await storage.destroy()
338
+ })
329
339
  })
330
340
 
331
341
  const testTxInputUtxoStatus = `010000003E63EAF142160AD52F3172D75305D0D495A99AD9F17A693017EF8630C86F37A200000000006A473044022004E94D9188B2CE1193969509F32B46F94A36DB2BB4FC0832936F937C59FDDA470220781E5A5AD34EE49C985E5177380D6D111546D7BCCBAAA219B292FB49400DB7C9C221021A67430A3C5F274D3563892965758D3DEAE67799DD47E28DA95FBD1013D3B302FFFFFFFF74B95869A62F82E50642B4B18C78321BC12858A640155C8DA34EC4043393CCA6000000006A4730440220680AEF159D6C158C703912A9FBA090A063A26D92DBDFB7F15D6026FB5EAC332E0220375559499733A35955CA5F562669C8A947624BF22A8475EC0CD2C488530BCBD1C22103F55B1909BFD6851773E7FA7E567B58BF586D1EF76D0DE00330EE7F05E19672C2FFFFFFFFCDA6E22336EA4F8898D56C85C022F35338A6CD9E8D14FC75EA39DEC3B78FB83E010000006B483045022100E2B532D81252E60465E694F40A67B8CC52CCEAA1992494AAE264E039ED4D471602204E5C65F74BB49D263C54E43CFE22C8AB39B8AEB89F64CFEF933E5EBE08C5EF6DC22103E4F28DF126FBE92CF4418EF16636D18D75F8FFEADF0D03A0339A53B4A37DDDF7FFFFFFFFE330B3BBCB5815DD6B2B03BA5105F71F09CB8C26344F67C7A5E082473DF75859030000006B483045022100EBF506D10F04EC171C6A598056F06946D0B6F244FD08AA3E5A2DABB2EAC01A2A02206E557D4D7048E19F1DE094C5BCB7FC507FEC7E13C419AE829AD9180BACE4D5D8C22102960CADC2656A19DAAF1FCC04F6CF235C0E83822336F3CD32D599A426DFF85114FFFFFFFF7A58F2A977D75EDC8D349AEC609DAEC3AB06C12CE83276FB986D0B36D37C3C3C090000006A47304402205B353BE3BBC19B3766D12D5268E34E34675EB8BB8DD7624A522C1A36C1A1F481022072DD8D7F11C5507781FE9C55931A95BB3FE0FF7748DB4D1765FB6DFCBDF27268C22103F051F897874F7365DBF96773EE4D54EEA289BF05EE1610FF8C7F52EBC15A8294FFFFFFFF2D1C1B9098484F91435CB9965F07886E30FB8D1EA7F221C9072DAD8AAD545B294C0000006A47304402205D42AC6A4CA02F7006781515E9DAB1101B2F8006193F7E3EEB61CDC3132EFDDE02203EB616AD39280D1A07E9B31D1E4BAF56F831AF95A21A16D304235DD7DC65CF20C22103F051F897874F7365DBF96773EE4D54EEA289BF05EE1610FF8C7F52EBC15A8294FFFFFFFF2D1C1B9098484F91435CB9965F07886E30FB8D1EA7F221C9072DAD8AAD545B29160000006B48304502210080AE055C991A3EFED069C3E0D22E984DAF0C2DDDE6C102280EAA6E7ABBA2E9A00220339DE057226FAD63D021A3167C3AEDA0447D49DFA782A59850F699012C44FA4DC221033F8A1AD07E37C12FCE914102509C9ABFC313F69D9329F5137FD2EA79F633C86CFFFFFFFFFBD56D01AAB9E6F7E73F0D6A232F4D73D552A933E3ECBFC2E4BD95F4ECF9A1C6020000006A473044022043AEAFBF8C63FC98CECFE79569BE2F0D94C02E44C2C50CAD37104C4EA0D0B8E4022072EA0F50DF429D15500F4F2795147256A40DEA751BECD6572E0C5AE51D6DF553C221033F8A1AD07E37C12FCE914102509C9ABFC313F69D9329F5137FD2EA79F633C86CFFFFFFFF1D6A18F2411362A374CE97D2480C54E21173A58C5E83D7679DB1BC5CA112A55D020000006A47304402204B5E9B9612F89CADC7BF2D7035BFFB1EE9127586F504D4C635B674D8A1BE000702207837EEC18E2BD808F58935C4C78685715B2C5A3D84AB39895F8DA1AA0F7E6A28C22102D7EAA52A92B311A96A0AEBB18CABFE3A9B17B82048ED1E3E58628A4959ED91B4FFFFFFFF4A2297374C26D0E5EE98C07FDA64DAD58577F89502835CD433EEC3191A66F380B30000006B483045022100CF83B0C64FD8ECA6761CC7BD3D72F2B38CC17B747C1E98F48DACD155B7CE9B3502202C696010E7673325CAEAE2E0D7F0BA8DC2EADC6FDB7A3779AA359820A16CD848C22102D7EAA52A92B311A96A0AEBB18CABFE3A9B17B82048ED1E3E58628A4959ED91B4FFFFFFFF589F60C44908602772131C5D457186E18F4D22D659353AC84F3A0795057F2378000000006B483045022100C4EC4D00EA39C2EBBA147752C67BB722B695777F00C462B7AE3E76467DB5EE9B02205402285B07031D4EA0FCCD298FED76F590243D1D9CE8B8C44F83F97B59691E9BC22103125E0DF790EAE42BFF3B6057A2699C534B3E4D08C1D3AFEC2AF4C10CC751EFD8FFFFFFFFB750A581EEA3A60079DE6D28FE07BAE3C7A63065D92DA936C67FE4C52F1C1DE6000000006A47304402201860470374A282FF58B6EE576A1EF46B60238131FD00D0C0C27777F8F76CAC4502204163110A54EB0B81C6F0791E363F3DF0F0A14C08F6A7AE2E8FC77B7713ED109BC22103125E0DF790EAE42BFF3B6057A2699C534B3E4D08C1D3AFEC2AF4C10CC751EFD8FFFFFFFF833F3725A47C30A4AD5EBE5EA46D9AED81D5213BA2B51DE74A8BF23B65AC99A39F0000006B483045022100F1B40B6D4053E817FC674872DB1B8FE8C64D625CF4974893846A490117D034C60220343365C584D60269BF7845AFD2B69B4CF230530091102B1493B32D7B73E0CA0FC22103125E0DF790EAE42BFF3B6057A2699C534B3E4D08C1D3AFEC2AF4C10CC751EFD8FFFFFFFF833F3725A47C30A4AD5EBE5EA46D9AED81D5213BA2B51DE74A8BF23B65AC99A39E0000006B483045022100A21CBDF75C58FAD76313F2CBE8D0E0DC1E3B5FCB9ECC61594A91D4F61218C85902202BB2250C3477EFC9D7C28F1D1E0ADB3296952671D340065ADA8B93A330C39244C22103584150A15E4D85DF54CFBBD822ACA5EEDE00D5DD8C32126FCBD51499519BA565FFFFFFFFA1DD547EAB22B19A49862C2ED7C3E059DBBB5307738F9D9581CED2B4AAB6B6D9010000006B483045022100A0918681C651851B91617C8E1C01074F2A0291EBB083AB2163D72FF565DD8590022008E27FC437A0DE19A3F39F3C2C3F1B3C1F508E52DC69ACC2CBF9D1774C7C4047C22103125E0DF790EAE42BFF3B6057A2699C534B3E4D08C1D3AFEC2AF4C10CC751EFD8FFFFFFFF0BB9D0E3A9CCEA73BC8682B66C559D6232265488647F0B7EEECE00BD0C2F5904000000006B483045022100C568678B624F6F04E8645AD8340638075E07AD4BCBB0FA9446B2153599B803C902204B9BD26BD58614360B86F95E9812E68A759450E64659AA5B8707FA629D12B438C22103125E0DF790EAE42BFF3B6057A2699C534B3E4D08C1D3AFEC2AF4C10CC751EFD8FFFFFFFF5367F929C9123A4853ED77A0087F72D135031A8E64C3D047976EFCD3807FC0D5010000006A47304402200B1F4939A427C65ED456B62158271F269C33740C5E4D9ED2F9E864E410F23511022059F10A7FEFE82CF89C274FE9486CFAEF7B148290386DDD3F6423280F0667EEF7C22103584150A15E4D85DF54CFBBD822ACA5EEDE00D5DD8C32126FCBD51499519BA565FFFFFFFF5367F929C9123A4853ED77A0087F72D135031A8E64C3D047976EFCD3807FC0D5000000006A473044022012D66417842DDF0079734B3885CE56D42B2309A49CFD1313895CE6401E67E47602200F8FCCBECEEC0546577872F4BA7B95EAF4621506238D88E89A0A0B12E46876DCC22103584150A15E4D85DF54CFBBD822ACA5EEDE00D5DD8C32126FCBD51499519BA565FFFFFFFF46CF567BCF79C0E845BC95A488DC8BEB8E3558783F21B30A2902F333D6080C3A000000006A47304402202DEBF679DE7F93DDABC84CC1953DC52570EF291F4BFE1C61840AAA2D3CDA0AF5022041C66B14238FE4CD4C5E7E3BF6BA2BDA031F7D4EACA3F15FC28DD6CDAF2B2E54C221036D9E146EDA0C9E01DF36F4735C39B29E8C8B58BFDB2BCF82E407A1CEEB8ED040FFFFFFFFA11701B6BC31DA3646DBAEBD0042AD7357B14A35B97461E9F2278DEB90FD6838D40000006A4730440220154EB1B8E54A660311C1A400F94F370B382BE9EA5B37836328BF2C2FADCFDD7C022006BE9C8336F56AE98135CBF6D87ABB47B3F5C38028E1438246078648CA031BF5C221036D9E146EDA0C9E01DF36F4735C39B29E8C8B58BFDB2BCF82E407A1CEEB8ED040FFFFFFFFA11701B6BC31DA3646DBAEBD0042AD7357B14A35B97461E9F2278DEB90FD6838D30000006B483045022100D7CD746B6352CDCF939870F2FC4B119B2F526171E00DA06ADB3359155E5BC03C022022E5126E535BE59FCF2AD6F6850B3F48DE7D5552D49468B00A01B728F4AB7239C221029C4787B4B8514206737095BB1C95E62BB901845E5AB8C4144B06E09C654F8F6CFFFFFFFFA11701B6BC31DA3646DBAEBD0042AD7357B14A35B97461E9F2278DEB90FD6838D20000006B483045022100CBC2A4BC0070EF066FDFC99D7214025E410C368D7711D1F30DB4D0A676C1D7B20220675CB5B255B882408C2797FFA5A25FE652F8B1D6E2CCBD8029905FDBAE88F9FEC22103346CEED4C7E38ECFDEF9DA13316C9549E2E3AB1BE03CEF2E1D799371C315897EFFFFFFFFCA40E64BC0512AD8EB45E5611A5482F609FD69D99C9E0AE4980D50C11B6C67D8000000006B483045022100E48A110972F0783E15EA0E89BD348D1531622872B0E35AB61B79A9098E3CFA5202206893582684F5CF2BDC6158EA4624B63788044E8142EA4247AD6979F66AFA7D48C221029C4787B4B8514206737095BB1C95E62BB901845E5AB8C4144B06E09C654F8F6CFFFFFFFFF47FA4B80212220A78327B2FE5F93263EA6659FFA6BD6D380C1D58C6739BE8D5010000006A473044022056F79F2D88910609ED1D2A83E86702A7794122D45C6433009BEBA328F60969E20220488D7D11D2DEED21A8A2034A537DF86A9319093DF782A54D1C49048D8A8028CEC2210364E1D7C8AB3D509207760BACF81BB050E67322EBF2E905FF309E89ACE13BE894FFFFFFFF1F6FCB9D335E553262F3FB1CA6A826DBBE9428DD579EA51BA6090C83A7D4FCDA010000006A47304402205C9C3FFC78210A7B93912FAC417775EE6DCD8B6794BE36D01C7D0BF36BC408D702201A253C7F4BD2464DED11A837C9EA628A97399632ED04C2FEA22CBD75579E58E8C2210364E1D7C8AB3D509207760BACF81BB050E67322EBF2E905FF309E89ACE13BE894FFFFFFFF09B0858061E61218B0BB5956508F643E3818FA1FBB1400ADA6D994704418DCD9010000006A47304402203FE198B7AB8F61546D62B35A4DF160DB438C84EFFD7067B46C60AF5F27E0CBB502205FB58F426A03427CDA37CCF5B63F672F5BFE71C7E8B791AFDEEACBD1D3595CB1C22103FB41089708436C88CF77E0700CB67ACDE37F255DC4CCDBD7637AA79307269630FFFFFFFF9B1A1B386F7D66899033F7B2AEB6A934CBA1BC2953AD4FE5E16A47EEC5F3FE23000000006A47304402202DDBBB9E92D1446A4F3890657F1F56EC2DC8F41DE864077CFDB41E6C99F75FDE02204553AC6BD3B9AE35DB4664BD18BF57B3E8E9BE84D76E40B78B77E760C36A064EC22103E080628C06E929C254B93A922BD42529A5E96491DFE0472AAF94928478B9EB60FFFFFFFF02FB55CA273FD7916E9C7B8F38D3F0287F9897980C840E0FA10F035DA33DAD47010000006B483045022100AC5FA70052293648A3BE5319C55B4E0A7E579F744CA04593F6EB88E0B88C1BA9022001B3419B5262022A8D5AADBEC1296167D436EE1808CD11CAC22C6B12B382CEB2C22103E080628C06E929C254B93A922BD42529A5E96491DFE0472AAF94928478B9EB60FFFFFFFF770E137F47D0C046AA1F02ED198F0F5EACBA78AED8A12D5B6AC9B169C75CC8ABB50000006A47304402204EBD05E2826D5263973B0C33AA32A6E5213C8378A16CF620E41E0AE27F04A5ED02201C38314E0755513CB720BDAAAACB495945C8B64873F04CCB0AB4ECE98C023543C22103E080628C06E929C254B93A922BD42529A5E96491DFE0472AAF94928478B9EB60FFFFFFFF770E137F47D0C046AA1F02ED198F0F5EACBA78AED8A12D5B6AC9B169C75CC8ABB40000006B483045022100CEE6BBBA8DFB309895A264091C9E9965EA71559F13DB22CE66DCD6A9E215E9DF0220355620462931985C870E5793C2F7222440CE468B1AD339BE4A85BADB81B25C08C22103D7558C265481BC9009884F2C6E629E7B6183D97538E9623503FC8CF5C7363D62FFFFFFFF249E0A85AC5C5F61771C6A7B1121C11FE2B68BCCA8734286AB936F10F0DF4C9E000000006B483045022100A1F45E58C823833DFA5BC5B7FE96618670911C9F1961B6E79CCBCC5D951859BB022034373BFF50DF19DD0E12736DAC6D9C4F5371C373CD6FB6CA0C07AF66AFD7F911C22103F9832BCBECE37C09BF91A46792F89C12C400F0E23F3B959CEA9EF1A9F5668888FFFFFFFF864243C3AC4F36396369D2A71FF4F0AB9C3BC0D3F12A5B396980542BE38C9E64330100006A473044022065A5B6C567A05E90B6C236678AEDBC6FE93371AC2F64D1EC0BF3F294EEC3A53202202E28C99E9E285DA66BAC4EEF042BABCD94A41E43A284F31A97D0A45CBE828A66C22103F9832BCBECE37C09BF91A46792F89C12C400F0E23F3B959CEA9EF1A9F5668888FFFFFFFF864243C3AC4F36396369D2A71FF4F0AB9C3BC0D3F12A5B396980542BE38C9E643501000069463043021F5601776FD074AB9A0FC636661D156CF07BF5B15B6648C5BC66D05DE4D3A663022048F33208CED52287867C6E56498553998ED9F5FF46FA5A5F2B14EC6F6C9F1FC6C221038948C2F32F21FF2E33B00D16E3204AF5EF888331C74D237709CA4D4654BBBB80FFFFFFFF864243C3AC4F36396369D2A71FF4F0AB9C3BC0D3F12A5B396980542BE38C9E64340100006B483045022100ED170557BCF179486B0CD35E56717721AA948941E84234F7CACC5EE3C24C3110022063B0CFBDB9C6C8F2AEBA01EFE48ED5B273006B8B6D238C1C1282763F7BA0852FC22102F72539E17B2A9FB12999AD5AEA4FEECB2CE50574B56B5CEEE4D02D8CD07090B7FFFFFFFF51386BF256B3987E0C6404D27D06E3E53B0DE6904A419F6B8DF038F13988A8CA000000006B483045022100E34C6EA96AF4701F0CF16E898E979EBC3EB214DDA8B485AEE811E21F1C34782D022047EAD42030B2E67B15B2A3417A0420D77467C71CA31AC06E759415E2ED1E73B0C221038948C2F32F21FF2E33B00D16E3204AF5EF888331C74D237709CA4D4654BBBB80FFFFFFFF11F69487F837BD1D30C88D6F89800760FD914CBEA11EFEFB97CC2EF8467FD29C000000006A473044022079A8AE9B2F18D6C8A8C57F925C8EDE9E7DC4E9B029A08FF04FB0E7955B18E8DA0220050B99D687C43AF8CADC311DB062309B2232D0A978AC6E39328A562D3965243DC221038948C2F32F21FF2E33B00D16E3204AF5EF888331C74D237709CA4D4654BBBB80FFFFFFFFE10CEAE7D2BB2D7C60DD853E6DF8540D352C6FCA363553690425F267F4E36BB5380000006B4830450221009CF2B05A6B673E2AFF83CDA2B52D2FEF073DC8DC84C544CB5F978532A626CC7502206B6F69D943286ED45E7A5F430DEE8C6475F95EB8E557A2E2C5785F60B4E5E5E3C221022586C020EC9DF598D68F69967E61123B8F487CEFF465C8A1A0BCD377C0D4C608FFFFFFFFFBC6C11521941FBBB72A0F3B68D609F66419586D47ED2F313C64181918A04A92010000006B483045022100BEDFA3ADCBF41A099F4372746682F305A5245E08FA137801E7D4EBDE8E7EDEED02206D15AFECC651B8F6C65B59B8844C2088AA154625746A8A02C617D99277D95895C22103987C11B7D23C49817D6164B9C57CE5C845BE9E11342EBCF19095A7486B9BF147FFFFFFFF5D08873B553F347F83F8B30740C5DCBB7586E22A121ADF1888DA6F23F2C253646D0000006A47304402202E6E19291842A0390CA9098510F686D993D02F7A5C01305E5B7EF075BBBEC92E022031C1E35D8DE8F62FA015249FAD699DCA3BD7D48C60FA262C4A25872A99885E98C22103987C11B7D23C49817D6164B9C57CE5C845BE9E11342EBCF19095A7486B9BF147FFFFFFFF5D08873B553F347F83F8B30740C5DCBB7586E22A121ADF1888DA6F23F2C253646C0000006A473044022010920B2B3465ECF21A685884AD54E041C54B0CC73DE7A988921C742B06BEB51302203DB46BD95FEBD29A69008A214A0E7ED65B6B49FB5C96DD086ED10851B7C55B3DC2210239F7060641B0E9A8ED1365420BA2987479ABD66206275067E4EAC21FDCE2AF5AFFFFFFFF73D4D99BA348D4DA8E7F221709280F16A14B4C1E72C1A0E24AD5FC8F09CEED7D010000006A4730440220584F82CBCD237083BE0B5C80645AB8A31C0EAD5C140BD5C299EA3B7270ADADF40220429CAD186E80F0936528B2A3313EEF8A0BC67403969880BF0C1E762FCF82A062C2210239F7060641B0E9A8ED1365420BA2987479ABD66206275067E4EAC21FDCE2AF5AFFFFFFFF0843CB3AD2622892163DF29617F45A799E09B667AD707AD6FE7D0C2FF6FA0248010000006B483045022100DE499AD82B27200F140417C92D2BB7223F4A51AA4E3B3EC0942FFADCA8572F990220587EA05565349E79CA85DFEEE6617335BF50DD56CC0A73434478B867927253D7C2210239F7060641B0E9A8ED1365420BA2987479ABD66206275067E4EAC21FDCE2AF5AFFFFFFFF7E3EFF23768186357CD9E23A3C5E64D7CCDF778D4625C5FD7AF8AA0BA26D18B1010000006A47304402201667B3A2445F77BCD6A4A9DCB87B052E50189F8F261847F165EA6AA8C30204B8022034A449DCEED01B782EEB764B1453A7696B6F45BCDF58F5A16242A27B40254A26C2210205EB0CF0442AC7CF95F237F83631F3A71A769F14070BFBA130E7F6446D0FDA89FFFFFFFF7BD7CA433910CD9CD3A31E3C526C8A08F56218ABEBB8FA7B6D7F9013770903B7060000006B483045022100CBE66D90AF66E7B2098644D489E761D2E1A017DA1BCF514F6EB9CC0D143D3E29022028C3D949EBEB493C630EBA6B94E963DEE224F82E0CAFA688DCE82BF2E3E33029C2210205EB0CF0442AC7CF95F237F83631F3A71A769F14070BFBA130E7F6446D0FDA89FFFFFFFFC06A85664B630EC529F066F082CD4ECE9C6D627B4A25FA052A4321CE201F5249000000006B483045022100B8E3DBB1B95253947D66224F2B56D4AD32CEE62862AA6079BBFDB2A29097384C02207B06BAFDD798EBFC1042952A214EE0095AC456E4EC7ADCD2D7643AC940E37808C22102E6A2C34586C6A2F9F9D8247622E03E2427D8DA8BAD7069B5FBD4BAB7CFD495BEFFFFFFFF5455D0E0DAF167EA4DD6268EBF681F5B627E3CDB95A64E45B46504B47DE7559B010000006A47304402202FB18936EAA9E7574D68B64FD3A72163DC02F36E76105F6230B69B9A8CE8186E02200669E0FF51A609CF52F2D484CF90DECC7E0F288815D889DD54A208FDAFCB0480C22102E6A2C34586C6A2F9F9D8247622E03E2427D8DA8BAD7069B5FBD4BAB7CFD495BEFFFFFFFF0FC11392D3D66CE589DBEE6396A9C91906E94E5FFB0F10582DD84DC27C139549010000006B483045022100B1B780C18EE1B24A67756E15ED487626247718743B25781E8DCEF385817EBA0A0220422935FE91405FD3E2834EBE03EA27DEA2AD73F2E5A32798D3EFAA28A11B0E45C22102D54A842BF3053DA8139191C78DD95859326551C14D33317232240E825AC86721FFFFFFFF5C81D63ACF4A9539158B16F116C9FE16E61AD2EAE8627B0DAF6E5E27D7065BCE4B0000006A473044022070BEAC59696981AB7E13CB99C8AA5EBDA64AB3B2CEFC4197760480B24473C62A02201AC5EA4E1AA854C7CF641A70D5629CE17D3101D0F29F383EBFD300D11B8355F7C22103E0C3031D39F82DCED6FE23F7DAEF43C1C2AA37279E6CACFCC3D65C20896EFAFEFFFFFFFFA832AAD47D0F6C088C259B108C1234866D824B63081D056889560A63987A9F61000000006B483045022100F67205F32BE5981277C403ADD7DDCF355760545FA5F07B5221AC51AD39B5D6240220015D5AC3AE684183E92F128C96B8C4FBE37D581A2238B55548D0FAE5188C93D0C221030A82429D655A883ABB84A6F494ED0F584FAE70AF76F6FFE089FC858DFF6791CAFFFFFFFF9F7AB7BD8B01B35936A0806314FBA6E05978B00B588809CBC1BFE440BE48F437010000006B483045022100B0E893E5300216E39CBA60AA01BBCF233024A364F6688305CBB5A23FD99A9DDB02200BE2E288377E83222C066A4647EEE4A0F8DB1289034F19C75B029071A74B1BB3C221028AA47294780FCE86047AD43B106B887101311EF2EC15CF8CC781A5E94E941B87FFFFFFFF437A577E1B156B11BA5D3D4F77883778B8A16344DE7A493337A48A4277E3501F640000006B4830450221008BDFE07288CC912878F66E451DA2067E02FD2169B32C42ADC226CA0AC588ABFC02207F3F185DB742C755F554539C2DDAE99DB84BF31198623F3D36B28A6040F13187C221028DC193FA0BAE51229C0D913B37B4B85E7D8657C67E6B39DE55F0F829F3E56F97FFFFFFFFEB46CAC62C55714409DC0CB9DEB430A28BDF64DE9F67D2A462E6901B4D633376010000006A47304402203627468E6F210ABD49276436DC5A76DF6160D25650C62F5943140AC70FECF39302202294C59CF141219551382ECCE8D529F346A88413070DC90FB11B3AFA24C9DDE5C2210375727B6DF18C46DA978E03F1197AD63F3A7A2EB59ECC6C808F01CF01DF4CC462FFFFFFFFFE263AF23E8A0656DA85D0E776CD26B77EB606869C41119CF0211DC3EB7FACD1210100006B483045022100967F8B5E10858E507C64F9DA6FF840133FD5A76E515C3CFDF88833E9819733F2022052B33CD8CD3AB5CF745C75136F2CDF675620BB94D09616117567FD22D08AD052C2210375727B6DF18C46DA978E03F1197AD63F3A7A2EB59ECC6C808F01CF01DF4CC462FFFFFFFFFE263AF23E8A0656DA85D0E776CD26B77EB606869C41119CF0211DC3EB7FACD1200100006B483045022100ADC229F8037EB7B3D08D6DE7A0DEAAE2874D7B943406D9ADAEC34899A7CC0B62022059DE20822F8E1DF474C0C763EAB20EB1AADC9DAC2EBB3D685CB24EC6917AFC49C221027ED09AC05B9215F00B6F8BE59CEC79284542F5E8C1D17AC660B2C296FCEE931BFFFFFFFF232740426EDFE1EA3337FB4438252AA67FB144C6CB1DAC76FEBB16BB954C6ABA000000006B483045022100DB65D8077D5EA9C886629F328BFCAC9ACBA3FF83E50EA18C360CE22CD6DC3BDC022001759AF276AFE21C13A66539008DC5F0469129A3FB7A51703B2FE416047C8A1CC221027ED09AC05B9215F00B6F8BE59CEC79284542F5E8C1D17AC660B2C296FCEE931BFFFFFFFF09537489C63ED62DF8D069AEFD16BF4775E1D9878F0BE9EAC4AC2CB3A8169DAE260000006B483045022100D0CAA6FD70BF80C6E936F4738221F874E9C620FE1CA96BC0D87F23FF863B33DE0220124B342E241E41C2645DC4181A75239618D267E64BBDAB7A72109BFAB89FE784C22102C4559C96B87528C3B2385DC63216B0EEE1E25524E9E45CBB7577DEF21B1D62B9FFFFFFFF3739FA73213ED1440431274667DDCEA593DFBDFADFF26F37359BC06492BBB0E59B0000006B48304502210099AA3BD609A06C875D0F584B0A6644387179ACB6F63C690C6FF20B650653259802205898DD42BC06A8F8D1A74A2F74CCBA7B0D6DCBDA51A9B7ADD12E5F4F13121CCFC2210366C2029F74160CBA941383501C988D37BF932629F97B4E07DF1A339EC25ADB71FFFFFFFFC34D896F7B4EAE1344A02398292A2FDDD464E15A0C3321FF17D3B96D92D8FB64340000006B483045022100F32667A5734DDA65A6DDF9DFA789907B1ABBEBB0062CD694FA6E2A57A13178A202205BAF300DFADA245B470BA87794219E8173723FF3AC6FEA06296D23297375BF45C2210268C6B69A5BC61E1F3452D5828D7D2D8FBD4AAC371665ADB17973198377DD10D4FFFFFFFFCFD345CB9C6D4574D28EF1E0704B2657434FBAE1521F27D9AE1E005039DF4D92940000006B483045022100F228CC33D6EAAE7C0631741D1D0DD1EE02ECF725DDEFB1D02C877B3E449AA588022052C50C407B0217EE829BC1392971198ED7D08D18A5ABF90C13D9A81F20D7EA65C2210265BD8F8378E28817B5CBE47B08E326FC9972F27D1A354A85F43888507B10A497FFFFFFFF4DFCB8A82E6BFA8EB78BA4E66F0142B49D685D3036094A7F490DB544007E2292560000006B483045022100A82557798CCA2E6D8F00FBB49A9DE767BB2079E90B615DF29E7F44A870BBA43C02207B2B038237D55F962046B8046E53DF428999D716EEC2B980A927ADD5AE3A607AC22102463CABC398AAC0B7239F1AB82D0794B4E9FF87D4DBBE8747E5A94586485013DCFFFFFFFFEAEACA9F9CDE43599A95F529769BE324C910E0BE55BC84E1F1E92F0DE60F82842A0000006A473044022041765D681A868D6898F1931ECA896B624C7796DF89A7C80004AEFCD4A84D0A19022053ABCE69D529BE59BBC859D4314C2E093FB2C24823001A396DCE4CD7B2F21AA7C2210364BB8517C6A28CF7253DAEBBBA7064A4216125DE6476426E74480A3371B92D42FFFFFFFF25DB850D2664BA6B4DEADC76366DA35C1780C4B937E6DF473C602B49C2F47688380100006A47304402202145BEFCBD10A3D97AF74E264AEFBB6931227FF723BE6A680D277B185E25919902205C1769C6BF8F036F57B092F428C06E39081AF979DE35415AF6C74B294BDD4211C22103B04A47F53CF3BB0F7B00088D453E36618148B9261FAEF8CE8F6B3FA3DFEFBDCAFFFFFFFF01031864CD2E0000001976A91465BD7B5E75C7450F77976954A91DE75C73BEB4CE88AC00000000`