Skip to content

feat: add Cleave action provider - #1620

Open
cleave-protocol wants to merge 4 commits into
coinbase:mainfrom
cleave-protocol:feat/cleave-action-provider
Open

cleave-protocol wants to merge 4 commits into
coinbase:mainfrom
cleave-protocol:feat/cleave-action-provider

Conversation

@cleave-protocol

Copy link
Copy Markdown

Description

Adds cleaveActionProvider, an action provider for Cleave by Cleave Protocol: a DEX aggregator on Ethereum, Arbitrum, Base, BNB Chain, Polygon and Optimism. It splits swaps over pools and paths, runs swaps between these chains, and sells native gas (ETH, BNB, POL) for USDC. Its agent API needs no API key.

Actions:

  • find_token: finds a token by symbol or contract address.
  • plan_swap: plans a swap from the wallet on its current chain and returns the route, the amounts, the third-party costs, the notices and the checked unsigned calls. It sends nothing.
  • execute_swap: sends a plan that plan_swap returned, by its requestId, with confirmed: true.
  • track_swap: reports the status of a sent swap or gas top-up.
  • quote_gas: quotes native gas paid in USDC. It signs nothing.
  • buy_gas: signs a checked gas offer's single USDC authorization with the wallet and submits it, with confirmed: true.

How the provider uses the wallet:

  • The wallet address and chain always come from the wallet provider, never from the model.
  • Every plan and gas offer is checked with @cleave-protocol/ai-sdk/core before it is returned. The checks cover the calls' targets and functions on Cleave's published contract list, the approve spender and amount, the wallet, the chain and the recipient. For gas offers they also cover the order hash, the payment address and the pinned contracts.
  • execute_swap sends exactly the plan the user saw: once, before its validUntil, and only from the wallet address and chain it was made for. It never plans again, and it checks the wallet's address and chain again before every call.
  • It also requires that:
    • the tokens were given as addresses or as USDC or the chain's native or wrapped native coin;
    • the main call takes exactly the requested amount of an ERC-20 sell token;
    • a swap to another chain pays the recipient directly.
  • Routes outside these rules can be planned but not executed.
  • Each hash is recorded as soon as it is sent. If a send or a receipt wait throws, the action returns outcome_unknown with every sent hash.
  • buy_gas refuses smart wallet providers and smart contract wallets. The signature is never returned to the model.
  • Every response to the model has URLs removed.
  • Cleave's fee is included in the price; third-party costs are listed in each plan.

The new dependency @cleave-protocol/ai-sdk is used only through its /core entry: the API client and the address checks. That entry has no ai or zod import, and the package is published with npm provenance. The lockfile change is limited to that package, and CI=true pnpm install leaves pnpm-lock.yaml unchanged.

Tests

Unit tests, typescript/agentkit:

Node 18.20.8: Test Suites: 63 passed, 63 total; Tests: 960 passed, 960 total
Node 20.18.0: Test Suites: 63 passed, 63 total; Tests: 960 passed, 960 total

cleaveActionProvider.test.ts has 56 tests. They use live API answers as fixtures and cover:

  • refusals in which nothing is sent or signed
  • single use and expiry
  • a wallet change between calls
  • amount binding
  • swaps to another chain that are plan only
  • unknown outcomes
  • smart wallet labels
  • signature redaction

pnpm run lint, pnpm run format:check and pnpm run check pass.

Read-only live check:

Setup: the provider's actions from getActions(), on Base, with a wallet that has no key; nothing was signed or sent

actions: CleaveActionProvider_find_token, CleaveActionProvider_plan_swap, CleaveActionProvider_execute_swap, CleaveActionProvider_track_swap, CleaveActionProvider_quote_gas, CleaveActionProvider_buy_gas
find_token USDC on Base: USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 listed=true
plan_swap 10 USDC -> WETH on Base: 2 checked calls to 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, 0xb08F28a3575805ee1E3729fc19Ab7E869CBAF563, receive expected 0.004367362312958127 WETH
plan_swap 10 USDC Base -> Arbitrum USDC: 2 checked calls, receive expected 9.990856 USDC on 42161
quote_gas 5 USDC on Base: kind swap, fee 0.048524 USDC, typedData returned: false

Checklist

  • Added documentation to all relevant README.md files
  • Added a changelog entry

Adds cleaveActionProvider with find_token, plan_swap, execute_swap,
track_swap, quote_gas and buy_gas for Ethereum, Arbitrum, Base, BNB Chain,
Polygon and Optimism.

Every plan and gas offer is checked with @cleave-protocol/ai-sdk/core
against Cleave's published contracts before the wallet sends or signs
anything. execute_swap and buy_gas require confirmed: true; the wallet
address and current chain are taken from the wallet provider.
… check claims

- execute_swap records each hash as soon as it is sent (userOpHash on
  smart wallets, with the mined txHash once known). If a send or a
  receipt wait throws, it returns outcome_unknown with every sent hash
  and asks to track the swap before any retry.
- execute_swap takes an optional minimumReceive from the confirmed plan
  and refuses when the new plan's minimum is lower.
- README and descriptions state what the address checks cover and what
  they leave to the user.
- plan_swap no longer passes the API's next text on; gas top-ups refuse
  on BNB Chain before the API call; a smart contract wallet must name the
  recipient for a swap to another chain; error text sent to the model
  has URLs removed; a duplicate call check is gone.
… wallet

- plan_swap keeps each checked plan in memory with the wallet address
  and chain it was made for. execute_swap takes requestId and
  confirmed: true and sends exactly that plan, once, before validUntil,
  from the same wallet on the same chain; it never plans again.
  minimumReceive is removed.
- execute_swap needs sellToken and buyToken given as addresses or as
  USDC or the native or wrapped native coin. For other sell tokens it
  reads decimals() through the wallet provider and needs the approve to
  be for exactly the requested amount.
- The wallet's address and chain are checked again before every send
  and before signing a gas authorization.
- buy_gas refuses smart wallet providers by type before reading code.
- Every response to the model has URLs removed and the API's next text
  dropped; the gas authorization signature is redacted from every
  post-submit response.
- A smart wallet's user operation is waited for once more before an
  unknown outcome, which then points to the wallet's user operation.
- A swap to another chain is executed only when its transfer pays the
  recipient (or the wallet) directly; a route that swaps on arrival
  through a destination message stays plan only.
- For every ERC-20 sell, the main call must take exactly the requested
  amount in the token's decimals (known for USDC and the wrapped native
  coin, read from the chain for a token given by address); a wallet
  that already holds an allowance works, and measured routes that take
  more stay plan only.
- A kept plan also expires by the local clock; only CDP smart wallets
  are treated as returning user operation hashes; the approve note in
  a failure is given only when the last call failed.
@cb-heimdall

Copy link
Copy Markdown

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
1 if authored by an app that is not allowlisted and lacks verified human attribution 0
Sum 1

@github-actions github-actions Bot added documentation Improvements or additions to documentation action provider New action provider typescript labels Nov 4, 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

action provider New action provider documentation Improvements or additions to documentation typescript

Development

Successfully merging this pull request may close these issues.

2 participants