Skip to content

Commit ff53337

Browse files
committed
Merge chalkeion-stellar/main into determined-001/main
The two repositories are independent - neither is a fork of the other - and their mains had diverged both ways: 42 commits here, 22 there (contributor PRs #33-#53: CAP-67 unified ingestion, abi-registry attestation and semantic taxonomy, the SEP-48 gap memo). This is a real two-way merge rather than a push, so every contributor commit on the chalkeion-stellar side keeps its authorship and its merge attribution. Conflicts and how they were resolved: - packages/abi-registry/package.json - union of both bin entries (abi-registry, abi-registry-generate, orbital-codegen); kept the newer @stellar/stellar-sdk ^16.1.0 and added yargs, which the verify CLI needs. - packages/abi-registry/src/index.ts - both sides only appended exports; kept both blocks. - packages/abi-registry/test/ChainedAbiRegistryClient.test.ts - both sides appended a describe block at end of file; kept both. - packages/pulse-core/src/EventEngine.ts - chalkeion-stellar extracted withTimestampDate into src/timestampDate.ts while this side still defined it locally, which collided with the new import (TS2440). Dropped the local copy - the extracted one is identical - and kept the refcount keys from #1000. - docs/COOKBOOK.md - both sides added recipes over the same numbering. Kept this side's 10-18 and renumbered the incoming unified-ingestion recipe to 19. - pnpm-lock.yaml - regenerated from the merged manifests rather than hand-resolved. One integration failure the merge itself produced: openData.test.ts derives the taxonomy from pulse-core's exhaustive describeEvent switch, and the incoming CAP-67 work added asset.clawback and fee.incurred without corresponding open-data records. Added both to generate-open-data.mjs and regenerated the artifacts (46 records). Verified on the merged tree: pnpm build, lint, format:check, typecheck of all five projects, Horizon type-drift check, and the suites for pulse-core (698), abi-registry (456), pulse-notify (77), anchor-sdk (72), orbital-indexer (8) and apps/web (40).
2 parents 78b9587 + a67aa0e commit ff53337

79 files changed

Lines changed: 7194 additions & 142 deletions

File tree

Some content is hidden

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

apps/web/public/data/integrity.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{
22
"schemaVersion": "1.0.0",
3-
"generatedAt": "2026-08-02T08:51:13.726Z",
3+
"generatedAt": "2026-08-10T00:48:39.648Z",
44
"files": {
55
"taxonomy.json": {
6-
"sha256": "2bef56f82865032f469967bb7d455c003d65f0d56ee01404a22922e4e2a05630",
7-
"bytes": 17794,
8-
"recordCount": 44
6+
"sha256": "2a382292be359e00a3d34f140e8a8d6c445108d2bacc20db481a3780da9608ff",
7+
"bytes": 18409,
8+
"recordCount": 46
99
},
1010
"labels.json": {
11-
"sha256": "82b170efb9d60d38c718cd19c8584588a2a48806b02a11f0a0579e1699890ba6",
11+
"sha256": "2955050fc590210f90111f33d51c8d7ee689063da6bf8744d11dbc79e9c226c4",
1212
"bytes": 2624,
1313
"recordCount": 5
1414
},

apps/web/public/data/labels.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"schemaVersion": "1.0.0",
3-
"generatedAt": "2026-08-02T08:51:13.726Z",
3+
"generatedAt": "2026-08-10T00:48:39.648Z",
44
"recordCount": 5,
55
"records": [
66
{

apps/web/public/data/taxonomy.json

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"schemaVersion": "1.0.0",
3-
"generatedAt": "2026-08-02T08:51:13.726Z",
4-
"recordCount": 44,
3+
"generatedAt": "2026-08-10T00:48:39.648Z",
4+
"recordCount": 46,
55
"records": [
66
{
77
"id": "payment.received",
@@ -192,6 +192,24 @@
192192
"description": "Key-value pair removed from account storage.",
193193
"source": "horizon"
194194
},
195+
{
196+
"id": "asset.clawback",
197+
"name": "Asset Clawback",
198+
"type": "classic",
199+
"category": "assets",
200+
"eventType": "asset.clawback",
201+
"description": "Issuer clawed back a clawback-enabled asset from an account.",
202+
"source": "soroban-rpc"
203+
},
204+
{
205+
"id": "fee.incurred",
206+
"name": "Fee Incurred",
207+
"type": "classic",
208+
"category": "fees",
209+
"eventType": "fee.incurred",
210+
"description": "Network fee charged for a classic transaction, emitted as a discrete event by CAP-67. No Horizon-derived equivalent exists.",
211+
"source": "soroban-rpc"
212+
},
195213
{
196214
"id": "contract.invoked",
197215
"name": "Soroban Contract Invoked",

data/integrity.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{
22
"schemaVersion": "1.0.0",
3-
"generatedAt": "2026-08-02T08:51:13.726Z",
3+
"generatedAt": "2026-08-10T00:48:39.648Z",
44
"files": {
55
"taxonomy.json": {
6-
"sha256": "2bef56f82865032f469967bb7d455c003d65f0d56ee01404a22922e4e2a05630",
7-
"bytes": 17794,
8-
"recordCount": 44
6+
"sha256": "2a382292be359e00a3d34f140e8a8d6c445108d2bacc20db481a3780da9608ff",
7+
"bytes": 18409,
8+
"recordCount": 46
99
},
1010
"labels.json": {
11-
"sha256": "82b170efb9d60d38c718cd19c8584588a2a48806b02a11f0a0579e1699890ba6",
11+
"sha256": "2955050fc590210f90111f33d51c8d7ee689063da6bf8744d11dbc79e9c226c4",
1212
"bytes": 2624,
1313
"recordCount": 5
1414
},

data/labels.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"schemaVersion": "1.0.0",
3-
"generatedAt": "2026-08-02T08:51:13.726Z",
3+
"generatedAt": "2026-08-10T00:48:39.648Z",
44
"recordCount": 5,
55
"records": [
66
{

data/taxonomy.json

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"schemaVersion": "1.0.0",
3-
"generatedAt": "2026-08-02T08:51:13.726Z",
4-
"recordCount": 44,
3+
"generatedAt": "2026-08-10T00:48:39.648Z",
4+
"recordCount": 46,
55
"records": [
66
{
77
"id": "payment.received",
@@ -192,6 +192,24 @@
192192
"description": "Key-value pair removed from account storage.",
193193
"source": "horizon"
194194
},
195+
{
196+
"id": "asset.clawback",
197+
"name": "Asset Clawback",
198+
"type": "classic",
199+
"category": "assets",
200+
"eventType": "asset.clawback",
201+
"description": "Issuer clawed back a clawback-enabled asset from an account.",
202+
"source": "soroban-rpc"
203+
},
204+
{
205+
"id": "fee.incurred",
206+
"name": "Fee Incurred",
207+
"type": "classic",
208+
"category": "fees",
209+
"eventType": "fee.incurred",
210+
"description": "Network fee charged for a classic transaction, emitted as a discrete event by CAP-67. No Horizon-derived equivalent exists.",
211+
"source": "soroban-rpc"
212+
},
195213
{
196214
"id": "contract.invoked",
197215
"name": "Soroban Contract Invoked",

docs/ARCHITECTURE.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ flowchart LR
4747
subgraph Stellar["Stellar network"]
4848
Horizon["Horizon REST + SSE"]
4949
RPC["Stellar RPC<br/>Soroban events"]
50+
Unified["Stellar RPC getEvents<br/>CAP-67 unified stream<br/>🛠️ Wave 1.6"]
5051
end
5152
5253
subgraph Subscribe["Subscription plane<br/>@orbital-stellar/pulse-core"]
@@ -67,6 +68,7 @@ flowchart LR
6768
6869
Horizon --> Engine
6970
RPC --> Engine
71+
Unified -.->|"see §4.1"| Engine
7072
Engine --> Cursor
7173
Engine --> Normalize --> Watcher
7274
Watcher --> Sign --> YourEndpoint["Your HTTPS endpoint"]
@@ -215,6 +217,74 @@ and the per-event TypeScript shapes live in
215217

216218
---
217219

220+
## 4.1 Unified event ingestion (CAP-67) 🛠️
221+
222+
Protocol 23's CAP-67 lets classic asset movements (transfer, mint, burn,
223+
clawback, `set_authorized`) emit Soroban-format events in a single stream,
224+
fetched the same way contract events already are - `SorobanRpcClient.getEvents()`.
225+
This is a third transport alongside Horizon SSE and the Soroban contract-event
226+
subscriber, tracked as Wave 1.6 in [`ROADMAP.md`](../ROADMAP.md) and designed
227+
in [`docs/design/cap67-mapping.md`](./design/cap67-mapping.md) (see also
228+
[`docs/CAP-67-Event-Mapping.md`](./CAP-67-Event-Mapping.md) for the taxonomy
229+
rationale). As of this writing the pieces below exist as independent,
230+
tested building blocks; wiring them into `EventEngine`'s live delivery path -
231+
so a family routed to "unified" actually stops arriving via Horizon and
232+
starts arriving via the unified stream instead - is still forthcoming.
233+
234+
**Ingestion mode.** `CoreConfig.ingestion?: "unified" | "horizon" | "auto"`
235+
(default `"horizon"`) selects a transport preference. `"horizon"` is the
236+
default specifically so that existing consumers see zero behavior change
237+
until they opt in. `"auto"` is meant to prefer `"unified"` once the
238+
configured Soroban RPC is confirmed CAP-67-capable, falling back to
239+
`"horizon"` otherwise. The flag is validated at construction (an unknown
240+
value throws) and reported back via `engine.status().ingestion`.
241+
242+
**Routing decision.** Not every event family has a CAP-67 equivalent - per
243+
the mapping design doc, only classic payments (transfer/mint/burn) and
244+
trustline authorization (`set_authorized`) do. Everything else (account
245+
options, account creation, account merges, trustline limit changes, offers,
246+
bump-sequence, `manage_data`, claimable balances, liquidity pools) has no
247+
unified-stream equivalent and stays Horizon-only under every mode.
248+
`resolveFamilyTransport(family, effectiveMode)` is the pure function
249+
encoding this:
250+
251+
| Event family | Under `"horizon"` mode | Under `"unified"` mode |
252+
|---|---|---|
253+
| `payment` (transfer/mint/burn) | Horizon | Unified |
254+
| `trustlineAuth` (`set_authorized`) | Horizon | Unified |
255+
| `trustlineLimit`, `accountCreated`, `accountOptions`, `accountMerge`, `offer`, `bumpSequence`, `manageData`, `claimableBalance`, `liquidityPool` | Horizon | Horizon |
256+
257+
`"auto"` mode is designed to resolve to one of the two columns above (never
258+
a third behavior) based on the CAP-67-capability probe described above -
259+
that probe isn't implemented yet, so `"auto"` currently behaves like
260+
`"horizon"` in practice.
261+
262+
**Dedupe window.** During a routing transition - a mode switch, or `"auto"`
263+
falling back and recovering - both transports can briefly observe the same
264+
on-chain movement, which would otherwise reach a `Watcher` twice.
265+
`deriveDedupeKey({ txHash, index })` derives one key per movement regardless
266+
of which transport observed it (a Horizon operation and a CAP-67 event both
267+
carry a transaction hash; `index` is the operation's position in the tx, or
268+
the unified event's ordinal). `DedupeWindow` holds a bounded set of
269+
recently-seen keys ahead of `Watcher` fan-out - `seenBefore(key)` returns
270+
`true` for a duplicate, and the oldest key is evicted once the window is at
271+
capacity, so memory never grows unbounded no matter how long the engine runs.
272+
273+
```mermaid
274+
flowchart LR
275+
HorizonOp["Horizon operation"] --> Route
276+
UnifiedEvt["CAP-67 unified event"] --> Route
277+
Route{"resolveFamilyTransport<br/>(family, mode)"} --> Normalize["normalize()"]
278+
Normalize --> Dedupe{"DedupeWindow<br/>.seenBefore(txHash:index)"}
279+
Dedupe -->|first time| Watcher["Watcher fan-out"]
280+
Dedupe -->|duplicate| Drop(["dropped"])
281+
```
282+
283+
A COOKBOOK recipe for migrating an existing Horizon-only deployment onto
284+
unified ingestion, once live routing lands, is planned but not yet written.
285+
286+
---
287+
218288
## 5. Reconnection, backoff, and rate limits
219289

220290
Horizon's SSE stream is not durable. Network blips, process restarts, and
@@ -489,6 +559,8 @@ orbital_stellar/
489559
- [`CHANGELOG.md`](../CHANGELOG.md) - Per-release notes
490560
- [`docs/semantic-layer.md`](./semantic-layer.md) - Semantic taxonomy, labels, precedence, honesty rule
491561
- [`docs/proposal.md`](./proposal.md) - SCF grant proposal
562+
- [`docs/design/cap67-mapping.md`](./design/cap67-mapping.md) - CAP-67 → `NormalizedEvent` mapping design doc (§4.1)
563+
- [`docs/CAP-67-Event-Mapping.md`](./CAP-67-Event-Mapping.md) - CAP-67 event taxonomy rationale (§4.1)
492564
- Per-package READMEs:
493565
[`pulse-core`](../packages/pulse-core/README.md),
494566
[`pulse-webhooks`](../packages/pulse-webhooks/README.md),

0 commit comments

Comments
 (0)