Skip to content

Commit ee40cf7

Browse files
authored
Harden and standardize BTMS packages (#352)
* harden and standardize BTMS packages * address BTMS quality feedback * test(btms): cover defensive parsing branches
1 parent 96ac096 commit ee40cf7

49 files changed

Lines changed: 2923 additions & 1729 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎governance/repository-health/contract-baseline.json‎

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"schemaVersion": 1,
33
"recordedAt": "2026-07-26",
4-
"findingCount": 94,
4+
"findingCount": 83,
55
"findings": [
66
{
77
"id": ".::missing-script::format:check",
@@ -207,14 +207,6 @@
207207
"id": "packages/network/ts-p2p::missing-script::typecheck",
208208
"message": "Profile node-library requires script typecheck"
209209
},
210-
{
211-
"id": "packages/overlays/btms-backend::missing-script::format:check",
212-
"message": "Profile private-library requires script format:check"
213-
},
214-
{
215-
"id": "packages/overlays/btms-backend::missing-script::typecheck",
216-
"message": "Profile private-library requires script typecheck"
217-
},
218210
{
219211
"id": "packages/overlays/gasp-core::missing-script::format:check",
220212
"message": "Profile dual-runtime-library requires script format:check"
@@ -303,42 +295,6 @@
303295
"id": "packages/verifast::missing-script::pack:check",
304296
"message": "Profile wasm-library requires script pack:check"
305297
},
306-
{
307-
"id": "packages/wallet/btms-permission-module::missing-script::format:check",
308-
"message": "Profile node-library requires script format:check"
309-
},
310-
{
311-
"id": "packages/wallet/btms-permission-module::missing-script::lint",
312-
"message": "Profile node-library requires script lint"
313-
},
314-
{
315-
"id": "packages/wallet/btms-permission-module::missing-script::pack:check",
316-
"message": "Profile node-library requires script pack:check"
317-
},
318-
{
319-
"id": "packages/wallet/btms-permission-module::missing-script::test",
320-
"message": "Profile node-library requires script test"
321-
},
322-
{
323-
"id": "packages/wallet/btms-permission-module::missing-script::test:coverage",
324-
"message": "Profile node-library requires script test:coverage"
325-
},
326-
{
327-
"id": "packages/wallet/btms-permission-module::missing-script::typecheck",
328-
"message": "Profile node-library requires script typecheck"
329-
},
330-
{
331-
"id": "packages/wallet/btms::missing-script::format:check",
332-
"message": "Profile node-library requires script format:check"
333-
},
334-
{
335-
"id": "packages/wallet/btms::missing-script::pack:check",
336-
"message": "Profile node-library requires script pack:check"
337-
},
338-
{
339-
"id": "packages/wallet/btms::missing-script::typecheck",
340-
"message": "Profile node-library requires script typecheck"
341-
},
342298
{
343299
"id": "packages/wallet/ts-wallet-relay::missing-script::format:check",
344300
"message": "Profile cli-library requires script format:check"

‎packages/overlays/btms-backend/README.md‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ BTMS is a UTXO-based token protocol built on the BSV blockchain that enables the
99
## Role in BTMS
1010

1111
The backend is the BTMS overlay network layer:
12+
1213
- **Topic Manager** enforces protocol validity.
1314
- **Lookup Service** indexes token state for queries.
1415

15-
## Related Docs
16+
## Related Documentation
1617

17-
- Project index: [`../README.md`](../README.md)
18-
- Main developer package (`@bsv/btms`): [`../core/README.md`](../core/README.md)
19-
- Frontend app and live deployment (`https://btms.metanet.app`): [`../frontend/README.md`](../frontend/README.md)
20-
- CARS deployment config: [`../deployment-info.json`](../deployment-info.json)
18+
- [ts-stack repository overview](../../../README.md)
19+
- [BTMS library](../../wallet/btms/README.md)
20+
- [BTMS wallet permission module](../../wallet/btms-permission-module/README.md)
2121

2222
## Features
2323

@@ -39,7 +39,7 @@ npm install
3939
The `BTMSTopicManager` validates transactions and determines which outputs should be admitted to the overlay:
4040

4141
```typescript
42-
import { BTMSTopicManager } from '@bsv/backend'
42+
import { BTMSTopicManager } from '@bsv/btms-backend'
4343

4444
const topicManager = new BTMSTopicManager()
4545

@@ -53,7 +53,7 @@ const result = await topicManager.identifyAdmissibleOutputs(beef, previousCoins)
5353
The `BTMSLookupService` indexes admitted tokens and provides query capabilities:
5454

5555
```typescript
56-
import BTMSLookupServiceFactory from '@bsv/backend'
56+
import { BTMSLookupServiceFactory } from '@bsv/btms-backend'
5757
import { MongoClient } from 'mongodb'
5858

5959
const client = new MongoClient('mongodb://localhost:27017')
@@ -118,6 +118,7 @@ npm run lint
118118
## API Documentation
119119

120120
For detailed API documentation, see:
121+
121122
- [Topic Manager Docs](./src/docs/BTMSTopicManagerDocs.ts)
122123
- [Lookup Service Docs](./src/docs/BTMSLookupDocs.ts)
123124

@@ -156,6 +157,7 @@ The storage manager automatically creates the following indexes:
156157
BTMS overlay backend is designed to be deployed as a CARS project. The `deployment-info.json` file defines the topic managers and lookup services to use:
157158

158159
Example:
160+
159161
```json
160162
{
161163
"schema": "bsv-app",
@@ -184,7 +186,7 @@ Example:
184186

185187
## License
186188

187-
See LICENSE.txt
189+
Open BSV License version 6. See [LICENSE.txt](./LICENSE.txt).
188190

189191
## Support
190192

‎packages/overlays/btms-backend/jest.config.js‎

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,23 @@ export default {
33
testEnvironment: 'node',
44
extensionsToTreatAsEsm: ['.ts'],
55
moduleNameMapper: {
6-
'^(\\.{1,2}/.*)\\.js$': '$1',
6+
'^(\\.{1,2}/.*)\\.js$': '$1'
77
},
88
transform: {
9-
'^.+\\.ts$': ['ts-jest', {
10-
useESM: true,
11-
tsconfig: {
12-
module: 'ESNext',
13-
moduleResolution: 'bundler',
14-
esModuleInterop: true,
15-
allowSyntheticDefaultImports: true
9+
'^.+\\.ts$': [
10+
'ts-jest',
11+
{
12+
useESM: true,
13+
tsconfig: {
14+
module: 'ESNext',
15+
moduleResolution: 'bundler',
16+
esModuleInterop: true,
17+
allowSyntheticDefaultImports: true
18+
}
1619
}
17-
}],
20+
]
1821
},
19-
transformIgnorePatterns: [
20-
'node_modules/(?!(@bsv)/)',
21-
],
22-
testMatch: [
23-
'**/__tests__/**/*.test.ts',
24-
'**/?(*.)+(spec|test).ts'
25-
],
26-
collectCoverageFrom: [
27-
'src/**/*.ts',
28-
'!src/**/*.d.ts',
29-
'!src/**/__tests__/**'
30-
]
22+
transformIgnorePatterns: ['node_modules/(?!(@bsv)/)'],
23+
testMatch: ['**/__tests__/**/*.test.ts', '**/?(*.)+(spec|test).ts'],
24+
collectCoverageFrom: ['src/**/*.ts', '!src/**/*.d.ts', '!src/**/__tests__/**']
3125
}

‎packages/overlays/btms-backend/package.json‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
"test:build": "npm run build && jest",
2828
"test:watch": "jest --watch",
2929
"test:coverage": "jest --coverage",
30-
"lint": "oxlint src",
30+
"lint": "oxlint src --deny-warnings",
3131
"build": "tsc -b",
32+
"format:check": "pnpm --workspace-root exec prettier --check \"packages/overlays/btms-backend/src/**/*.ts\" \"packages/overlays/btms-backend/README.md\" \"packages/overlays/btms-backend/*.{js,json,ts}\"",
33+
"typecheck": "tsc --project tsconfig.typecheck.json",
3234
"prepublish": "npm run build",
3335
"doc": "ts2md --inputFilename=mod.ts --outputFilename=API.md --filenameSubstring=API --firstHeadingLevel=1"
3436
},

‎packages/overlays/btms-backend/src/lookup-services/BTMSLookupServiceFactory.ts‎

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import { BTMSStorageManager } from './BTMSStorageManager.js'
2-
import { AdmissionMode, LookupFormula, LookupQuestion, LookupService, OutputAdmittedByTopic, OutputSpent, SpendNotificationMode } from '@bsv/overlay'
2+
import {
3+
AdmissionMode,
4+
LookupFormula,
5+
LookupQuestion,
6+
LookupService,
7+
OutputAdmittedByTopic,
8+
OutputSpent,
9+
SpendNotificationMode
10+
} from '@bsv/overlay'
311
import { LockingScript, PushDrop, Transaction, Utils } from '@bsv/sdk'
412
import { Db } from 'mongodb'
513
import { btmsProtocol, BTMSLookupResult, BTMSQuery, BTMSRecord } from './types.js'
@@ -16,9 +24,9 @@ class BTMSLookupService implements LookupService {
1624
private static readonly TOPIC = 'tm_btms'
1725
private static readonly SERVICE_ID = 'ls_btms'
1826

19-
constructor (public storageManager: BTMSStorageManager) { }
27+
constructor(public storageManager: BTMSStorageManager) {}
2028

21-
private isLikelySignatureField (field: number[]): boolean {
29+
private isLikelySignatureField(field: number[]): boolean {
2230
if (field.length < 40) {
2331
return false
2432
}
@@ -42,7 +50,11 @@ class BTMSLookupService implements LookupService {
4250
return printable / Math.max(asText.length, 1) < 0.8
4351
}
4452

45-
private decodeAdmittedToken (lockingScript: LockingScript, txid: string, outputIndex: number): {
53+
private decodeAdmittedToken(
54+
lockingScript: LockingScript,
55+
txid: string,
56+
outputIndex: number
57+
): {
4658
assetId: string
4759
amount: number
4860
metadata?: string
@@ -72,9 +84,7 @@ class BTMSLookupService implements LookupService {
7284
metadata = Utils.toUTF8(decoded.fields[btmsProtocol.metadata])
7385
}
7486

75-
const assetId = assetIdField === 'ISSUE'
76-
? `${txid}.${outputIndex}`
77-
: assetIdField
87+
const assetId = assetIdField === 'ISSUE' ? `${txid}.${outputIndex}` : assetIdField
7888

7989
return {
8090
assetId,
@@ -84,7 +94,7 @@ class BTMSLookupService implements LookupService {
8494
}
8595
}
8696

87-
async outputAdmittedByTopic (payload: OutputAdmittedByTopic): Promise<void> {
97+
async outputAdmittedByTopic(payload: OutputAdmittedByTopic): Promise<void> {
8898
if (payload.mode !== 'locking-script') {
8999
throw new Error('Invalid payload mode')
90100
}
@@ -95,35 +105,32 @@ class BTMSLookupService implements LookupService {
95105
}
96106

97107
try {
98-
const { assetId, amount, metadata, ownerKey } = this.decodeAdmittedToken(lockingScript, txid, outputIndex)
99-
100-
await this.storageManager.storeRecord(
108+
const { assetId, amount, metadata, ownerKey } = this.decodeAdmittedToken(
109+
lockingScript,
101110
txid,
102-
outputIndex,
103-
assetId,
104-
amount,
105-
ownerKey,
106-
metadata
111+
outputIndex
107112
)
113+
114+
await this.storageManager.storeRecord(txid, outputIndex, assetId, amount, ownerKey, metadata)
108115
} catch (error) {
109116
console.error('Error processing BTMS output:', error)
110117
throw error
111118
}
112119
}
113120

114-
async outputSpent (payload: OutputSpent): Promise<void> {
121+
async outputSpent(payload: OutputSpent): Promise<void> {
115122
if (payload.mode !== 'none') throw new Error('Invalid payload mode')
116123
const { topic, txid, outputIndex } = payload
117124
if (topic !== BTMSLookupService.TOPIC) return
118125

119126
await this.storageManager.deleteRecord(txid, outputIndex)
120127
}
121128

122-
async outputEvicted (txid: string, outputIndex: number): Promise<void> {
129+
async outputEvicted(txid: string, outputIndex: number): Promise<void> {
123130
await this.storageManager.deleteRecord(txid, outputIndex)
124131
}
125132

126-
async lookup (question: LookupQuestion): Promise<LookupFormula> {
133+
async lookup(question: LookupQuestion): Promise<LookupFormula> {
127134
if (question.query === undefined || question.query === null) {
128135
throw new Error('A valid query must be provided')
129136
}
@@ -149,11 +156,7 @@ class BTMSLookupService implements LookupService {
149156
query.sortOrder
150157
)
151158
} else {
152-
results = await this.storageManager.findAllRecords(
153-
query.limit,
154-
query.skip,
155-
query.sortOrder
156-
)
159+
results = await this.storageManager.findAllRecords(query.limit, query.skip, query.sortOrder)
157160
}
158161

159162
const lookupResults: BTMSLookupResult[] = []
@@ -163,9 +166,9 @@ class BTMSLookupService implements LookupService {
163166
txid: result.txid,
164167
outputIndex: result.outputIndex,
165168
history: query.history
166-
? async (beef: number[], outputIndex: number, currentDepth: number) => {
167-
return await this.historySelector(beef, outputIndex, result.assetId)
168-
}
169+
? async (beef: number[], outputIndex: number, _currentDepth: number) => {
170+
return await this.historySelector(beef, outputIndex, result.assetId)
171+
}
169172
: undefined
170173
})
171174
}
@@ -176,7 +179,11 @@ class BTMSLookupService implements LookupService {
176179
/**
177180
* History selector for determining which outputs to include in chain tracking
178181
*/
179-
private async historySelector (beef: number[], outputIndex: number, assetId?: string): Promise<boolean> {
182+
private async historySelector(
183+
beef: number[],
184+
outputIndex: number,
185+
assetId?: string
186+
): Promise<boolean> {
180187
try {
181188
const tx = Transaction.fromBEEF(beef)
182189
const output = tx.outputs[outputIndex]
@@ -192,17 +199,17 @@ class BTMSLookupService implements LookupService {
192199
}
193200

194201
return true
195-
} catch (_e) {
202+
} catch {
196203
// Malformed BEEF or script — output is not a valid BTMS token; exclude from history
197204
return false
198205
}
199206
}
200207

201-
async getDocumentation (): Promise<string> {
208+
async getDocumentation(): Promise<string> {
202209
return docs
203210
}
204211

205-
async getMetaData (): Promise<{
212+
async getMetaData(): Promise<{
206213
name: string
207214
shortDescription: string
208215
iconURL?: string
@@ -217,7 +224,7 @@ class BTMSLookupService implements LookupService {
217224
}
218225

219226
// Factory function
220-
function createBTMSLookupService (db: Db): BTMSLookupService {
227+
function createBTMSLookupService(db: Db): BTMSLookupService {
221228
return new BTMSLookupService(new BTMSStorageManager(db))
222229
}
223230
export default createBTMSLookupService

0 commit comments

Comments
 (0)