Add Balancer plugin for Base MCP#74
Conversation
✅ Heimdall Review Status
|
stephancill
left a comment
There was a problem hiding this comment.
Thanks for the submission. The frontmatter and structure are spec-conformant and the v3 swap path builds and submits correctly. There is a blocking correctness issue in the build script:
Required
- Revert the
SKILL.mdplugins-table row. Plugins shouldn't add themselves to the registry — maintainers will register them when the program is ready. Limit the PR toplugins/balancer.md. build-swap.mjsomitssender/recipienton the basis that "v3 makes msg.sender the sender/recipient." That is v3-only. The SOR routes through both v2 and v3 depending on liquidity, and v2-routed pairs causebuildCallto throw:Input Validation: Swap input missing parameter sender/recipient for Balancer v2. A significant share of common Base pairs currently route v2 (e.g. WETH->cbETH, USDC->DAI, WETH->BAL), so the headline example fails intermittently. Passsender/recipient(the wallet fromget_wallets) whenever any path hasprotocolVersion: 2.- v2 settles through the V2 Vault, so the Permit2 onchain-allowance batch in
## Submissionis v3-specific. Document the version-dependent submission (v2 uses Vault approval, not Permit2).
89f614e to
59be9eb
Compare
|
Thank you for your submission @tiago-hansen ! This would limit the calldata generation to CLI only where the agent has access to generating nodejs code, right? In which case, can you please update the fontmatter? |
59be9eb to
7a5f73e
Compare
New cli-only plugin (skills/base-mcp/plugins/balancer.md): read pools and SOR quotes from the Balancer API via curl, encode swap/liquidity calldata with @balancer/sdk in a shell (version-aware for Balancer v2/v3 routing), and submit via send_calls. Requires a shell; unsupported on chat-only surfaces. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
7a5f73e to
4e66834
Compare
build-swap.mjs now encodes the version-correct approval(s) alongside the action
call and emits a ready-to-submit { chain, calls } payload, deriving every
approval target from the same call.to the SDK returns. This removes the one
spot where an agent could hand-pair v3 Permit2 approvals with a v2 Vault target
— a mismatch that passes per-call encoding (each approval is individually
valid) and only reverts at the action call, typically as an uninformative
"unable to estimate gas".
Also document that sorGetSwapPaths can return a null priceImpact carrying a
"still valid and can be executed" note for some valid multi-hop routes
(USDC->WETH does this today). Treat that as unknown — not a hard error and not
a high-impact warning; fall back to returnAmount and TVL.
Verified live on Base: v2 (USDC->WETH) emits approve(Vault) + Vault call; v3
(boosted pool) emits approve(Permit2) + Permit2.approve(Router) + Router call.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks again for putting this together, @tiago-hansen. One operational note: this PR includes one or more commits that GitHub marks as unverified. We require verified commits for external plugin submissions so we can rely on GitHub signature and provenance checks before merging code into base/skills. Could you please open a new PR with verified commits? I cannot merge this PR as-is. Thank you. |
|
Thanks for the review and the clear guidance, @youssefea! 🙏 I've opened #104 to replace this PR with verified, SSH-signed commits, so it satisfies the verified-signatures branch requirement. It's the same Balancer plugin, with a few small robustness improvements folded in:
Closing this in favor of #104. |
Summary
Adds a native Base MCP plugin for Balancer, authored against
skills/base-mcp/references/plugin-spec.md.skills/base-mcp/plugins/balancer.md.Integration:
cli-onlyBalancer's API returns swap paths and pool data, not calldata; calldata is encoded by
@balancer/sdkrunning in Node, and itsquery()simulation needs a Base RPC. Balancer ships no hosted calldata endpoint, so every step requires a shell — reads/quotes viacurl, calldata via a short Node SDK script — then submit viasend_calls. On chat-only surfaces the plugin is unsupported (noweb_request/paste fallback): tell the user it needs a terminal and stop. Same pattern as Aerodrome.v2 / v3 routing (verified live)
The SOR routes each pair through Balancer v2 or v3 by liquidity, and the two settle differently. Tested against the live API + a Base RPC — USDC→WETH currently routes v2, so this is the common path, not an edge case:
msg.senderis sender/recipient.0xBA1222…BF2C8); plain ERC20 approval to the Vault;buildCallrequiressender/recipient(else it throws).The build script detects v2 from the SOR paths and emits
protocolVersionso the agent assembles the correctsend_callsbatch.Frontmatter
integrationcli-onlyrequires.shellrequiredrequires.allowlist[](API reached from the shell viacurl, notweb_request)requires.cliPackagenull(no Balancer CLI — the shell path is a Node script using@balancer/sdk)chains[base, ethereum, arbitrum, optimism, avalanche]authnonerisk[slippage, low-liquidity]