Skip to content

fix(receive): stamp extended delegatee claim packets - #348

Open
Kukks wants to merge 1 commit into
mainfrom
fix/extended-claim-ciphertext-20261111
Open

Kukks wants to merge 1 commit into
mainfrom
fix/extended-claim-ciphertext-20261111

Conversation

@Kukks

@Kukks Kukks commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

The pinned swap codec recognizes only a 93-byte ciphertext, so the larger encrypted receive terms produced by ts-sdk #1206 were treated as legacy ciphertext and omitted from funding. This accepts the existing type-4/TLV format with extended ciphertext, preserves the original opaque bytes, and appends only the solver's own covenant script and taptree.

The released codec remains the canonical fast path. A strict local compatibility fallback checks complete TLV bounds, key width and duplicate-field semantics; it can be removed when the pinned swap package supports extended terms. Valid extended packets also bypass covclaimd Reveal for adopted funding with a null stampedAt, because that legacy service cannot decrypt the longer payload. Existing raw/preimage-only packets and adopted legacy Reveal behavior stay compatible. No unpublished dependency or new JSON envelope is introduced; this supersedes #270 as written.

The template engine owns receiver/minimum authorization, clarified in meta #35 for template/v1. Current main removed onchain receive in #292, so this server change covers its existing Lightning path and leaves the onchain drain guard intact. Enabling the extended client packet still requires deploying compatible solver support and activating the selected template on delegatee.

The focused receive baseline passed 198 tests. Seven new regressions failed before the fix; the final focused suite passes 212, including the exact public SDK ciphertext and fresh/adopted funding. Build, typecheck, formatting and diff checks pass. Full Windows units reached 2,634 passes and two failures outside the changed receive code; the boundary scan passed on unchanged isolated retry, while the example lockup comparison hit its existing 5-second limit. The same example timeout reproduces with both changed runtime files restored to pristine main. No tests or timeouts were changed. Exact-head Linux CI passed all 6,578 units on Node 22 and 24, build/typecheck/format and both image smoke jobs; Lightning receive integration passed all 15 tests with no skips. All ten E2E groups passed; their report checks confirmed the expected files ran without skips. The actual Go template opened the SDK vector and passed nine positive/rejection scenarios without daemon product changes. Independent review and CodeRabbit found no actionable issues; formal protocol review remains separate from CI.

The optional authenticated predicate follow-up in SDK #1208 / executor #8 needs no further solver change. The actual compiled bdef5aa stamper preserved both 202/207-byte SDK packet bodies, including the public predicate in TLV4, while adding only its own covenant script. This transport proof is separate from a funded SDK flow. Arkana's exact-head COMMENTED review reports no blocking issues; its nonblocking observations were checked against source and answered.

@coderabbitai

coderabbitai Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The change adds extended claim packet parsing and stamping support. The receive orchestrator skips legacy reveal for extended packets. Tests cover packet parsing, stamping, and newly funded and adopted swaps.

Changes

Extended claim packet handling

Layer / File(s) Summary
Parse and stamp extended packets
packages/solver-corridors/src/receive/claimPacket.ts, test/receive/claimPacket.test.ts, test/receive/fixtures/delegateeReceiveTerms.json
The parser decodes and validates extended TLV packets. The packet-shape and stamp functions handle extended packets. Tests cover valid, malformed, and already-stamped packets.
Skip reveal for extended packets
packages/solver-corridors/src/receive/orchestrator.ts, test/receive/orchestrator.test.ts
The orchestrator skips legacy reveal for extended packets as well as stamped funding. Tests cover newly funded and adopted swaps.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant Orchestrator
  participant isExtendedClaimPacket
  participant ExtendedPacketParser
  participant Covclaimd
  Orchestrator->>isExtendedClaimPacket: Check claim packet
  isExtendedClaimPacket->>ExtendedPacketParser: Parse extended TLV
  ExtendedPacketParser-->>isExtendedClaimPacket: Packet or undefined
  isExtendedClaimPacket-->>Orchestrator: Extended packet status
  alt Extended packet or stamped funding
    Orchestrator->>Orchestrator: Skip reveal
  else Unstamped non-extended packet
    Orchestrator->>Covclaimd: Call reveal
  end
Loading

Suggested reviewers: d4rp4t

Merge Risk: Minimal · up to bdef5

The change lets extended encrypted receive terms bypass the legacy reveal step, with tests for both newly funded and adopted swaps. No concrete merge-blocking risk was found in the supplied evidence. Linux CI is still pending, so check it before merging.

Pre-merge checks: Passed 5

Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: stamping extended delegatee claim packets during receive handling.
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 4 files. (1 skipped: 1 unsupported.)

Finishing Touches

Generate docstrings

  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 58f14e01-7490-4602-b61a-c907aee755df
Commits

Reviewing files that changed from the base of the PR and between 0df685a and bdef5aa.

Files selected for processing: 5

  • packages/solver-corridors/src/receive/claimPacket.ts
  • packages/solver-corridors/src/receive/orchestrator.ts
  • test/receive/claimPacket.test.ts
  • test/receive/fixtures/delegateeReceiveTerms.json
  • test/receive/orchestrator.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

@arkana-ai-bot arkana-ai-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arkana review — #348

Overall: looks correct. Three observations below, none blocking.


What the diff does

The canonical claimPacketShape from @arkade-os/swap guards on ciphertextLength === SEALED_CIPHERTEXT_LENGTH (exactly 93 bytes), so extended-terms packets — which seal more than a bare preimage and produce a longer ciphertext — were silently downgraded to { kind: 'ciphertext' }. That caused claimPacketStamp to return undefined and stamping/funding to be skipped entirely. The fix is:

  1. extendedClaimPacketShape — a local TLV walker that accepts any ciphertext length > 93 bytes.
  2. The re-exported claimPacketShape tries the extended parser when the canonical one returns 'ciphertext' (fallback chain, not a replacement).
  3. claimPacketStamp now calls the wrapper instead of canonicalClaimPacketShape directly — this is the key correctness fix (packages/solver-corridors/src/receive/claimPacket.ts:62).
  4. revealToCovclaimd gains || isExtendedClaimPacket(row.claimPacket) to skip the reveal for extended packets, which covclaimd cannot decrypt (packages/solver-corridors/src/receive/orchestrator.ts:1136).

The original stampedAt-only guard comment ("an adopted output carries nothing the shape promises, and skipping the reveal on it strands the swap") is preserved for the legacy-packet adopted case, which still falls through to the reveal correctly.


Findings

1. revealedAt stays null permanently for extended-packet swaps — orchestrator.ts:1091

revealToCovclaimd exits early before store.patch(row.id, { revealed_at: ... }), so revealedAt is never set for these swaps. The whenFunded guard:

if (row.revealedAt === null && this.deps.covclaimd && row.claimPacket !== null) {
  await this.revealToCovclaimd(row)
}

evaluates to true on every tick for the whole funded lifetime (both fresh-stamped and adopted+extended). The call is cheap (~200-byte base64 decode + TLV walk, early return), so this is not a throughput concern. The swap settles correctly via the template claim path.

Worth verifying: does any monitoring query alert on funded && revealedAt IS NULL after a time threshold? If so, extended-packet swaps will fire it continuously. A comment alongside the guard or a brief note in the runbook would prevent a future false-alarm chase.

2. Duplicate 0x03 pubkey TLVs — claimPacket.ts:38

The extended parser is last-wins for all fields (consistent with covclaimd's DeserializeClaim and with the canonical ts-sdk parseTlv). The existing test 'bad duplicate key followed by valid key' only covers the case where the first 0x03 has an invalid length (1 byte), triggering return undefined before the second entry is reached. A packet containing two valid 33-byte 0x03 TLVs would silently accept the second key; this path is not tested. Not a security concern (both entries are compressed public keys the client chose), but worth a brief inline note or a simple test entry for documentation purposes.

3. Fixture field names — test/receive/fixtures/delegateeReceiveTerms.json

recipientSecretKey and ephemeralKey carry repeating-pattern test values (09...09, 11...11) and the description says "Public test key material". These are clearly not operational keys. No issue — just flagging for anyone who reviews the file without that context.


Protocol interactions verified

  • claimPacketStamp (claimPacket.ts:62–76): wraps to claimPacketShape, propagates covclaimdPubKey check (capital K, correctly normalised from the canonical lowercase form), appends arkade script only when needsArkadeScript is true, returns undefined on missing nonInteractiveClaim leaf. All paths unchanged in semantics from main except the new extended-packet branch. ✓
  • Adopted funding + extended packet (orchestrator.test.ts:1263): stampedAt stays null, fundCalls empty, revealCalls zero, state funded. ✓
  • Fresh funding + extended packet (orchestrator.test.ts:1263): stamp carries appendArkadeScript(body, nonInteractiveClaimArkadeScript) and correct tapTree, stampedAt non-null, revealCalls zero. ✓
  • Legacy packets (non-extended): both paths in the dual guard (stampedAt !== null || isExtendedClaimPacket(...)) leave the reveal logic entirely unmodified. ✓
  • // shortcut: remove this parser comment in claimPacket.ts:21 is the right form of scope-limiting a compatibility shim.

Kukks commented Nov 11, 2026

Copy link
Copy Markdown
Contributor Author

Checked the three nonblocking observations at bdef5aa. There is no repository monitoring/query consumer that treats funded + revealedAt == null as an alert; its runtime use is the legacy HTTP Reveal retry guard. Keeping null accurately records that extended packets did not use that API. The existing receive test also expects null on the packet-driven path.

The valid duplicate-key case is already covered by keeps the final ciphertext/key and existing script semantics: it appends a second valid 33-byte PUBKEY to the public SDK vector's existing key and asserts the final key is selected. The separate invalid-width duplicate test deliberately rejects the malformed packet. The repeating private material in the JSON fixture is public test material as identified in its description.

The optional predicate follow-up in SDK #1208 / executor #8 needs no additional solver change: the compiled bdef5aa stamper preserved both SDK predicate packets (202 and 207 bytes), including TLV 4, and only appended its own covenant script. These are transport proofs, distinct from a funded SDK flow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants