Skip to content

chore: remove deprecated Solana/wallet-based provider payouts#155

Open
hankbobtheresearchoor wants to merge 17 commits into
Layr-Labs:swift-providerfrom
hankbobtheresearchoor:swift-llm
Open

chore: remove deprecated Solana/wallet-based provider payouts#155
hankbobtheresearchoor wants to merge 17 commits into
Layr-Labs:swift-providerfrom
hankbobtheresearchoor:swift-llm

Conversation

@hankbobtheresearchoor
Copy link
Copy Markdown
Contributor

Removes all deprecated Solana/wallet-based provider payout functionality, which has been superseded by Stripe Connect Express. The BIP39 mnemonic is retained for coordinator X25519 encryption key derivation — only the payment/deposit uses of Solana have been removed.

Changes

Coordinator (Go)

  • coordinator/api/billing_integration_test.go: Remove SolanaWalletAddress/SolanaWalletID from User struct; clean up BillingSession comments (stripe-only)
  • coordinator/billing/billing.go: Remove solana_wallet_address/solana_wallet_id from schema; add migration to rename→drop legacy columns
  • coordinator/auth/privy.go: Remove Solana wallet extraction from Privy linked accounts
  • coordinator/cmd/coordinator/main.go: Rename SolanaMnemonicEncryptionMnemonic
  • coordinator/payments/payments.go: Remove CreditProvider convenience method (wallet-based wrapper)
  • coordinator/protocol/messages.go: Remove WalletAddress from RegisterMessage
  • coordinator/registry/registry.go: Remove WalletAddress from Provider struct
  • coordinator/api/consumer.go: Remove wallet-based payout fallback (CreditProvider via Ledger); pricing now uses AccountID instead of WalletAddress
  • coordinator/api/me_handlers.go: Remove WalletAddress from responses; clean up comments

Web UI

  • web/src/app/(authenticated)/wallet/page.tsx: Remove Solana wallet card & related sections (replaced by Stripe Connect status)
  • web/src/hooks/useWalletAddress.tsx: Delete hook
  • web/src/components/solana-provider.tsx: Delete component
  • web/src/app/layout.tsx: Remove SolanaProvider wrapper
  • web/src/app/api/wallet/route.ts: Remove wallet endpoint
  • web/src/hooks/useLinkWalletMutation.ts: Delete hook
  • web/src/app/api/wallet/link/route.ts: Remove link-wallet endpoint
  • web/src/app/(authenticated)/settings/page.tsx: Remove SolanaWallet section
  • web/src/app/api/wallet/route.ts: Remove wallet verification endpoint

Other

  • package.json: Remove bs58 dependency
  • scripts/profile.sh: Remove Solana references from profile script

Removes all deprecated Solana/wallet-based provider payout functionality,
superseded by Stripe Connect Express. BIP39 mnemonic is retained for
coordinator X25519 encryption key derivation.

- Simplified migration: drop solana columns directly without rename step
- Drop Chain field from BillingSession (always empty since EVM/Solana removal)
@vercel
Copy link
Copy Markdown

vercel Bot commented May 12, 2026

@hankbobtheresearchoor is attempting to deploy a commit to the EigenLabs Team on Vercel.

A member of the Team first needs to authorize it.

@ethenotethan ethenotethan requested a review from Gajesh2007 May 12, 2026 16:55
ethenotethan and others added 13 commits May 13, 2026 13:54
…e isolation

- Move R2_BUCKET from vars to secrets so it participates in GitHub
  environment scoping (dev vs prod get different buckets/credentials)
- Add documentation header listing all environment-scoped secrets
  required per environment
- Soft-fail Swift unit tests on dev releases (live MLX model cache
  may be incomplete on CI)
- Download full model (remove --include filter) for deterministic
  CI cache seeding
…tion

Both release workflows now resolve DEV_ or PROD_ prefixed repo secrets
in a resolve-env step using bash indirection — no GitHub environments
needed. The environment: gate is removed since secrets live at repo
level with prefixes.

Required repo secrets:
  DEV_R2_ACCESS_KEY_ID, PROD_R2_ACCESS_KEY_ID
  DEV_R2_SECRET_ACCESS_KEY, PROD_R2_SECRET_ACCESS_KEY
  DEV_R2_ENDPOINT, PROD_R2_ENDPOINT
  DEV_R2_BUCKET, PROD_R2_BUCKET
  DEV_R2_PUBLIC_URL, PROD_R2_PUBLIC_URL
  DEV_COORDINATOR_URL, PROD_COORDINATOR_URL
  DEV_RELEASE_KEY, PROD_RELEASE_KEY
40 threats across 9 trust boundaries (coordinator/provider WebSocket,
provider operator vs process, browser/UI, Apple MDM/MDA, admin API,
inference engine, payments, Apple attestation chain). Adversaries:
malicious provider, malicious consumer, external attacker. Each threat
includes affected_files globs, mitigations with status, open_findings
links to the existing security audit, and a detection_hint for
automated PR review.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Each of the 9 trust boundaries now documents how_it_works (exact code
paths, line numbers, auth mechanisms, data flows) and current_limitations
(specific open gaps with SEC-* references). Sources: coordinator/internal/
api/{server,provider,release_handlers,device_auth,billing_handlers}.go,
registry/registry.go, attestation/, mdm/, provider-swift/Sources/
ProviderCore/Security/{AntiDebug,BinaryHasher,SecureEnclaveIdentity,
SecurityHardening}.swift, Crypto/NodeKeyPair.swift, Inference/
{BatchScheduler,IdleTimeoutPolicy,InferenceCancellation}.swift,
ProviderLoop.swift, console-ui/src/{hooks/useAuth,lib/{api,store,
encryption}}.ts, next.config.ts.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
On every PR against master/main, the workflow:
1. Gets the PR diff via gh pr diff
2. Matches changed files against affected_files globs in docs/threat-model.yaml
3. Calls Claude API (claude-sonnet-4-6) with the focused diff + full threat model
4. Posts (or updates) a single PR comment with STRIDE-based security analysis

Uses prompt caching on the static threat model block to minimise API cost
on repeated pushes. The comment marker <!-- threat-model-review --> lets
the workflow update rather than append on each push.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…ayr-Labs#146)

* Add persistent Secure Enclave attestation key with keychain access group enforcement

Replace ephemeral CryptoKit SE keys with persistent Security framework keys stored
in the macOS data protection keychain. The key is bound to the signing team's
keychain access group (SLDQ2GJ6TL.io.darkbloom.provider), enforced by securityd
at the kernel level. A patched binary re-signed with codesign -s - gets
errSecMissingEntitlement and cannot access the key.

- PersistentEnclaveKey: Security framework SE key with SecKeyCreateRandomKey,
  kSecAttrIsPermanent, and team-scoped access group
- AttestationSigner protocol: abstracts over both ephemeral and persistent keys
- ProviderLoop: tries persistent key first, falls back to ephemeral with warning
- Entitlements plist with keychain-access-groups for production signing
- 8 tests covering creation, persistence, signing, deletion, protocol conformance

* Embed provisioning profile in .app bundle for persistent SE key

The data protection keychain requires a provisioning profile to authorize
the keychain-access-groups entitlement. Wrap the CLI binaries in a minimal
Darkbloom.app bundle with embedded.provisionprofile so the persistent SE
attestation key works on provider machines.

- release-swift.yml: new step decodes PROVISIONING_PROFILE_BASE64 secret,
  builds Darkbloom.app/Contents/ structure, signs bundle + individual binaries
- install.sh: detects .app bundle layout, symlinks bin/ into the app bundle
- Backward-compatible: falls back gracefully if secret is not set or if
  provider receives a flat (pre-.app) bundle

* Add com.apple.application-identifier to provider entitlements

Required for data protection keychain access. Must match the bundle ID
in the provisioning profile (SLDQ2GJ6TL.io.darkbloom.provider).

* Address review: data protection keychain flag, tighter error handling, real SE probe

Codex P1 / hank P1:
- coordinator/api/install.sh: restore __DARKBLOOM_COORD_URL__ placeholder
  (the coordinator templates this at serve time via server.go;
  hardcoding the URL broke dev/self-hosted coordinators)
- PersistentEnclaveKey: add kSecUseDataProtectionKeychain: true to all
  Security framework calls. Without it, queries may hit the legacy
  file-based keychain where access group enforcement is silently ignored.

hank P2:
- loadOrCreate: catch only errSecItemNotFound before falling through to
  createNew. Auth failures, locked keychain, and missing entitlement
  now propagate to the caller instead of racing with key creation.
- isAvailable: probe real SE capability via CryptoKit's
  SecureEnclave.isAvailable instead of just checking macOS version.
  Now returns false on Intel Macs without T2 and macOS VMs without
  virtualized SE. Added doc comment noting the entitlement dependency.
…abs#144)

The errorResponse function only populated type and message, missing
code and param required by the OpenAI API spec. Without code, SDKs
cannot programmatically distinguish error types (e.g. Python SDK
e.code returns None, retry logic breaks, Sentry groups all errors
as one).

Changes:
- errorResponse now accepts optional errorDetailOpt variadic args
- code defaults to errType for backward compatibility
- withParam() and withCode() helpers for call-site overrides
- model-not-found errors include param="model"
- model-is-required errors include param="model"
- insufficient_funds uses OpenAI-canonical code "insufficient_quota"
- rate_limit_exceeded gets explicit withCode for clarity

All 202 existing call sites are backward-compatible: the variadic
signature means they compile unchanged, and the default code=errType
matches the implicit behavior SDKs already assumed.

Closes Layr-Labs#142
)

* Fix Darkbloom analytics tracking

* Harden release workflow protections (Layr-Labs#103)

* Harden release registration and binary hash policy (Layr-Labs#99)

* Harden release registration and binary hash policy

* derive release download URL from allowlist

* Stabilize provider coordinator test

---------

Co-authored-by: Gajesh Naik <26431906+Gajesh2007@users.noreply.github.com>

* Remove stale Python integration test (Layr-Labs#109)

* e2e: add local simulation environment skeleton

Introduces scripts/e2e-runner.py, a Python orchestrator that spins up the
real coordinator binary with test-friendly configuration (in-memory store,
mock billing, no trust requirements) alongside a simulated or real
provider, and runs HTTP/WebSocket-level assertions against the live stack.

Key components:
- Coordinator class: builds and spawns coordinator with EIGENINFERENCE_MIN_TRUST=none,
  EIGENINFERENCE_BILLING_MOCK=true, and in-memory store
- SimulatedProvider: pure-Python WebSocket client speaking the full provider protocol
  (register, attestation challenge/response, heartbeat, inference request/response)
- Test framework: decorator-based test registration, pass/fail summary, signal-safe
  cleanup via atexit + signal handlers
- Test stubs: test_basic (registration + discovery), test_inference (consumer
  request routing), test_multi_provider (two providers, same model)

TODO:
- RealProvider wrapper around darkbloom serve --coordinator
- Coordination between provider challenge cycle and consumer request timing
- API key handling for consumer vs admin routes
- Python dependency management (websockets, cryptography)

* Revert "e2e: add local simulation environment skeleton"

This reverts commit d02074e. The Python E2E runner adds noise on top of
the existing Go integration tests (internal/api/integration_test.go +
fullstack_integration_test.go) which already cover the full coordinator
protocol surface. The cross-language orchestration doesn't buy anything
over what httptest.Server + simulated providers already provide.

* Remove stale Python integration test

@ethenotethan

tests/integration_test.py is superseded by the Go-based coordinator
integration tests at coordinator/internal/api/:

- Test coverage for coordinator protocol (register, challenge, heartbeat,
  inference) is covered by integration_test.go using httptest.Server +
  Go simulated providers — same coverage, no binary build needed
- Full-stack GPU inference is covered by fullstack_integration_test.go
  with real vllm-mlx backends (gated behind LIVE_FULLSTACK_TEST=1)
- The Python test uses stale binary names ('eigeninference-provider'),
  old flags ('--backend mlx-lm'), and predates attestation challenges,
  E2E encryption, and the vllm-mlx backend migration
- No external dependency coverage (Postgres, Stripe, etc.) is lost — the
  coordinator main.go wiring for those is trivially tested elsewhere
- The Python SDK tests (4.5.x) belong in the SDK repo, not the infra repo

---------

Co-authored-by: Hank Bob <hankbob@researchoors.com>

* chore: remove unused dependencies (Layr-Labs#112)

* chore: remove unused dependencies

* test: fix console ui test isolation

* chore: prune repo-wide dead code findings

* ci: run CI on any PR, not just master/main (Layr-Labs#119)

* ci: remove racing deploy-dev-coordinator workflow (Layr-Labs#137)

Cloud Build (deploy/gcp/cloudbuild.yaml) already deploys the coordinator
on the same trigger (push to master touching coordinator/** or deploy/gcp/**).
Having both paths active creates a race condition where two CI systems
simultaneously deploy to the same dev VM — see Layr-Labs#115.

* feat: add Datadog observability stack for dev coordinator

Install Datadog Agent on the dev GCE VM (DogStatsD, APM, journald logs)
and wire the coordinator to emit structured metrics, split attestation
counters, model_type tags, reactive provider-count gauges, and a
completion-tokens counter. Rebuild the dev dashboard with 7 sections
covering metrics, logs, traces, and system health.

* fix: prevent double-decrement when untrusted provider disconnects

Disconnect now checks StatusUntrusted before decrementing the online
counter and model-provider gauges, since MarkUntrusted already
decremented them.

* feat: add fleet version and binary hash observability

New metrics:
- providers.per_version gauge (per provider binary version)
- providers.per_binary_hash gauge (per attested binary hash)
- coordinator.min_provider_version_set gauge (1 when configured)
- provider_version_below_minimum counter (tagged by gate and version)

Gates instrumented:
- registration (provider.go)
- challenge revalidation (provider.go)
- manifest sync (server.go)

Registry additions:
- ProviderCountByVersion()
- ProviderCountByBinaryHash()

Dashboard: Fleet Version & Binary Hash group with providers by version,
providers by binary hash, min provider version, below-minimum events,
and top binary hashes toplist.

* fix: update Dockerfile + cloudbuild for go.mod at repo root

go.mod moved from coordinator/ to repo root during the swift-provider
merge. Build context is now repo root, Dockerfile copies coordinator/
subdir explicitly.

* fix: chmod +x coordinator binary in Dockerfile

* fix: ensure coordinator binary is executable in builder stage

* fix: rename coordinator source dir in builder to avoid colliding with binary path

* fix: copy full repo in Dockerfile builder so go.mod resolves all packages

* fix: remove unused modelTypeTag and format Go files for CI

* fix: skip python/dangerous-modules check for swift runtime in private text gate

* billing telemetry + MarkUntrusted race fix + Swift routing tests

- Add Datadog histogram metrics for reservation amounts, settlement
  refunds, provider credits, and platform fees
- Add store.debit/credit.latency_ms histograms for DB operation timing
- Add billing.cost_clamped and billing.reservation_refunds counters
- Fix race in MarkUntrusted: hold r.mu write lock through counter
  decrement to prevent double-decrement with Disconnect
- Add unit tests for Swift provider privacy caps (with/without Python)
- Add E2E test for Swift provider routing via challenge-verified path
- Update dev-network-dashboard.json with Billing & Store group

* fix Heartbeat reviving untrusted providers causing onlineCount double-decrement

* revert orthogonal landing/console-ui/provider changes

* remove unbounded binary_hash cardinality, add input token metrics + store latency, fix dashboard group-by

* fix review feedback: ModelType() untrusted filter, routing.cost_ms by provider, billing in cents, dead comment

---------

Co-authored-by: Gajesh Naik <26431906+Gajesh2007@users.noreply.github.com>
Co-authored-by: anupsv <6407789+anupsv@users.noreply.github.com>
Co-authored-by: hankbob <hankbobtheresearchoor@gmail.com>
Co-authored-by: Hank Bob <hankbob@researchoors.com>
@Gajesh2007
Copy link
Copy Markdown
Member

@codex review this

Copy link
Copy Markdown
Member

@Gajesh2007 Gajesh2007 left a comment

Choose a reason for hiding this comment

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

Reviewed against base swift-provider in a fresh clone. Builds, runs the test suites, and traces remaining wallet references end-to-end.

Blocking — CI will fail today

  1. cargo test fails to compile. provider/src/coordinator.rs:991 still calls build_register_message(&hw, &models, "vllm_mlx", None) (4 args), but the PR merged the old build_register_message_with_wallet into build_register_message and the surviving signature now takes 5 args (added attestation: Option<Box<RawValue>>). Real compile error:

    error[E0061]: this function takes 5 arguments but 4 arguments were supplied
      --> src/coordinator.rs:991:19
    

    Fix: either pass None for the new 5th arg, or restore a 4-arg wrapper.

  2. cargo fmt --check fails. provider/src/coordinator.rs:1452 has a trailing blank line where the deleted test_build_register_message_with_wallet used to sit.

  3. gofmt -l . fails on two files (ci.yml aborts the build on any unformatted file):

    • coordinator/cmd/coordinator/main.go:316 — the // Mnemonic — … comment inside billingCfg := billing.Config{ is indented with 1 tab instead of 2.
    • coordinator/api/billing_integration_test.go:14 — trailing whitespace on "io" (introduced by the GitHub-web-UI commit "Update billing_integration_test.go").

go build ./... and the full Go test suite pass. The Rust test failure and both formatters block CI.

Semantic concerns worth flagging before merge

  1. Unlinked providers no longer earn anything. The wallet-address payout fallback in handleComplete (coordinator/api/provider.go) is gone — only p.AccountID != "" providers get credited. The integration test TestIntegration_AccountLinkedEarnings was updated to drop the wallet-balance assertion, but the comment in TestIntegration_ReferralRewardDistribution calls it out plainly: "connectProvider doesn't set either, so no provider credit occurs." If any live provider is connected without account linkage, it will silently stop accruing — worth checking the registry before shipping.

  2. The PR description is misleading — the frontend is not actually de-Solanaized. The body lists 9 files under web/src/... (delete useWalletAddress, solana-provider.tsx, etc.). There is no web/ directory in this repo, and the actual diff touches zero frontend files. The real frontend (console-ui/) still has live wallet_address references:

    • console-ui/src/app/providers/types.ts:113,139 — typed fields
    • console-ui/src/app/providers/ProviderDashboardContent.tsx:253if (summary.payout_ready || summary.wallet_address) return null;
    • console-ui/src/app/providers/warnings.ts:261 — "No payout method configured" warning gated by !p.account_id && !p.wallet_address
    • console-ui/__tests__/provider-dashboard-warnings.test.ts:280

    These won't crash (TS field is optional, will always be undefined), but the "no payout" warning logic and the PayoutBanner now degrade to "driven solely by payout_ready / account_id". Should be cleaned up to match the PR's stated intent.

  3. Pricing key change is a behavior shift (probably a latent fix). coordinator/api/provider.go:1010 now does GetModelPrice(p.AccountID, ...) where it previously used p.WalletAddress. Admin endpoints (billing_handlers.go:403/450) already set model_prices keyed by account_id and "platform", so the previous lookup-by-wallet was likely dead code that always missed. Worth confirming no rows in prod model_prices are keyed by hex wallet addresses.

  4. Logout message lies. provider/src/main.rs:6963 cmd_logout still prints "Provider earnings will use the local wallet until you log in again." The local wallet module is deleted; there is no fallback.

  5. Paper changes are unrelated scope. papers/dginf-private-inference.tex rewrites the RDMA/hypervisor trust policy (from "RDMA without hypervisor → immediate untrust" to "informational"). Nothing about Solana, and it contradicts current attestation code unless that policy is also changing elsewhere. Either unrelated drift, or the corresponding policy change is missing from this diff.

Non-issues (safe)

  • Postgres migration uses DROP COLUMN IF EXISTS inside DO $$ … EXCEPTION WHEN others, idempotent — but forward-only and destructive (any data in users.solana_wallet_* and billing_sessions.chain is permanently lost on first boot of the new binary).
  • EncryptionMnemonic reads legacy EIGENINFERENCE_SOLANA_MNEMONIC via firstNonEmpty(...), so existing env vars work. Deploy env files (deploy/environments/{prod,dev}.env) still set SOLANA_NETWORK/SOLANA_RPC_URL/SOLANA_USDC_MINT — unused now but cosmetic.
  • WebSocket protocol drop of wallet_address is backward-compatible: Go's json.Unmarshal ignores unknown fields, so old providers sending it won't break against the new coordinator.
  • provider_payouts table and CreditProviderWallet store method are retained (the Ledger.CreditProvider wrapper above them is what got removed) — historical payout rows remain readable.
  • Orphaned ~/.darkbloom/wallet_key on existing provider installs is harmless.

Verdict

Not safe to merge as-is — at minimum, fix the 4 CI failures (1 Rust test, 1 cargo fmt, 2 gofmt). Beyond that, decide whether the missing console-ui/ cleanup, the misleading logout message, and the unrelated paper changes belong in this PR or a follow-up.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

- Fix build_register_message test call: pass 5th arg (attestation)
- Fix gofmt: comment indent in main.go, trailing space in billing test
- Fix stale handleComplete comment (no wallet fallback exists)
- Fix stale billing integration test comment
- Fix logout message claiming local wallet fallback
- cargo fmt
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.

4 participants