Personal control plane for Base Account users: who can spend your USDC, standing orders to pay a basename on a schedule, and one-time pay requests.
- Repo: https://github.com/philkraft1/Float
- Live demo: https://basea-tau.vercel.app
- Network: Base (
8453) - Base.dev app id:
6a8abd3739d7d26f4bad1883
Base App is full of swaps, launches, and merchant checkout. Nothing else is:
- A daily inbox of Base Account spend permissions and leftover ERC-20 approvals
- One-tap revoke
- Person-to-person recurring USDC (rent, allowance) using spend permissions when the host allows it, with a Pay this period fallback when it does not
- Connect Base Account or an injected wallet.
- Inbox — incoming and outgoing standing orders and pay requests, plus who can still spend.
- New — create a standing order to a basename, a one-time USDC request (open or named payer), or Send now (one-tap USDC via Base Account
pay()). /due/{id}— shareable standing-order link; payer settles the current period./pay/{id}— shareable one-time request; payer approves USDC and pays.- Permissions — list spend permissions + discovered USDC allowances; revoke.
Spend permissions inside Base App itself are still rolling out. Auto-charge is implemented; Pay this period is the path that always works.
contracts/src/StandingOrder.sol — create, payPeriod, recordPayment (operator / CDP), cancel.
contracts/src/PayRequest.sol — createRequest, pay. Set NEXT_PUBLIC_PAY_REQUEST_ADDRESS after deploy.
npm run contracts:build
npm run contracts:test
# needs Base ETH + DEPLOYER_PRIVATE_KEY
npm run contracts:deploy
# Etherscan V2 key (works for Basescan)
npm run contracts:verifyThen set the CDP subscription owner as operator:
node scripts/set-operator.mjsOnchain counters: GET /api/metrics.
See .env.example. Never commit private keys. Put deploy secrets in contracts/.env, app secrets in .env.local and Vercel. Only NEXT_PUBLIC_* is safe on the client.
| Variable | Where it lives | Where you get it |
|---|---|---|
DEPLOYER_PRIVATE_KEY |
contracts/.env |
Your EOA (MetaMask / Rabby / Coinbase Wallet export, or Foundry cast wallet). Fund it with ETH on Base. Not from CDP. |
ETHERSCAN_API_KEY |
contracts/.env |
etherscan.io/apidashboard (API V2; same key works for Basescan) |
NEXT_PUBLIC_STANDING_ORDER_ADDRESS |
.env.local + Vercel |
Printed by npm run contracts:deploy (StandingOrder: 0x…); script also writes .env.local |
NEXT_PUBLIC_PAY_REQUEST_ADDRESS |
.env.local + Vercel |
Deployed PayRequest address (verified on Base) |
NEXT_PUBLIC_BUILDER_CODE |
.env.local + Vercel |
base.dev → project → Settings → Builder Codes |
NEXT_PUBLIC_USDC_ADDRESS / NEXT_PUBLIC_RPC_URL |
Client (defaults exist) | Native USDC on Base + https://mainnet.base.org unless you use a paid RPC |
CDP_API_KEY_ID / CDP_API_KEY_SECRET |
.env.local + Vercel (server) |
CDP Portal API keys |
CDP_WALLET_SECRET |
.env.local + Vercel (server) |
CDP Portal → Wallets / API Wallets → Wallet Secret (separate from the API key) |
OPERATOR_ADDRESS |
contracts/.env |
address from GET /api/subscription/owner after CDP is configured |
PAYMASTER_URL |
Server, optional | CDP Paymaster |
CRON_SECRET |
Vercel | You invent this; Vercel Cron sends Authorization: Bearer |
BASE_NOTIFICATIONS_API_KEY |
Server, optional | Base Notifications API |
Never put CDP secrets or the deployer key in NEXT_PUBLIC_* vars.
Do them in order. Steps 2, 5, and 6 are not env vars.
flowchart TD
wallet[Your funded EOA]
cdpPortal[portal.cdp.coinbase.com]
baseDev[base.dev]
etherscan[etherscan.io API V2]
deploy[npm run contracts:deploy]
ownerApi["GET /api/subscription/owner"]
talent[talent.xyz / Builder Score]
wallet -->|"DEPLOYER_PRIVATE_KEY"| deploy
deploy -->|"prints contract address"| envLocal["NEXT_PUBLIC_STANDING_ORDER_ADDRESS"]
etherscan -->|"ETHERSCAN_API_KEY"| verify["npm run contracts:verify"]
baseDev -->|"NEXT_PUBLIC_BUILDER_CODE"| envLocal
cdpPortal -->|"CDP_API_KEY_ID SECRET WALLET_SECRET"| vercel[Vercel server env]
vercel --> ownerApi
ownerApi -->|"OPERATOR_ADDRESS"| setOp["npm run contracts:operator"]
envLocal --> setOp
baseDev --> listing[App listing name Due]
talent --> github[Connect Float repo + deployer]
DEPLOYER_PRIVATE_KEY— hex private key of an EOA you control (0x+ 64 hex chars) incontracts/.env. Fund that address with a little ETH on Base. Optional:BASE_RPC_URL.- Deploy + verify —
npm run contracts:deploythennpm run contracts:verify(needsETHERSCAN_API_KEY). The deploy script isscripts/deploy-standing-order.mjs. NEXT_PUBLIC_STANDING_ORDER_ADDRESS(output of step 2) andNEXT_PUBLIC_BUILDER_CODE(base.dev Settings → Builder Codes) in.env.localand Vercel → Settings → Environment Variables.- CDP trio on Vercel (server only) and
.env.local. Redeploy /npm run dev, thenGET /api/subscription/owner→ thataddressisOPERATOR_ADDRESS. Put it incontracts/.envand runnpm run contracts:operator. WithoutCDP_WALLET_SECRET, auto-charge stays off; Pay this period still works. - Base.dev listing — dashboard paste, not an env var. Same project as app id
6a8abd3739d7d26f4bad1883. See the table below. - Talent — talent.xyz: Basename, human checkmark, score ≥ 40, connect GitHub philkraft1/Float and the same deployer wallet as step 1. After mainnet, create / pay / revoke on Due so Talent sees txs on your verified
StandingOrder.
npm install
cd contracts && forge install foundry-rs/forge-std --no-git && cd ..
npm run devIDE: .cursor/mcp.json already registers https://mcp.base.org. Restart Cursor and connect under Settings → MCP. Install notes: docs.base.org/ai-agents/quickstart.
Cloud Agents do not load project mcp.json. Add the same HTTP server in the Cloud Agents MCP dropdown and complete Base Account OAuth. Then a prompt like Show me my wallets can run against the connected Base Account. Every send, swap, or sign still needs a Base Account approval.
Register / update the project at base.dev. Discovery no longer uses farcaster.json.
| Field | Value |
|---|---|
| Name | Due |
| Tagline | Standing USDC between people, plus a spend-permission inbox |
| Description | See every spender that can take your USDC, revoke in one tap, and create person-to-person standing orders (rent / allowance) to a basename. Auto-charge when Base Account spend permissions are available; otherwise pay each period from the share link. |
| Category | finance |
| Primary URL | https://basea-tau.vercel.app |
| Icon | /app-icon.svg or /due.svg |
| Screenshots | Inbox, New order, Permissions, /due/{id} |
| Builder code | paste from Base.dev Settings |
Eligibility is on you, not the app: Basename, Talent Builder Score ≥ 40, human checkmark, OFAC-clean wallet.
Ranked activity this repo is meant to produce:
- Public GitHub quality — keep github.com/philkraft1/Float public; connect it on Talent.
- Verified mainnet contract activity — users must transact with our
StandingOrder, not only USDC / SpendPermissionManager. Deploy, verify, then create / pay / revoke for real. - Base App usage — this listing on base.dev, builder code on every write (
NEXT_PUBLIC_BUILDER_CODE+ ERC-8021 suffix). - Share — cast the live demo after mainnet ship. Connect the deployer wallet on Talent.
Do not wash volume. Talent does not pay for a Sepolia-only tutorial.
| Metric | Why |
|---|---|
| Orders created / paid | Core usage (GET /api/metrics) |
| Unique payers / payees | Real users + onboarding |
USDC volume through payPeriod / charge |
Economic activity |
| Permission and allowance revokes | Safety hygiene |
| Permission-inbox opens | Retention loop |
Next.js · wagmi · viem · Base Account SDK (pay, subscribe) · Foundry · TanStack Query · CDP subscriptions