KeeperHub / KeeperHub/keeperhub
feat: stablecoin to native gas top-up for Turnkey EOA wallets
- Dominant language
- TypeScript
- Stars
- 24
- Forks
- 93
- Avg merge
- 1d 4h
- Merged PRs (30d)
- 253
Description
## Problem
Orgs and agents often fund the Turnkey wallet with **USDC (or another stable)** and still cannot keep executing:
- Gas **sponsorship** pays the **network fee only**. It does not create spendable native ETH.
- Native is still required for ETH value transfers, Safe outer sends, withdraw, and any path that falls back to self-pay when sponsorship or credits are unavailable.
- Today there is no productized "convert stable to gas" path. `POST /api/execute/swap` returns **501 Coming soon**. Agents must hand-compose Uniswap + WETH unwrap (and still need gas or sponsorship for that composition).
This is the failure mode: **have USDC, cannot pay or bootstrap gas**.
## Scope (v1)
Same-chain **USDC to native ETH** on the org **Turnkey EOA**, as one idempotent Direct Execution action.
**In**
- `POST /api/execute/gas-top-up` (dedicated route; do not overload general `/swap` yet)
- MCP tool `top_up_gas` wrapping that route
- Wallet UI CTA: "Top up gas from USDC" (can follow the API in a second PR if preferred)
- Docs: distinguish from PAYG "send USDC for billing; we cover gas"
**Flow (server-orchestrated)**
1. Resolve org Turnkey EOA; reject Safe-as-sender for v1 (gas lands on the EOA that pays gas).
2. Check USDC balance on the chosen chain.
3. Under **sponsorship** (required for MVP; fail closed if ineligible or credits exhausted): approve USDC to router, swap USDC to WETH, unwrap WETH to ETH.
4. Return `{ ethReceived, usdcSpent, txHashes[], sponsored: true, executionId? }` with `Idempotency-Key` support like other execute routes.
**Chains (v1):** sponsorship-supported EVM where Uniswap V3 and WETH already exist in the protocol registry (for example Base, Ethereum). Exact list in the PR.
**Out of scope for v1**
- General `POST /api/execute/swap`
- Cross-chain bridge
- Fiat on-ramp
- Safe-as-sender / funding the Safe itself
- Solana
## Why this is separate from sponsorship
Sponsorship already solves "zero ETH for **fees**" on eligible EOA routes. It does **not** solve "need **spendable** ETH" or "bootstrap when the only balance is a stable." Top-up creates native balance; sponsorship continues to pay fees on eligible writes.
## Building blocks (exist)
- Sponsored write path (`executeSponsoredTransaction` / Turnkey Gas Station)
- Uniswap V3 and `wrapped` unwrap protocol actions
- Execute-route auth, scopes, idempotency patterns (`/api/execute/transfer`, contract-call)
- Gas credits metering
## Acceptance criteria
- [ ] With USDC and **no** native ETH on a sponsorship-eligible EOA, `gas-top-up` succeeds and wallet native balance increases.
- [ ] Without sponsorship eligibility or credits, the call **fails closed** with a clear error (does not attempt an unsponsored swap that needs ETH).
- [ ] Idempotent retry with the same key does not double-spend USDC.
- [ ] Unit/integration coverage for happy path, fail-closed, and idempotency.
- [ ] Docs updated; PAYG billing wording remains distinct.
## Non-goals / notes
- Not a replacement for a full Swap product (`/swap` can stay 501 until a separate issue).
- Amount UX can start as explicit `amountUsdc`; "enough for N txs" can be a follow-up.
Contributor guide
Research direction
Start by reading the existing execute routes, especially /api/execute/transfer and contract-call, then trace executeSponsoredTransaction, the Uniswap V3 and wrapped protocol actions, and the gas credits metering. The work is done when the dedicated gas-top-up route and top_up_gas tool meet the happy-path, fail-closed, idempotency, test-coverage, and documentation acceptance criteria.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend, blockchain, documentation
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100