From e71a743a0a6e3a1a6bde5c1bc29df94555f74bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Falc=C3=B3n?= Date: Wed, 13 May 2026 18:53:30 +0100 Subject: [PATCH] feat: Coinbase banking integration (#388) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Adds **Coinbase** as a banking/investment provider, alongside existing Binance, Bitpanda, and Indexa Capital integrations. Connection auth uses Coinbase Developer Platform (CDP) JWT (ES256) API keys. Sync model mirrors Bitpanda: no historical balance reconstruction (Coinbase API has no daily snapshot endpoint). Balance tracking starts from connection date. ## Account model One single **Crypto Portfolio** Whisper Account in the user's fiat currency, aggregating all Coinbase wallets (crypto + fiat). ## Backend - `app/Services/Banking/CoinbaseClient.php` — JWT-signed Coinbase Advanced Trade client (`firebase/php-jwt` ES256). Per-request JWT, 120s TTL, `uri` claim `"METHOD host/path"`. Methods: `getAccounts`/`getAllAccounts` (cursor pagination), `getProduct`, `getBestBidAsk` (batched), with 429 retry/backoff. - `app/Services/Banking/CoinbaseBalanceSyncService.php` — Partitions wallets into fiat vs crypto. Batched `best_bid_ask` for prices, USD stablecoin shortcut (USDT/USDC/DAI/PYUSD/GUSD), `CurrencyConversionService` fallback. Aggregates everything into user fiat. - `app/Http/Controllers/OpenBanking/CoinbaseController.php` + `ConnectCoinbaseRequest.php` — mirror Bitpanda flow, validates `api_key_name` (`organizations/{org}/apiKeys/{id}`) + PEM `private_key`. Stores key_name in `api_token`, PEM in `api_secret` (already encrypted TEXT). - `BankingConnection::isCoinbase()`, `SyncBankingConnectionJob::syncCoinbase()`, credential-update flow. - `routes/web.php`: `POST /open-banking/coinbase/connect`. - Bank seeder entry + factory `coinbase()` state. ## Frontend - `connect-account-dialog.tsx` / `connect-account-inline.tsx`: Coinbase appears in the bank picker. Confirm step shows `` for API key name and `