feat(agent): sip.sol tools — resolveSNS + sendPrivateToSNS#252
Merged
Conversation
Resolves a .sol domain to its SIP-STEALTH meta-address (spending + viewing hex keys) via @sip-protocol/sns-stealth. Read-only, intentionally NOT registered in FUND_MOVING_TOOLS — the composite sendPrivateToSNS tool (next commit) is the fund-mover and goes through SENTINEL preflight. - Tool descriptor matches sipher's AnthropicTool + executeXxx convention - Connection sourced via createConnection(loadNetworkConfig().clusterName) - Returns discriminated union: resolved | not-found | malformed | network-error - NetworkError caught + reified; unknown throws propagate - Domain normalization (trim + lowercase) before resolver call - 23 tests covering descriptor, validation, all 4 result paths, service interaction
sendPrivateToSNS routes a .sol domain to its SIP-STEALTH meta-address via
executeResolveSNS, builds the sip:solana:0x<spending>:0x<viewing> URI in the
0x-hex form sendTool expects, then delegates to executeSend (which derives
the one-time stealth address, builds Pedersen commitment, encrypts amount +
blinding, serializes the unsigned withdraw tx).
- Returns discriminated union: status=ok with composite resolved + send blocks,
or status=cannot-send with reason ∈ {no-domain, no-record, malformed-record,
network-error} when resolution fails
- Input field named `recipient` (the .sol domain) so the preflight gate's
input.recipient read at preflight-gate.ts works unchanged
- Registered in sentinel/preflight-rules.ts FUND_MOVING_TOOLS — blacklist,
known-repeat, dust rules apply against the .sol domain before execution
- Registered in agent.ts TOOLS + TOOL_EXECUTORS + SYSTEM_PROMPT alongside
resolveSNS (Task 18) so the LLM can discover and dispatch both
- 22 unit tests covering descriptor, validation, happy path with URI build
+ arg forwarding, all 4 cannot-send paths, service-error propagation from
both delegated tools
- Registry tests (tools.test.ts, pi-migration.test.ts) updated for new
count: 22 → 24 tools
Replaces plan's Task 20 HERALD smoke test — HERALD has X-only tools and
no fund-moving surface; the composite unit test exercises the resolve +
URI build + delegate path end-to-end without coupling to LLM determinism.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Phase D added @sip-protocol/sns-stealth which transitively pulls in @bonfida/spl-name-service@3.0.21. That package ships a broken ESM bundle (vendored borsh path resolution confuses tsx's ESM loader despite the file correctly exporting `serialize`). Plain Node ESM handles it fine, but tsx fails to instantiate the module graph at boot. This broke playwright in CI because its webServer used `pnpm --filter @sipher/agent dev` (tsx-based). Production is unaffected — Docker uses `node dist/index.js`, and the root sipher dev path uses tsup → node. Unit tests are unaffected — they mock sns-stealth. Fix scope (minimum): - playwright.config.ts webServer command: `agent dev` → `agent start` (start = `node dist/index.js`, identical to production boot path) - .github/workflows/e2e.yml: explicit `pnpm --filter @sipher/agent build` step before "Run Playwright" so the start command has a `dist/` to run Agent dev mode (`pnpm --filter @sipher/agent dev` directly) remains broken under tsx. A follow-up issue will track that separately — switching the agent's `dev` script to tsup or similar is out of scope for the Phase D feature PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase D of the sip.sol foundation — adds two new tools to the SIPHER agent so HERALD/Sipher chat can route private payments by
.solname.resolveSNS— read-only.sol→ SIP-STEALTH meta-address lookup via@sip-protocol/sns-stealth@^0.1.0. Returns discriminated union:resolved | not-found | malformed | network-error. NOT inFUND_MOVING_TOOLS— pure read.sendPrivateToSNS— composite tool. Resolves the domain, buildssip:solana:0x<spending>:0x<viewing>URI (matchingsend.ts's 0x-hex contract — NOT bs58), then delegates toexecuteSend. Returnsokwith compositeresolved + sendblocks orcannot-sendwith reason.sendPrivateToSNSadded toFUND_MOVING_TOOLS. Input field namedrecipient(the.soldomain) so the existing gate atagent.ts:169reads it unchanged for blacklist / known-repeat / dust evaluation before execution.agent.tsregistry +SYSTEM_PROMPTupdated.Tests: +47 (resolve-sns: 23, send-private-to-sns: 22, registry updates: 2).
pnpm test1446 → 1495 across 124 files.Plan deviations from
2026-05-11-sip-sol-foundation.mdlines 2118–2472new Connection(process.env.SIPHER_SOLANA_RPC ?? 'mainnet-beta')at the top of the tool file. That crashes at test load becauseloadNetworkConfig()throws fatal on unsetSIPHER_NETWORK/SIPHER_HELIUS_API_KEY. Adapted to construct theConnectionviacreateConnection(loadNetworkConfig().clusterName)inside the executor — matchessend.tsprecedent, picks up the configured cluster, and works under vitest (which presets these env vars).{ name, description, inputSchema, handler }. Sipher's convention isAnthropicTool { name, description, input_schema }paired with a separateexecuteXxx(params)function (persend.ts,deposit.ts, etc.). All new tools follow the established shape.src/tools/<name>.test.ts(co-located). Sipher's convention istests/<kebab-name>.test.ts(per all existing tool tests). Moved accordingly.bs58.encode(meta.spending)for the sip-URI build, but sipher'ssend.ts:166-167rejects non-0x-prefixed keys:parts[2].startsWith('0x'). The composite buildssip:solana:0x${hex}:0x${hex}to satisfy the existing contract.handleHeraldDM, expectingtoolsCalledto includesendPrivateToSNS) targeted a non-existent entry point and would have required addingsendPrivateToSNStoHERALD_TOOLS, expanding HERALD's X-only surface into fund-moving territory. Replaced with the composite integration test built intosend-private-to-sns.test.ts— exercisesresolveSNS+ URI build + delegate-to-sendend-to-end via mocks, without coupling to LLM intent classification.Test Plan
cd packages/agent && pnpm test -- --run— 1495 / 1495 passingpnpm test -- --run(root REST suite) — 555 / 555 passingcd packages/agent && npx tsc --noEmit— cleanpnpm typecheck(root) — clean.soldomain is registered with SIP-STEALTH record:/v1/healthto confirm process boots with the new tools registeredresolveSNSNotes
@sip-protocol/sns-stealth@^0.1.0was published to npm in Phase A (PR sip-protocol#10825a85d11). pnpm-lock now references that version.src/lib/sns-stealth-*.tswrapper because their UI consumers imported it from multiple call sites. Sipher has only the two tools as callers, so the wrapper is inlined intoresolve-sns.ts—executeResolveSNSis the wrapper boundary.bytesToHexis inlined as a small helper (matchingsend.ts's inlinehexToBytes) rather than pulling in@noble/hashes/utilsas a direct dep — it's not inpackages/agent/package.jsonexplicitly.sendPrivateToSNStoHERALD_TOOLS(would need DM-triggered fund-movement trust review).Phase D acceptance
resolveSNStool + 23 tests, registered in agent loopsendPrivateToSNScomposite tool + 22 tests, SENTINEL preflight wired