Skip to content

Strategy Marketplace / Opt-In Copy-Trading #285

Description

@robertocarlous

Problem Statement

Every user's agent strategy today is private and independent — there's no way for a new or uncertain user to benefit from another user's proven configuration, and no reason for a successful user to stick around and engage beyond their own portfolio. A marketplace where users opt in to publish an anonymized track record, and others can follow that strategy's configuration (never its funds), turns the product into something with network effects instead of a single-player tool.

Current State

Strategies are configuration objects implementing RebalanceStrategy (src/agent/strategies.ts), selected per-user via src/agent/router.ts. Performance data already exists in AgentLog and YieldSnapshot, and issue #225 is separately adding richer live-portfolio analytics (Sharpe ratio, drawdown) — this feature should consume whatever ranking metric #225 lands, rather than inventing a third definition of risk-adjusted return.

Proposed Solution

Data Model

model PublishedStrategy {
  id              String   @id @default(uuid())
  userId          String
  label           String
  strategyConfig  Json     // serialized RebalanceStrategy config (type + params, no PII)
  isPublished     Boolean  @default(false)
  publishedAt     DateTime?
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt
  user            User             @relation(fields: [userId], references: [id], onDelete: Cascade)
  followers       StrategyFollow[]
  @@index([isPublished])
}
model StrategyFollow {
  id                  String   @id @default(uuid())
  followerUserId      String
  publishedStrategyId String
  followedAt          DateTime @default(now())
  unfollowedAt         DateTime?
  follower            User              @relation(fields: [followerUserId], references: [id], onDelete: Cascade)
  publishedStrategy   PublishedStrategy @relation(fields: [publishedStrategyId], references: [id], onDelete: Cascade)
  @@unique([followerUserId, publishedStrategyId])
}

API Surface

  • POST /api/agent/strategies/publish — publish/update the caller's own strategy snapshot (requireAuth, no :userId param needed since it always acts on the caller).
  • POST /api/agent/strategies/unpublish — stop showing it on the marketplace (existing followers keep their current applied config until they explicitly unfollow — see Edge Cases).
  • GET /api/agent/strategies/marketplace?sortBy=apy|sharpe&window=30d|90d|1y — public leaderboard, paginated, no PII (requireAuth still recommended even for a "public" leaderboard, consistent with the rest of the API's auth posture, but no ownership check needed since it's not user-scoped).
  • POST /api/agent/strategies/:id/follow / POST /api/agent/strategies/:id/unfollowrequireAuth.

Integration Points

  • Following a strategy means the follower's router.ts selection picks up the published strategyConfig on its next scheduled run — it does not move funds, create a shared wallet, or grant the publisher any access to the follower's CustodialWallet/Position. This boundary must be enforced structurally, not just documented: the follow relationship should have no code path that touches another user's wallet or Stellar keys.
  • Anonymization: PublishedStrategy.label and any displayed performance stats must be derived only from the publishing user's own AgentLog/YieldSnapshot aggregates, never raw balances — build the leaderboard query to select only the aggregate fields it needs, not a broad include that could leak more than intended.
  • When a publisher updates their strategy config materially, dispatch a webhook/WhatsApp notification to current followers via the existing dispatchWebhookEvent/src/whatsapp/formatters.ts paths (new event, e.g. strategy.updated) — a follower's risk exposure should never change silently underneath them.

Edge Cases & Failure Modes

  • Publisher unpublishes or deletes their account while others still follow it — existing followers keep their last-applied config (a snapshot at follow time, or at last update) rather than having their agent loop break; they should be notified that the source strategy is no longer being updated.
  • A user tries to follow their own published strategy — either a no-op or explicitly disallowed; decide and enforce one, don't leave it undefined.
  • Leaderboard gaming: a strategy with very little history (e.g. one day of data) posting a misleadingly high short-window APY — require a minimum track-record length before a strategy is eligible for the leaderboard.

Security & Privacy Considerations

  • This is the first feature exposing one user's data (even anonymized) to others — the anonymization boundary is the core security property and needs its own explicit test coverage (a test asserting the marketplace endpoint's response shape contains no userId, wallet address, or absolute balance fields).
  • Consent must be explicit and revocable — unpublish must be immediate and should stop the strategy appearing in new queries right away, even if existing followers retain their last snapshot.

Out of Scope

  • Any transfer of funds, shared custody, or fee-sharing between publisher and follower — configuration-following only.
  • Comments/social features beyond the leaderboard itself.

Suggested Implementation Plan

  1. PublishedStrategy/StrategyFollow models, publish/unpublish flow with anonymization enforced at the query layer.
  2. Follow/unfollow endpoints; wire router.ts to apply a followed config.
  3. Leaderboard endpoint with a minimum-track-record eligibility rule.
  4. Change-notification webhook/WhatsApp event for followers.

Acceptance Criteria

  • Publish/unpublish flow with explicit opt-in; unpublishing immediately removes the strategy from marketplace queries
  • Follow/unfollow endpoints; a follower's agent loop applies the config on its next scheduled run
  • Leaderboard sorted by a documented risk-adjusted metric, paginated, with a minimum track-record eligibility threshold
  • Test asserting the marketplace/leaderboard response contains no PII, wallet addresses, or raw balances
  • Notification sent to followers when a followed strategy's config changes materially
  • Tests confirming a follow relationship never grants access to another user's CustodialWallet or triggers any Stellar operation on their behalf
  • docs/openapi.yaml updated

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions