diff --git a/README.md b/README.md index 662cd55..2ae0182 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ In addition to workshop materials, this repository includes reference guides on | Topic | Description | |-------|-------------| | [Soroban Development](./soroban-development/) | Smart contract development with Rust SDK | -| [Wallet Integration](./wallet-integration/) | Freighter, Stellar Wallets Kit, Smart Account Kit | +| [Wallet Integration](./wallet-integration/) | Freighter, Stellar Wallets Kit, Smart Account Kit, Cavos | | [OpenZeppelin Tools](./openzeppelin/) | Audited contracts, Contract Wizard, Relayer, Monitor | | [DeFi Protocols](./defi/) | Lending, DEXs, vaults, and stablecoins | | [Tokens](./tokens/) | Stellar Assets vs Soroban Tokens | @@ -49,6 +49,7 @@ In addition to workshop materials, this repository includes reference guides on - [Freighter](./wallet-integration/freighter.md) - Browser extension wallet - [Stellar Wallets Kit](./wallet-integration/stellar-wallets-kit.md) - Multi-wallet SDK - [Smart Account Kit](./wallet-integration/smart-account-kit.md) - Passkey-based smart wallets +- [Cavos](./wallet-integration/cavos.md) - Embedded self-custodial wallet SDK ### OpenZeppelin Stellar Suite diff --git a/wallet-integration/README.md b/wallet-integration/README.md index 0929285..637fdd3 100644 --- a/wallet-integration/README.md +++ b/wallet-integration/README.md @@ -11,6 +11,7 @@ Stellar offers multiple approaches to wallet integration, each suited for differ | [Freighter](./freighter.md) | Quick integration, SDF's official wallet | Browser extension or Freighter Mobile app | Low | | [Stellar Wallets Kit](./stellar-wallets-kit.md) | Multi-wallet support | Users choose their preferred wallet | Medium | | [Smart Account Kit](./smart-account-kit.md) | Modern dapps, best UX | Passkey-based, no extension needed | Medium | +| [Cavos](./cavos.md) | Embedded self-custodial SDK | Google or Apple login; control key unwrapped locally | Medium | ## Quick Decision Guide @@ -30,6 +31,13 @@ Stellar offers multiple approaches to wallet integration, each suited for differ - You're building a consumer-facing application - You want passkey-based authentication (FaceID, TouchID, etc.) +**Choose Cavos if:** +- You want an embedded self-custodial wallet (no extension, no seed phrase) +- Users should sign in with Google or Apple +- The Ed25519 control key is unwrapped locally on the device (Cavos cannot see it or move funds) +- You are building with React or React Native +- Optional pass-through gas sponsorship would help onboarding + ## Comparison See [comparison.md](./comparison.md) for a detailed feature comparison. @@ -44,6 +52,8 @@ For most new projects in 2026, we recommend **Smart Account Kit** for the best u Note that the kit is still pre-1.0 (v0.4.x) with occasional breaking changes between minor versions — pin your version and check the repo README when upgrading. +If you want Google or Apple login with a device-native embedded wallet (the Stellar control key is unwrapped locally and Cavos cannot see it), see **Cavos**. + ## Additional Resources - [Official Stellar Developer Docs](https://developers.stellar.org/docs/build/apps) diff --git a/wallet-integration/cavos.md b/wallet-integration/cavos.md new file mode 100644 index 0000000..159b034 --- /dev/null +++ b/wallet-integration/cavos.md @@ -0,0 +1,301 @@ +# Cavos + +Cavos is a device-native embedded self-custodial wallet SDK. Users sign in with Google or Apple. No seed phrase, no browser extension, and no MPC. + +On Stellar, Cavos provisions a classic `G…` account (not a Soroban contract) that interoperates with existing Stellar tools and can still invoke Soroban contracts. Starknet and Solana use non-extractable P-256 device signers to sign. Stellar is different: a device-bound P-256 ECDH key locally unwraps an encrypted Ed25519 control key; the control key signs Stellar transactions. Unwrap happens on the device. Cavos cannot see the control key or move funds. Passkeys enroll additional devices; they do not sign. The same SDK also supports Solana and Starknet. + +The kit README notes that production launch still requires operational, security, and relayer hardening for the target deployment. + +## Overview + +- **Type:** Embedded self-custodial wallet SDK +- **User Experience:** Google or Apple login; the control key is unwrapped locally on the device +- **Best for:** Consumer apps that want in-app wallets without extensions or seed phrases +- **Package:** [`@cavos/kit`](https://www.npmjs.com/package/@cavos/kit) (React and React Native) +- **GitHub:** [cavos-labs/kit](https://github.com/cavos-labs/kit) + +## Why Cavos? + +| Typical wallet onboarding | Cavos | +|---------------------------|-------| +| Install a browser extension | No installation; embed the wallet in your app | +| Save a seed phrase | Sign in with Google or Apple | +| Key material held by a third party or split across servers | Control key is unwrapped locally; Cavos never sees it | +| Desktop-oriented popups | Works in the browser and in React Native | + +## Key Features + +- **Embedded self-custody:** The Ed25519 control key is unwrapped locally on the device. Cavos cannot see it, sign transactions, or move funds. +- **Familiar login:** Hosted Google or Apple auth. Login never signs transactions. +- **No seed phrase, no extension, no MPC.** +- **Classic Stellar account:** Deterministic `G…` address derived from identity plus app salt. +- **Silent local signing:** On a known device, the device-bound P-256 key unwraps the control key locally and the control key signs without a wallet popup. +- **Passkeys enroll devices:** A passkey is a second factor for adding a new device. It does not sign transactions. +- **Optional gas sponsorship:** Pass-through relayer that sponsors reserves and fees when configured. The relayer is not a custodian and cannot move funds. +- **React and React Native:** Same package, including a React Native entrypoint. + +## Installation + +```bash +npm install @cavos/kit +``` + +Create an app in the [Cavos dashboard](https://cavos.xyz) and copy its App ID. The App ID is a public client identifier used to enable hosted auth and optional sponsorship. + +React Native needs extra native peers and a rebuild; see [React Native](#react-native) below. + +## Hosted Login (Google or Apple) + +`CavosAuth` provides hosted Google and Apple login that resolves to an identity you pass into `connect`. Handle the OAuth callback first; only generate a new OAuth URL when this page load is not a callback. + +```typescript +import { Cavos, CavosAuth } from "@cavos/kit"; + +const auth = new CavosAuth({ + appId: process.env.NEXT_PUBLIC_CAVOS_APP_ID, +}); + +const params = new URLSearchParams(window.location.search); +if (!params.has("cavos_auth_code")) { + window.location.href = await auth.getGoogleOAuthUrl(); +} else { + const identity = await auth.handleCallback(window.location.search); + + const wallet = await Cavos.connect({ + chain: "stellar", + network: "testnet", + appSalt: "my-app", + identity, + appId: process.env.NEXT_PUBLIC_CAVOS_APP_ID, + }); + + console.log(wallet.address); +} +``` + +Register every callback URL for your app in the Cavos dashboard (scheme, host, path; no wildcards). Treat `appSalt` as permanent. Changing it derives a different wallet for every user. + +Login never signs transactions. On Stellar the device-bound P-256 key unwraps the Ed25519 control key locally, and that control key signs. + +### Advanced: bring your own identity + +If you already authenticate users, kit still accepts `{ userId, email }` as `identity` instead of hosted login. This is not the default path. The Stellar address is derived from `userId` plus `appSalt`, so both must stay stable. Do not use a guessable or public identifier as `userId`. + +## Sign and Send Transactions + +The returned wallet is a discriminated union. Narrow on `wallet.chain` and gate on `status === "ready"` before executing. + +Native XLM transfer (amount is stroops; 1 XLM = 10_000_000 stroops). `execute` takes options as the third argument: + +```typescript +if (wallet.chain === "stellar" && wallet.status === "ready") { + const hash = await wallet.execute( + 10_000_000n, + "GDESTINATION...ADDRESS" + ); + console.log(hash); + + // await wallet.execute(10_000_000n, "GDESTINATION...ADDRESS", { sponsored: false }); +} +``` + +Soroban contract invocation. `invokeContract` applies `nativeToScVal` without an address type hint, so a raw G address string becomes an ScVal string. For `require_auth` arguments, pass an explicit address ScVal. Sponsorship options go in `opts` inside the parameter object, not as a top-level `sponsored` field: + +```typescript +import { nativeToScVal } from "@stellar/stellar-sdk"; + +if (wallet.chain === "stellar" && wallet.status === "ready") { + const hash = await wallet.invokeContract({ + contractId: "C...CONTRACT", + method: "do_thing", + args: [nativeToScVal(wallet.address, { type: "address" })], + // opts: { sponsored: false }, + }); +} +``` + +On a new device the same identity lands on the same `G…` with `status: "needs-device-approval"`. Do not create a second wallet. Enroll the device with a passkey or a recovery code. + +## React Integration + +Bindings ship in the same package under `@cavos/kit/react`: + +```tsx +import { CavosProvider, useCavos } from "@cavos/kit/react"; + +export function Providers({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} +``` + +```tsx +export function WalletButton() { + const { isAuthenticated, address, wallet, walletStatus, openModal, logout } = + useCavos(); + + if (!isAuthenticated) { + return ; + } + + const send = async () => { + if (wallet?.chain === "stellar" && walletStatus.isReady) { + await wallet.execute(10_000_000n, "GDESTINATION...ADDRESS"); + } + }; + + return ( +
+ {address?.slice(0, 4)}...{address?.slice(-4)} + + +
+ ); +} +``` + +Gate execution on `walletStatus.isReady`, not merely `isAuthenticated`. + +## React Native + +Switching the import to `@cavos/kit/react-native` is not enough. Expo Go is not supported: the kit ships a custom native module, so you need an Expo development build / EAS or bare React Native, then a native rebuild after installing peers and the config plugin. + +Install the packages the kit docs require: + +```bash +npm install @cavos/kit expo expo-modules-core expo-web-browser expo-linking react-native-get-random-values +npx expo prebuild +npx expo run:ios # or: npx expo run:android +``` + +Add the `@cavos/kit` config plugin and set `redirectUri` plus `rpId`: + +```json +{ + "expo": { + "scheme": "myapp", + "plugins": [["@cavos/kit", { + "rpId": "auth.example.com", + "scheme": "myapp" + }]] + } +} +``` + +```tsx +import { CavosProvider } from "@cavos/kit/react-native"; + +export function Providers({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} +``` + +Register that same `redirectUri` exactly in the Cavos dashboard under Callback URLs. `rpId` is required for native passkeys and must be a domain associated with the app. + +## Gas Sponsorship + +Setting `appId` activates the hosted Stellar relayer, which can sponsor account reserves and fee-bump submission. Sponsorship is pass-through: the relayer is a fee payer and reserve sponsor only. It is not a custodian, cannot see the control key, and cannot move funds. A missing or unavailable relayer can affect fees; it cannot squat the address or authorize transactions. + +```typescript +const wallet = await Cavos.connect({ + chain: "stellar", + network: "testnet", + appSalt: "my-app", + identity, + appId: process.env.NEXT_PUBLIC_CAVOS_APP_ID, +}); +``` + +To have the account pay its own fee: + +- `execute(amount, destination, { sponsored: false })` — options are the third argument +- `invokeContract({ contractId, method, args, opts: { sponsored: false } })` — `opts` sits inside the parameter object + +You can also supply your own funded source (`stellarSourceKeypair`) instead of the hosted relayer. + +## Passkeys and Recovery + +Passkeys enroll devices. They do not sign transactions. On Stellar the device-bound P-256 key unwraps the encrypted Ed25519 control key locally; the control key signs. + +After signup, prompt the user to enroll a passkey so they can approve a new device later without finding one that is already logged in. `PasskeyPrf.enroll()` may omit `secret` when the authenticator does not return a PRF result on create; fall back to `getSecret()` as the React provider does: + +```typescript +import { PasskeyPrf } from "@cavos/kit"; + +if (wallet.chain === "stellar" && wallet.status === "ready") { + const prf = new PasskeyPrf({ rpName: "My App" }); + const { secret } = await prf.enroll({ + userId: user.id, + userName: user.email ?? user.id, + }); + await wallet.enrollPasskey(secret ?? (await prf.getSecret())); +} +``` + +On a new device: + +```typescript +if (wallet.chain === "stellar" && wallet.status === "needs-device-approval") { + const prf = new PasskeyPrf({ rpName: "My App" }); + await wallet.approveThisDeviceWithPasskey(await prf.getSecret()); +} +``` + +The React provider wraps this as `enrollPasskeyDefault()` and `approveDeviceWithPasskey()`. An optional recovery code is a last-resort unlock factor (`setupRecovery` / `approveThisDeviceWithRecovery`). Cavos never sees the code. + +## Best Practices + +1. **Keep `userId` and `appSalt` stable** — both are inputs to the derived address +2. **Gate transactions on `status === "ready"`** — handle `needs-device-approval` instead of creating a new wallet +3. **Enroll a passkey after signup** — it only adds devices; it does not sign +4. **Treat the App ID as public** — do not put operator or treasury secrets in client code +5. **Register callback URLs exactly** in the dashboard (scheme, host, path; no wildcards) +6. **Test React Native on a development build** — Expo Go cannot load the native module; install the Expo native peers, add the config plugin, set `redirectUri` and `rpId`, then rebuild + +## When to Use Cavos + +**Use it when:** +- You want an embedded wallet inside your app (no extension, no seed phrase) +- Users should sign in with Google or Apple +- The control key must be unwrapped only on the device (Cavos cannot see it or move funds) +- You are building for the web (React) and/or React Native +- Optional pass-through gas sponsorship would reduce onboarding friction + +**Consider another approach when:** +- Users already have Stellar wallets they want to connect +- You need hardware wallet support +- You need a wallet-agnostic connect-button that talks to many existing wallets + +## Resources + +- [Website](https://cavos.xyz) +- [Docs](https://docs.cavos.xyz) +- [Live demo](https://demo.cavos.xyz) +- [GitHub](https://github.com/cavos-labs/kit) +- [Twitter/X](https://x.com/cavosxyz) +- [npm — `@cavos/kit`](https://www.npmjs.com/package/@cavos/kit) diff --git a/wallet-integration/comparison.md b/wallet-integration/comparison.md index 33bad5e..689b3ba 100644 --- a/wallet-integration/comparison.md +++ b/wallet-integration/comparison.md @@ -4,17 +4,17 @@ A detailed comparison of wallet integration approaches for Stellar. ## Feature Comparison -| Feature | Freighter | Stellar Wallets Kit | Smart Account Kit | -|---------|-----------|---------------------|-------------------| -| **Installation Required** | Browser extension or mobile app | None (library only) | None | -| **User Authentication** | Extension popup | Wallet-specific | Passkey (biometric) | -| **Mobile Support** | Yes (Freighter Mobile app, via WalletConnect) | Partial (LOBSTR, WalletConnect) | Yes | -| **Gasless Transactions** | No | No | Yes (via Relayer) | -| **Multi-wallet Support** | Freighter only | 15+ wallets | Smart wallets only | -| **Hardware Wallets** | Ledger | Ledger, Trezor | No | -| **Smart Wallet Features** | No | No | Yes (multisig, policies) | -| **Setup Complexity** | Low | Medium | Medium | -| **User Onboarding** | Must install extension | Choose from wallets | Create passkey | +| Feature | Freighter | Stellar Wallets Kit | Smart Account Kit | Cavos | +|---------|-----------|---------------------|-------------------|-------| +| **Installation Required** | Browser extension or mobile app | None (library only) | None | None | +| **User Authentication** | Extension popup | Wallet-specific | Passkey (biometric) | Google or Apple | +| **Mobile Support** | Yes (Freighter Mobile app, via WalletConnect) | Partial (LOBSTR, WalletConnect) | Yes | Yes (React Native) | +| **Gasless Transactions** | No | No | Yes (via Relayer) | Yes (pass-through relayer) | +| **Multi-wallet Support** | Freighter only | 15+ wallets | Smart wallets only | Embedded wallet only | +| **Hardware Wallets** | Ledger | Ledger, Trezor | No | No | +| **Smart Wallet Features** | No | No | Yes (multisig, policies) | Classic `G…` account (device-native) | +| **Setup Complexity** | Low | Medium | Medium | Medium | +| **User Onboarding** | Must install extension | Choose from wallets | Create passkey | Sign in with Google or Apple | ## Integration Complexity @@ -39,29 +39,36 @@ Lines of code: ~50-100 Dependencies: 1 (smart-account-kit) + Relayer setup ``` +### Cavos +``` +Complexity: ⭐⭐ Medium +Lines of code: ~50-100 +Dependencies: 1 (@cavos/kit) on web; React Native also needs Expo native peers (expo-modules-core, expo-web-browser, expo-linking) +``` + ## User Experience Comparison ### New User Onboarding -| Step | Freighter | Stellar Wallets Kit | Smart Account Kit | -|------|-----------|---------------------|-------------------| -| 1 | Install extension | Install extension OR use web wallet | Click "Sign Up" | -| 2 | Create new wallet | Create new wallet | Scan fingerprint/face | -| 3 | Save seed phrase | Save seed phrase | Done! | -| 4 | Fund account | Fund account | (Optional) Fund later | -| 5 | Connect to dapp | Connect to dapp | - | +| Step | Freighter | Stellar Wallets Kit | Smart Account Kit | Cavos | +|------|-----------|---------------------|-------------------|-------| +| 1 | Install extension | Install extension OR use web wallet | Click "Sign Up" | Click "Sign in" | +| 2 | Create new wallet | Create new wallet | Scan fingerprint/face | Google or Apple | +| 3 | Save seed phrase | Save seed phrase | Done! | Done! | +| 4 | Fund account | Fund account | (Optional) Fund later | - | +| 5 | Connect to dapp | Connect to dapp | - | - | -**Winner: Smart Account Kit** (2 steps vs 5) +**Winner: Smart Account Kit or Cavos** (2 steps vs 5) ### Returning User Login -| Step | Freighter | Stellar Wallets Kit | Smart Account Kit | -|------|-----------|---------------------|-------------------| -| 1 | Click "Connect" | Click "Connect" | Click "Sign In" | -| 2 | Approve in extension | Select wallet | Scan fingerprint/face | -| 3 | - | Approve in wallet | Done! | +| Step | Freighter | Stellar Wallets Kit | Smart Account Kit | Cavos | +|------|-----------|---------------------|-------------------|-------| +| 1 | Click "Connect" | Click "Connect" | Click "Sign In" | Click "Sign in" | +| 2 | Approve in extension | Select wallet | Scan fingerprint/face | Google or Apple (returning device is silent) | +| 3 | - | Approve in wallet | Done! | Done! | -**Winner: Smart Account Kit** (2 steps, no popups) +**Winner: Smart Account Kit or Cavos** (2 steps, no wallet popups) ## Transaction Flow @@ -80,6 +87,11 @@ User → Dapp → Selected wallet popup → User approves → Submit to network User → Dapp → Passkey prompt → Submit to Relayer → Relayer pays fee ``` +### Cavos +``` +User → Dapp → Google or Apple → Device P-256 key unwraps control key locally → Ed25519 control key signs → Relayer may sponsor fee +``` + ## Cost Comparison | Approach | User Pays Fees | Developer Pays Fees | @@ -87,6 +99,7 @@ User → Dapp → Passkey prompt → Submit to Relayer → Relayer pays fee | Freighter | Yes | No | | Stellar Wallets Kit | Yes | No | | Smart Account Kit | Optional | Optional (when a relayer is configured) | +| Cavos | Optional | Optional (pass-through relayer when configured) | ## Use Case Recommendations @@ -97,7 +110,7 @@ User → Dapp → Passkey prompt → Submit to Relayer → Relayer pays fee - Users expect to pay their own fees ### Consumer Mobile App -**Recommended:** Smart Account Kit +**Recommended:** Smart Account Kit or Cavos - Users may not have crypto experience - Mobile-first experience needed - Gasless transactions reduce friction @@ -115,7 +128,7 @@ User → Dapp → Passkey prompt → Submit to Relayer → Relayer pays fee - Flexibility for different user types ### Gaming / Social App -**Recommended:** Smart Account Kit +**Recommended:** Smart Account Kit or Cavos - Mass market audience - Users shouldn't need to understand crypto - Fast, seamless transactions @@ -133,6 +146,9 @@ Requires users to create new smart wallets. Consider: ### From Passkey Kit to Smart Account Kit passkey-kit remains a maintained sibling SDK — migrate to Smart Account Kit when you need context rules and policy signers. The APIs and on-chain authorization models differ, so there is no drop-in upgrade path. +### Adding Cavos +Cavos provisions a new embedded classic account from Google or Apple login. It does not wrap existing extension wallets. Consider running it alongside an existing-wallet option during transition. + ## Decision Flowchart ``` @@ -151,15 +167,19 @@ Are your users crypto-native? │ │ │ └─ No → Stellar Wallets Kit │ - └─ No → Is mobile support important? + └─ No → Should users sign in with Google or Apple? │ - ├─ Yes → Smart Account Kit + ├─ Yes → Cavos │ - └─ No → Do you want gasless transactions? + └─ No → Is mobile support important? │ ├─ Yes → Smart Account Kit │ - └─ No → Consider your UX priorities + └─ No → Do you want gasless transactions? + │ + ├─ Yes → Smart Account Kit + │ + └─ No → Consider your UX priorities ``` ## Summary @@ -169,3 +189,4 @@ Are your users crypto-native? | **Freighter** | Quick prototypes, developer tools | Broad multi-wallet user base | | **Stellar Wallets Kit** | DeFi, existing crypto users | Non-crypto users, mobile-first | | **Smart Account Kit** | Consumer apps, best UX | Hardware wallet requirement | +| **Cavos** | Embedded self-custodial SDK, Google/Apple login | Existing wallets or hardware wallets |