Skip to content

Commit 98442ed

Browse files
warmidrisclaude
andcommitted
fix: preserve case in watched contract matching
Stacks contract identifiers are case-sensitive — two contracts can share the same name with different address casing. Case-insensitive normalization was unsafe and could cause incorrect contract matches. - Remove .toLowerCase() from normalizeWatchedContracts and contractMatches - Whitespace trimming of STACKFLOW_CONTRACTS entries is preserved - Update test to use correct-case identifier (with padding to exercise trim) - Correct README to reflect case-sensitive matching Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b8aeb10 commit 98442ed

File tree

3 files changed

+4
-5
lines changed

3 files changed

+4
-5
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ STACKFLOW_NODE_FORWARDING_REVEAL_RETRY_MAX_ATTEMPTS=20
258258

259259
If `STACKFLOW_CONTRACTS` is omitted, the stackflow-node automatically monitors any
260260
contract identifier matching `*.stackflow*`.
261-
When set, `STACKFLOW_CONTRACTS` entries are trimmed and matched case-insensitively.
261+
When set, `STACKFLOW_CONTRACTS` entries are trimmed of whitespace and matched case-sensitively (Stacks contract identifiers are case-sensitive).
262262
The current implementation uses Node's `node:sqlite` module for persistence.
263263
`STACKFLOW_NODE_SIGNATURE_VERIFIER_MODE` supports `readonly` (default),
264264
`accept-all`, and `reject-all`. Non-`readonly` modes are intended for testing.

server/src/observer-parser.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ function collectContractEventCandidates(
241241

242242
function normalizeWatchedContracts(watchedContracts: string[]): string[] {
243243
return watchedContracts
244-
.map((contract) => contract.trim().toLowerCase())
244+
.map((contract) => contract.trim())
245245
.filter((contract) => contract.length > 0);
246246
}
247247

@@ -254,8 +254,7 @@ function contractMatches(
254254
}
255255

256256
if (watchedContracts.length > 0) {
257-
const normalizedContractId = contractId.toLowerCase();
258-
return watchedContracts.some((candidate) => candidate === normalizedContractId);
257+
return watchedContracts.some((candidate) => candidate === contractId);
259258
}
260259

261260
return DEFAULT_STACKFLOW_CONTRACT_PATTERN.test(contractId);

tests/stackflow-node-observer.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ describe('watchtower event parser', () => {
228228
};
229229

230230
const events = extractStackflowPrintEvents(payload, {
231-
watchedContracts: [' st1pqhqkv0rjxzfy1dgx8mnsnyve3vgzjsrtpgzgm.custom-flow '],
231+
watchedContracts: [` ${CLOSER}.custom-flow `],
232232
});
233233

234234
expect(events).toHaveLength(1);

0 commit comments

Comments
 (0)