Skip to content

Add YieldSignal plugin: six x402-paid yield and risk tools - #596

Open
Stakemate369 wants to merge 11 commits into
goat-sdk:mainfrom
Stakemate369:add-yieldsignal-plugin
Open

Stakemate369 wants to merge 11 commits into
goat-sdk:mainfrom
Stakemate369:add-yieldsignal-plugin

Conversation

@Stakemate369

@Stakemate369 Stakemate369 commented Jul 20, 2026 •

Copy link
Copy Markdown

Summary

Adds @goat-sdk/plugin-yieldsignal, a GOAT plugin for YieldSignal — yield and risk data for lending on Base and ETH liquid staking on Ethereum, paid per call over the x402 protocol.

I couldn't find existing x402 support in the GOAT plugin catalog, so this also happens to be a first example of an x402-paid data plugin here, in case that pattern is useful for other paid-API integrations later.

Six tools

Tool Question it answers
yieldsignal_get_yield_signal What pays best right now, risk-weighted
yieldsignal_get_yield_decision Given where my capital already sits, is moving it worth the cost?
yieldsignal_get_yield_durability Is this yield real, or a reward campaign about to end?
yieldsignal_get_exit_capacity Can I actually withdraw my size from that market?
yieldsignal_get_rate_sensitivity How close is this market to the kink where borrow rates jump?
yieldsignal_get_shared_exposure I'm in N venues — but behind how many distinct risks?

A raw "who pays most" reading is available free elsewhere; the other five are the reason the API exists.

Design notes

The x402 client is injected, not provisioned. An earlier revision of this branch built its own CDP wallet from env vars, which forced @coinbase/cdp-sdk onto every consumer. The plugin now takes an x402Client — anything @x402/fetch accepts — so its dependencies are just @goat-sdk/core, zod and the published yieldsignal-client.

Prices are not restated in the docs. They come from the 402 challenge, so the README can't drift out of date when they change.

The four risk reports cover lending only (USDC, WETH). Liquid staking has no utilization curve, no borrow side and no itemized incentive component, so those reports would have nothing to compute against. The parameter schemas enforce this, and there are unit tests over exactly that boundary.

The service class is not unit-tested on purpose. @Tool resolves its schema through design:paramtypes reflection metadata, which esbuild-based runners (vitest included) do not emit — importing the service under vitest throws regardless of correctness. The parameter schemas, which are what the model actually sees, are covered.

Verification

  • biome check --diagnostic-level=error — clean, using this repo's config
  • Typechecks against @goat-sdk/core source and the published yieldsignal-client types
  • Parameter schema tests pass against the real @goat-sdk/core
  • The endpoint is live on Base mainnet with settled payments; per-asset accuracy computed from public on-chain EAS attestations is free at /accuracy.json

The changeset lives in typescript/.changeset/ next to this repo's config.json. The changeset bot reports "No Changeset found" because it looks at the repository root, where this monorepo has no .changeset directory — that warning appears on every PR here.

pnpm-lock.yaml is intentionally untouched: my local Node version is outside this repo's engines range, so a lockfile generated here would prune unrelated entries. It needs a regular pnpm install on a supported Node to pick up the new package.

@changeset-bot

changeset-bot Bot commented Jul 20, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 72b5949

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@Stakemate369

Copy link
Copy Markdown
Author

Friendly follow-up on this one 🙏 The plugin is tested against the real @goat-sdk/core SDK (not a reference stub) and the endpoint it wraps is live on Base mainnet with settled payments. Happy to rebase or address any feedback whenever a maintainer has a moment to take a look — thanks!

The plugin only offered USDC/WETH lending and built the URL by transforming
the asset name (`${asset.toLowerCase()}-base-yield`). That shortcut cannot
reach ETH liquid staking - it is neither on Base nor lending - and the same
shortcut shipped in a sibling plugin where it silently requested a 404 path.
Replaced with an explicit path map, which is also the only place a new asset
has to be registered.

ETH_STAKING is now selectable and is the asset with the strongest verified
record of the three. The tool description states the comparison basis (base
interest plus incentives) and points at the free accuracy endpoint, so the
model can tell a full reading from a partial one.
@Stakemate369

Copy link
Copy Markdown
Author

Pushed a substantive update rather than a ping — the branch had a real gap.

ETH liquid staking was unreachable. The client derived the URL from the asset name (${asset.toLowerCase()}-base-yield), which works for USDC/WETH and cannot express ETH liquid staking (neither on Base, nor lending). The exact same shortcut shipped in a sibling plugin and quietly requested a 404 path for that asset. Replaced with an explicit path map, so ETH_STAKING is now selectable — and it is the asset with the strongest verified record of the three (median 13h as the leader, against 1h for USDC lending, measured from the public on-chain attestations).

The tool description now states the comparison basis. Upstream, every protocol is compared on base interest plus incentives, and the response lists any protocol it could not read (omittedProtocols/coverage) — that case is live right now, with the Euler USDC pool on Base reading mute. A model choosing where to allocate should be able to tell a full reading from a partial one.

Verified: unpaid 402/308/signature checks against production, plus the equivalent change in the service's own reference integration, which is covered by verify-integrations against a real tsc build. I have not run the GOAT monorepo build locally (the install is heavy on this machine) — CI on this PR is the check for that, and I'll fix whatever it flags.

Free, unpaid endpoint to check the service against: https://yieldsignal.vercel.app/accuracy.json

🤖 Generated with Claude Code

Three things the earlier revision of this branch got wrong.

The plugin shipped ONE tool while the service sells six. The five it hid are
the ones that aren't a commodity: a MOVE/HOLD decision that accounts for the
cost of moving, incentive durability (how much of an APY survives if rewards
stop), exit capacity (whether a given size can actually be withdrawn),
borrow-rate sensitivity (distance to the kink, read from the protocol's own
curve) and shared exposure (how much capital sits behind the same collateral
or oracle across venues). A raw "who pays most" reading is available free
elsewhere; those five are not.

It forced @coinbase/cdp-sdk on every consumer by provisioning its own wallet
from CDP env vars. The x402 client is now injected, so the package depends
only on @goat-sdk/core, zod and the published yieldsignal-client, and anyone
with an @x402/fetch-compatible signer can use it.

The README hardcoded "$0.01 USDC per call", which is no longer the price.
Prices now come from the 402 challenge and are not restated in docs that
can drift.

Also adds the changeset this branch was missing, and unit tests over the
parameter schemas. The service itself isn't unit-tested on purpose: @tool
resolves its schema through design:paramtypes reflection metadata, which
esbuild-based runners (vitest included) do not emit, so importing it under
vitest would throw regardless of correctness.
@Stakemate369 Stakemate369 changed the title Add YieldSignal plugin (x402-paid Base lending APY signal) Add YieldSignal plugin: six x402-paid yield and risk tools Aug 10, 2026

This branch has not been deployed

No deployments
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