You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: SPEC.md
+30-2Lines changed: 30 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,7 +3,7 @@
3
3
Status: Draft (spec-driven design)
4
4
Owner: Token Host
5
5
Domain: `tokenhost.com`
6
-
Last updated: 2026-02-05
6
+
Last updated: 2026-03-23
7
7
Scope: Production system. All existing repos are legacy prototypes and are not binding.
8
8
9
9
This document defines the intended production design of the Token Host platform: a managed schema-to-dapp builder that generates and deploys smart contracts, generates a hosted UI, optionally provisions indexing, and publishes apps under a dedicated hosted-app origin (default `*.apps.tokenhost.com`, plus optional custom domains).
@@ -857,7 +857,7 @@ Implementation note: list methods MUST cap `limit` to a safe maximum (configurab
857
857
858
858
Recommended defaults (non-normative):
859
859
- If chain config provides `limits.lists.maxLimit` and/or `limits.lists.maxScanSteps`, the generator SHOULD use those values (or stricter).
860
-
- Otherwise, a safe default is `maxLimit=50` and `maxScanSteps = min(1000, maxLimit * 20)`.
860
+
- Otherwise, a safe default is `maxLimit=50` and `maxScanSteps=1000`.
861
861
- The UI SHOULD handle “short pages” (fewer than `limit` results) gracefully and SHOULD allow loading more using the next cursor (the smallest returned ID).
862
862
863
863
### 7.6 Update semantics
@@ -931,6 +931,25 @@ For each indexed field `f`:
931
931
- If a record’s field changes, the record ID MAY appear in multiple buckets historically; readers MUST validate current field value when interpreting results.
932
932
- Index accessors MUST be paginated (offset + limit) and MUST cap `limit`.
933
933
934
+
**Tokenized index (secondary index; when `onChainIndexing=true`)**
935
+
For each tokenized indexed field `f`:
936
+
-`indexC_f: mapping(bytes32 => uint256[])` mapping of normalized token key to append-only list of candidate record IDs.
937
+
- Tokenized indexes MUST apply deterministic extraction and normalization rules defined by the configured tokenizer.
938
+
- In v1, the only supported tokenizer is `hashtag`:
939
+
- source field type MUST be `string`,
940
+
- tokens begin with `#`,
941
+
- the token body is limited to ASCII letters, digits, and underscore,
942
+
- normalized token content is lowercased ASCII without the leading `#`,
943
+
- empty markers (e.g. a bare `#`) MUST be ignored,
944
+
- duplicate tokens from the same write MUST be de-duplicated before bucket append.
945
+
- If a record’s field changes, the record ID MAY appear in multiple token buckets historically; readers MUST validate current field value when interpreting results.
946
+
- Token extraction during create/update MUST be bounded. In v1, a safe default is:
947
+
- maximum extracted tokens per indexed field: `8`
948
+
- maximum normalized token length: `32` bytes
949
+
- writes that exceed those bounds MUST revert.
950
+
- If chain config provides stricter tokenized-index guidance (for example `limits.indexing.tokenized.maxTokens` and `limits.indexing.tokenized.maxTokenLength`), the generator SHOULD use those values or stricter values.
951
+
- Index accessors MUST be paginated (offset + limit) and MUST cap `limit`.
952
+
934
953
**Reference reverse index (when `onChainIndexing=true`)**
935
954
For reference fields `ref`:
936
955
-`refIndexC_ref: mapping(uint256 => uint256[])` mapping of referenced ID to append-only list of record IDs.
@@ -939,6 +958,7 @@ For reference fields `ref`:
939
958
**Index accessor semantics (normative)**
940
959
- Index accessors MUST return **candidate IDs only**. Callers MUST validate record existence, deletion status, and current field values via `getC`/`existsC` when correctness matters.
941
960
- For append-only equality/reference indexes, ordering MUST be insertion order (oldest to newest) within the bucket.
961
+
- For append-only tokenized indexes, ordering MUST be insertion order (oldest to newest) within the bucket.
942
962
- For swap-and-pop sets (e.g., owner index sets), ordering MUST NOT be relied upon.
943
963
- Index accessors MUST be paginated and MUST cap `limit` to avoid RPC timeouts.
944
964
@@ -957,6 +977,14 @@ This produces a uniform `bytes32` key space.
957
977
958
978
Normalization note: Token Host does not implicitly normalize string values on-chain. If an app requires case-insensitive uniqueness or trimmed matching, the schema/UI MUST enforce canonicalization by storing the canonical form as the field value.
959
979
980
+
For tokenized hashtag indexes:
981
+
- the lookup input is the normalized token body without the leading `#`,
982
+
- normalization MUST lowercase ASCII `A-Z` to `a-z`,
983
+
- only ASCII letters, digits, and underscore are preserved in the token body,
984
+
- the key is `keccak256(bytes(normalizedToken))`.
985
+
986
+
This allows generated UIs, self-hosted runtimes, and external indexers to derive the same lookup key without replaying contract internals.
987
+
960
988
### 7.9 Event model
961
989
962
990
Events are the primary integration surface for indexers and external analytics.
0 commit comments