Skip to content

feat: KEEP-578 add Frax Ether V2 protocol plugin#1287

Merged
suisuss merged 4 commits into
stagingfrom
feat/KEEP-578-frax-ether-v2
May 19, 2026
Merged

feat: KEEP-578 add Frax Ether V2 protocol plugin#1287
suisuss merged 4 commits into
stagingfrom
feat/KEEP-578-frax-ether-v2

Conversation

@suisuss
Copy link
Copy Markdown

@suisuss suisuss commented May 19, 2026

Summary

Add Frax Ether V2 as a new protocol plugin exposing the V2 minter. First protocol added under the iterative /add-protocol workflow (KEEP-577) - tests the new 5-phase loop end-to-end.

Closes KEEP-578.

Surface

  • protocols/frax-ether-v2.ts (defineAbiProtocol, single contract, mainnet only)
  • protocols/abis/frax-ether-v2.json (reduced V2 ABI, 4 functions)
  • 4 actions: mint, mint-and-give, mint-and-stake, mint-paused
  • tests/unit/protocol-frax-ether-v2.test.ts (17 assertions, all pass)
  • tests/integration/protocol-frax-ether-v2-onchain.test.ts (mainnet, gated on INTEGRATION_TEST_MAINNET_RPC_URL, all 4 pass)
  • docs/plugins/frax-ether-v2.md, _meta.ts and overview.md updates

Version isolation

V2 only. V1 minter used submit(); V2 renamed to mintFrxEth(). A V1 ABI against V2 bytecode produces INVALID_ARGUMENT on first call - this is exactly the failure mode KEEP-577's research-phase gate was designed to catch. Confirmed against the verified V2 contract at 0x7Bc6bad540453360F744666D625fec0ee1320cA3.

Slug frax-ether-v2 follows the protocol-version-branding rule from .claude/commands/add-protocol.md (Frax themselves brand it as V2).

Out of scope (file follow-ups when wanted)

  • FraxEtherRedemptionQueueV2 at 0xfDC69e6BE352BD5644C438302DE4E311AAD5565b (queue-based redemption, separate surface from instant unwrap)
  • sfrxETH ERC4626 vault at 0xac3E018457B222d93114458476f3E3416Abbe38F (already addressable via erc4626VaultActions())
  • L2 token-read surface for frxETH/sfrxETH on Arbitrum, Base, Optimism, Polygon, BNB, Avalanche, Moonbeam (LayerZero-bridged variants; not mintable)

Test plan

  • Unit tests pass (17/17 via pnpm test tests/unit/protocol-frax-ether-v2.test.ts)
  • Integration tests pass against real mainnet RPC (4/4 via INTEGRATION_TEST_MAINNET_RPC_URL=<mainnet-rpc> pnpm test tests/integration/protocol-frax-ether-v2-onchain.test.ts)
  • pnpm discover-plugins registers the protocol and regenerates protocols/index.ts + lib/types/integration.ts
  • pnpm type-check passes
  • Reviewer manually verifies protocol appears in the workflow builder action grid with the 4 expected actions and the mainnet-only chain restriction in the chain selector

Add Frax Ether V2 as a new protocol plugin exposing the V2 minter
contract. First protocol added under the iterative /add-protocol
workflow (KEEP-577).

Surface:
- protocols/frax-ether-v2.ts uses defineAbiProtocol with one contract
  (the V2 minter at 0x7Bc6bad540453360F744666D625fec0ee1320cA3) on
  Ethereum mainnet.
- 4 actions: mint (payable), mint-and-give (payable, recipient),
  mint-and-stake (payable, recipient, returns sfrxETH shares),
  mint-paused (read).
- protocols/abis/frax-ether-v2.json: reduced V2 ABI, functions only.

Version isolation: V2 explicit. V1 minter used submit(); V2 uses
mintFrxEth(). Picking the wrong version's ABI produces INVALID_ARGUMENT
on first call. Slug is frax-ether-v2 per the protocol-version-branding
rule.

Tests:
- tests/unit/protocol-frax-ether-v2.test.ts: 17 shape and override
  integrity assertions; pass.
- tests/integration/protocol-frax-ether-v2-onchain.test.ts: 4 on-chain
  calldata validation tests gated on INTEGRATION_TEST_MAINNET_RPC_URL.
  All 4 pass against a real mainnet RPC.

Docs:
- docs/plugins/frax-ether-v2.md with per-action sections.
- docs/plugins/_meta.ts nav entry (between curve and lido).
- docs/plugins/overview.md table row (between Curve and Lido).

Out of scope (deferred):
- FraxEtherRedemptionQueueV2 surface (queue-based redemption,
  separate contract).
- sfrxETH ERC4626 vault surface (addressable via
  erc4626VaultActions()).
- L2 token-read surface for frxETH/sfrxETH on Arbitrum/Base/Optimism.
Restructure the helper that drove the 3 biome warnings the file shipped
with:

- Hoist the `/^0x/` regex literal to a module-scope constant
  (TX_RESULT_HEX_PREFIX). Clears `useTopLevelRegex`.
- Move the helper inside the describe block AND switch it from
  expect-based to throw-based. The helper no longer contains expect()
  calls; instead it rethrows any error class that is not CALL_EXCEPTION,
  and call sites assert with `expect(...).resolves.toBeUndefined()`.
  Clears the two `noMisplacedAssertion` warnings.

Net effect: helper conveys intent through type signature + exceptions
(Promise<void> resolves iff calldata was accepted by the bytecode);
each it() block contains an explicit assertion; biome check on the file
is clean.

Matches aave-v4-onchain.test.ts in structure but improves on its lint
status. Same refactor pattern is available for aave-v4, rocket-pool,
uniswap, and wrapped if their helpers are extracted to a shared module
in a follow-up.

Verified: pnpm exec biome check is clean on this file; pnpm type-check
passes; integration test still passes 4/4 against a mainnet RPC.
…nit test

The "minter contract is deployed on Ethereum mainnet only" test asserted
toEqual(["1"]) followed by toContain("1") and four not.toContain checks.
The toEqual already proves the array is exactly ["1"]; the other five
assertions are subsumed.

Drop the redundant lines. 17 unit tests still pass.
@github-actions
Copy link
Copy Markdown

PR Environment Deployed

Your PR environment has been deployed!

Environment Details:

Components:

  • Keeperhub Application
  • PostgreSQL Database (isolated instance)
  • LocalStack (SQS emulation)
  • Redis (isolated instance)
  • Schedule Dispatcher (staging image)
  • Block Dispatcher (staging image)
  • Event Tracker (staging image)

The environment will be automatically cleaned up when this PR is closed or merged.

- public/protocols/frax-ether.png: brand asset for the path declared
  at protocols/frax-ether-v2.ts:24.
- scripts/frax-ether-v2-fork-test.ts: tsx smoke test that broadcasts
  mintFrxEth against a local anvil mainnet fork and asserts the 1:1
  frxETH mint. Verified end-to-end against an anvil fork.
- docs/plugins/frax-ether-v2.md: "Testing Without Risking Real ETH"
  section. Documents why there is no testnet entry (Frax did not
  deploy V2 to any public testnet) and the fork pattern as the
  supported substitute.
@github-actions
Copy link
Copy Markdown

PR Environment Deployed

Your PR environment has been deployed!

Environment Details:

Components:

  • Keeperhub Application
  • PostgreSQL Database (isolated instance)
  • LocalStack (SQS emulation)
  • Redis (isolated instance)
  • Schedule Dispatcher (staging image)
  • Block Dispatcher (staging image)
  • Event Tracker (staging image)

The environment will be automatically cleaned up when this PR is closed or merged.

@suisuss suisuss merged commit fdf55a5 into staging May 19, 2026
43 checks passed
@suisuss suisuss deleted the feat/KEEP-578-frax-ether-v2 branch May 19, 2026 05:29
@github-actions
Copy link
Copy Markdown

🧹 PR Environment Cleaned Up

The PR environment has been successfully deleted.

Deleted Resources:

  • Namespace: pr-1287
  • All Helm releases (Keeperhub, Scheduler, Event services)
  • PostgreSQL Database (including data)
  • LocalStack, Redis
  • All associated secrets and configs

All resources have been cleaned up and will no longer incur costs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant