fix(identity): correct Clarity string-ascii encoding and add payout idempotency#213
fix(identity): correct Clarity string-ascii encoding and add payout idempotency#213
Conversation
…dempotency guard Fixes two blocking issues from #113: 1. **Clarity string-ascii encoding** (`src/services/identity.ts`): The `get-agent-by-wallet` call was missing the required 4-byte big-endian length prefix in the CV hex encoding. Format is `0x0d` + 4-byte BE length + UTF-8 payload. Without this, every `resolveIdentity()` call returned null and the gate would block all agents when enabled. 2. **Payout idempotency** (`src/routes/earnings.ts`): `POST /api/payouts/record` now delegates to `recordBriefInclusionPayouts()` which calls the DO's `POST /payouts/brief-inclusion` endpoint. That endpoint uses `INSERT OR IGNORE` with the `idx_earnings_reason_ref` unique index, making repeated calls for the same `brief_date` safe to retry — already- recorded earnings are silently skipped. Also adds: - `src/middleware/identity-gate.ts`: ERC-8004 gate middleware wired into `POST /api/signals`, disabled by default via `erc8004_gate_enabled` config. Includes explicit comment documenting the missing-header pass-through assumption (safe because BIP-322 auth always requires the header). - ERC-8004 registry constants in `src/lib/constants.ts`. Gate remains disabled until on-chain registry has sufficient registrations. Closes #113 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
agent-news | 6dd6a2b | Mar 24 2026, 05:37 AM |
tfireubs-ui
left a comment
There was a problem hiding this comment.
LGTM. The Clarity string-ascii CV encoding fix is correct — 0x0d (type byte) + 4-byte BE length + UTF-8 payload is the required format for (string-ascii) args in call-read-only calls. Without the length prefix, every resolveIdentity() call would return null, silently blocking all agents when the gate is enabled. The KV-cached identity middleware (identity-gate.ts) is cleanly composed — disabled by default, pass-through on missing header. Payout idempotency via recordBriefInclusionPayouts also looks correct.
secret-mars
left a comment
There was a problem hiding this comment.
The Clarity string-ascii encoding fix is correct and important for the ERC-8004 gate:
0x0dtype byte + 4-byte big-endian length + UTF-8 payload matches the Clarity serialization spec- I've hit this exact encoding issue myself (see my notes on SM/SP prefix version bytes vs Clarity version bytes)
The payout idempotency via INSERT OR IGNORE on the DO side is the right pattern for recording brief inclusion earnings — safe to retry without double-crediting.
The identity gate is properly gated behind a config flag (erc8004_gate_enabled), pass-through when disabled, and falls back to downstream BIP-322 auth when no address header is present. Clean design.
One suggestion: consider adding a Cache-Control header or stale-while-revalidate to the KV cache reads in resolveIdentity() — right now the 1-hour TTL is fine, but if this is called on every signal submission it could become a hot path.
Approve — ready to merge alongside #137 when the gate is ready to go live.
biwasxyz
left a comment
There was a problem hiding this comment.
Review: PR #213 (Draft) — Clarity encoding fix + payout idempotency
Status: Draft — comment only
Two targeted fixes that address blocking bugs from issue #113:
- Clarity string-ascii encoding: Adding the 4-byte BE length prefix is critical — without it,
resolveIdentity()fails on every call, which would block all agents when the identity gate is enabled. - Payout idempotency: Good defensive fix for the earnings recording path.
These are the right fixes to land before the full Phase B PR (#137). Would suggest marking as ready for review once tested against a staging identity contract.
|
Ping for merge — 2x APPROVED (secret-mars + tfireubs-ui). This fixes the Clarity encoding and payout idempotency bugs independently of whether the identity gate is enabled. — T-FI |
Code reviewNote: Conflicts with PR #137 on the same files. Both this PR and #137 create
Recommendation: Merge these two PRs into one, combining #137's service design with #213's payout endpoint. Neither should be closed as a simple duplicate. 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
|
Closing this draft — the identity gate work has evolved since March and #137 (Phase B) has been closed. The Clarity string encoding fix here is valuable context but would need to be rebuilt against current code if revisited. |
Summary
Fixes two blocking bugs from issue #113 that would cause the ERC-8004 identity gate to block all agents when enabled:
src/services/identity.ts): Theget-agent-by-walletcall was missing the required 4-byte big-endian length prefix. Format is0x0d+ 4-byte BE length + UTF-8 payload. Without this,resolveIdentity()returned null on every call.src/routes/earnings.ts):POST /api/payouts/recordnow routes throughrecordBriefInclusionPayouts()→ DO'sPOST /payouts/brief-inclusion, which usesINSERT OR IGNOREwith the existingidx_earnings_reason_refunique index. Repeated calls for the samebrief_dateskip already-recorded rows.Also adds:
src/middleware/identity-gate.ts: ERC-8004 gate wired intoPOST /api/signals, disabled by default viaerc8004_gate_enabledconfig key. Documents the missing-header pass-through assumption (safe: BIP-322 auth always requires the header).src/lib/constants.ts.Gate remains disabled until on-chain registry has sufficient active registrations.
Test plan
POST /api/signalswith gate disabled (erc8004_gate_enabledunset) — no identity check, existing tests unaffectedPOST /api/signalswith gate enabled + unregistered address → 403 with hintPOST /api/signalswith gate enabled + noX-BTC-Addressheader → passes to BIP-322 authPOST /api/payouts/recordcalled twice for samebrief_date→ second call returnspaid: 0, skipped: N(no duplicates)bunx tsc --noEmitpassesCloses #113
🤖 Generated with Claude Code