cavos-react-sdk
npx skills add https://github.com/cavos-labs/cavos-skills --skill cavos-react-sdk
Agent 安装分布
Skill 文档
Cavos React SDK â AI Agent Skill
Complete architectural knowledge and implementation patterns for
@cavos/react. This skill enables AI agents to correctly integrate, extend, and debug the Cavos SDK.
1. What is Cavos?
Cavos is a non-custodial account abstraction SDK for Starknet. It lets users create smart wallets using their existing OAuth identity (Google, Apple, Firebase email/password) â no seed phrases, no browser extensions.
Key Principles
- Non-custodial: The user’s wallet is derived deterministically from their OAuth
subclaim + a per-app salt. No one holds the keys. - Gasless by default: All transactions go through the AVNU paymaster (SNIP-9 Outside Execution).
- Session keys: Ephemeral ECDSA keys that sign transactions on behalf of the user, with configurable spending limits and contract restrictions.
2. Architecture Overview
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â React App â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââ â
â â <CavosProvider config={...}> â â
â â useCavos() â { login, execute, address, ... } â â
â âââââââââââââââââââââââââââââââââââââââââââââââââââââ â
â â â
â âââââââ´ââââââ â
â â CavosSDK â â
â âââââââ¬ââââââ â
â âââââââââââââââââ¼ââââââââââââââââ â
â ââââââââ´ââââââââ ââââââ´âââââââ ââââââââ´âââââââ â
â â OAuthWallet â â Session â â Transaction â â
â â Manager â â Manager â â Manager â â
â ââââââââââââââââ âââââââââââââ âââââââââââââââ â
â Identity & Key AVNU Paymaster â
â JWT handling lifecycle & SNIP-9 execution â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
âââââââ´ââââââ
â Starknet â
â Contract â
â (Cairo) â
âââââââââââââ
cavos.cairo
Three Layers
| Layer | Class | Responsibility |
|---|---|---|
| Identity | OAuthWalletManager |
OAuth login, JWT parsing, nonce computation, address derivation, session key generation, JWT signature building |
| Session | SessionManager |
Session key storage, expiration tracking, renewal detection |
| Execution | OAuthTransactionManager |
Account deployment, transaction execution (JWT vs session signature), session registration, renewal, revocation |
3. Configuration Reference
CavosConfig (Required)
interface CavosConfig {
appId: string; // From https://cavos.xyz/dashboard
backendUrl?: string; // Default: 'https://cavos.xyz'
starknetRpcUrl?: string; // Custom RPC (optional)
network?: 'mainnet' | 'sepolia'; // Default: 'sepolia'
paymasterApiKey?: string; // AVNU key (optional, shared key used if omitted)
enableLogging?: boolean; // Debug logs (default: false)
oauthWallet?: Partial<OAuthWalletConfig>; // Advanced: custom class hash, registry
session?: SessionConfig; // Session duration & default policy
}
SessionConfig
interface SessionConfig {
sessionDuration?: number; // Seconds (default: 86400 = 24h)
renewalGracePeriod?: number; // Seconds (default: 172800 = 48h)
defaultPolicy?: SessionKeyPolicy; // Applied to all sessions
}
SessionKeyPolicy â ï¸ Critical Type
interface SessionKeyPolicy {
spendingLimits: Array<{
token: string; // Contract address of the ERC-20 token
limit: bigint; // Maximum amount (in wei, use BigInt!)
}>;
allowedContracts: string[]; // Only these contracts can be called
maxCallsPerTx: number; // Max calls per multicall
}
[!CAUTION]
limitMUST be abigint(e.g.,BigInt(10 * 10**18)for 10 tokens with 18 decimals). Usingnumberwill silently truncate large values.
4. Complete API Reference
4.1 useCavos() Hook (Primary Interface)
This is what 99% of integrations should use:
const {
// --- State ---
isAuthenticated, // boolean
user, // UserInfo | null â { id, email, name, picture? }
address, // string | null â '0x...' Starknet address
hasActiveSession, // boolean
isLoading, // boolean â true during init/login
walletStatus, // WalletStatus â { isDeploying, isDeployed, isRegistering, isSessionActive, isReady }
// --- Auth ---
login, // (provider: 'google'|'apple'|'firebase', creds?) => Promise<void>
register, // (provider, { email, password }) => Promise<void> (Firebase only)
logout, // () => Promise<void>
// --- Transactions ---
execute, // (calls: Call | Call[]) => Promise<string> â returns tx hash
signMessage, // (typedData: TypedData) => Promise<Signature> (SNIP-12)
// --- Session Management ---
registerCurrentSession, // () => Promise<string> â explicit on-chain registration
updateSessionPolicy, // (policy: SessionKeyPolicy) => void â MUST call before register!
renewSession, // () => Promise<string>
revokeSession, // (sessionKey: string) => Promise<string>
emergencyRevokeAllSessions, // () => Promise<string> â nuclear option
exportSession, // () => string â base64 token for CLI
// --- Account ---
isAccountDeployed, // () => Promise<boolean>
deployAccount, // () => Promise<string>
getBalance, // () => Promise<string> â ETH balance as string
// --- Multi-Wallet ---
getAssociatedWallets, // () => Promise<{ address: string; name?: string }[]>
switchWallet, // (name?: string) => Promise<void>
// --- Utilities ---
getOnramp, // (provider: 'RAMP_NETWORK') => string â fiat onramp URL
resendVerificationEmail, // (email: string) => Promise<void>
// --- Raw SDK (Advanced) ---
cavos, // CavosSDK instance for direct access
} = useCavos();
4.2 Login Providers
| Provider | Method | Notes |
|---|---|---|
'google' |
login('google') |
Redirects to Google OAuth. Address derived from Google sub. |
'apple' |
login('apple') |
Redirects to Apple OAuth. Address derived from Apple sub. |
'firebase' |
login('firebase', { email, password }) |
Email/password via Firebase. Must register() first. |
5. Critical Flows & Rules
5.1 The Policy Synchronization Rule
[!IMPORTANT] ALWAYS call
updateSessionPolicy(policy)BEFOREregisterCurrentSession().
Why: The session policy is captured at login time. If the user changes their spending limits in the UI after login but before registration, the stale (possibly empty) policy gets stored on-chain.
What happens if you don’t: The contract sees policy_count == 0 and skips all spending limit checks, allowing unlimited transfers.
// â
CORRECT
const activate = async () => {
updateSessionPolicy(latestPolicy); // Sync first!
await registerCurrentSession(); // Then register
};
// â WRONG â stale policy gets registered
const activate = async () => {
await registerCurrentSession(); // Uses policy from login time!
};
See: Policy Synchronization Deep Dive
5.2 Transaction Execution Flow
execute(calls)
â
ââ Session NOT registered?
â ââ Uses JWT signature (OAUTH_JWT_V1)
â â Registers session + executes in ONE atomic tx
â â Expensive (RSA verification on-chain)
â
ââ Session registered & active?
â ââ Uses session signature (SESSION_V1)
â â Lightweight, fast
â
ââ Session expired but within grace period?
â ââ Auto-renews session, then executes
â
ââ Session expired beyond grace period?
ââ Throws error â user must re-login
5.3 Account Deployment
Accounts are deployed lazily â on the first execute() call or explicitly via deployAccount().
- Uses AVNU Paymaster for gasless self-deployment.
- The contract’s
__validate_deploy__verifies the JWT and registers the session key simultaneously. - No relayer needed â fully self-custodial.
5.4 Address Derivation
The wallet address is deterministic and derived from:
address = Poseidon(sub, salt, walletName?)
sub: OAuth subject claim (unique per user per provider)salt: Per-app salt fetched from the Cavos backendwalletName: Optional name for sub-accounts (default: unnamed)
5.5 Session Renewal
Sessions have two time boundaries:
valid_until: When the session expires (default: 24h after registration)renewal_deadline: Grace period window (default: 48h after expiry)
Between valid_until and renewal_deadline, the old session key can sign a renewal request for a new session key, without needing a new JWT.
5.6 Session Revocation
Two levels of revocation:
revokeSession(pubKey): Invalidates one specific session key. Requires JWT.emergencyRevokeAllSessions(): Increments the on-chainrevocation_epoch, invalidating ALL sessions. Nuclear option.
6. Common Patterns
Minimal Integration (5 lines)
import { CavosProvider, useCavos } from '@cavos/react';
// In your layout:
<CavosProvider config={{ appId: 'YOUR_APP_ID', network: 'sepolia' }}>
<App />
</CavosProvider>
// In your component:
function App() {
const { login, execute, address, isAuthenticated } = useCavos();
if (!isAuthenticated) return <button onClick={() => login('google')}>Login</button>;
return <p>Wallet: {address}</p>;
}
Execute a Token Transfer
const tx = await execute({
contractAddress: '0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d', // STRK
entrypoint: 'transfer',
calldata: [recipientAddress, amountLow, amountHigh] // uint256 = [low, high]
});
Multi-Call (Approve + Swap)
const tx = await execute([
{
contractAddress: TOKEN_ADDRESS,
entrypoint: 'approve',
calldata: [ROUTER_ADDRESS, amountLow, amountHigh]
},
{
contractAddress: ROUTER_ADDRESS,
entrypoint: 'swap',
calldata: [...]
}
]);
Export Session to CLI
const token = exportSession();
// User runs: cavos session import <token>
7. Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
| “Spending limit exceeded” | BigInt conversion error â wrong decimals | Verify limit: BigInt(amount * 10**decimals) |
| Transfer goes through despite limit | policy_count == 0 on-chain |
Call updateSessionPolicy() before registerCurrentSession() |
| “Address seed mismatch” | Different sub or salt between login and verification |
Ensure appSalt is fetched correctly from backend |
| “SESSION_EXPIRED” | Session older than valid_until |
Call renewSession() if within grace period, else re-login |
| “Claim mismatch after decoding” | JWT kid rotation or issuer mismatch | Check JWKS registry is up to date |
| Account not deploying | No ETH/STRK for gas | Use paymaster (default) or fund the counterfactual address |
useCavos throws “must be used within CavosProvider” |
Component is outside the provider tree | Wrap your app in <CavosProvider> |
8. Token Addresses (Starknet)
| Token | Mainnet | Sepolia |
|---|---|---|
| ETH | 0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7 |
Same |
| STRK | 0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d |
Same |
| USDC | 0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8 |
â |
| USDT | 0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8 |
â |
9. File Map (SDK Source)
When modifying the SDK, here’s where things live:
| File | Purpose |
|---|---|
src/CavosSDK.ts |
Main orchestrator â all public methods |
src/react/CavosContext.tsx |
React provider & useCavos() hook |
src/oauth/OAuthWalletManager.ts |
Identity, JWT, session keys, signatures |
src/oauth/OAuthTransactionManager.ts |
Deployment, execution, renewal, revocation |
src/oauth/AddressSeedManager.ts |
Deterministic address computation |
src/oauth/NonceManager.ts |
Session nonce for JWT binding |
src/types/config.ts |
CavosConfig, SessionConfig, OAuthWalletConfig |
src/types/session.ts |
SessionKeyPolicy, SessionData |
src/types/auth.ts |
UserInfo, LoginProvider, FirebaseCredentials |
src/paymaster/PaymasterIntegration.ts |
AVNU paymaster wrapper |
src/config/defaults.ts |
Network-specific defaults (class hashes, registry addresses) |
10. Coding Rules for AI Agents
- Never expose private keys â use the managers, not raw crypto.
- Always sync policy before registration â see Section 5.1.
- When adding SDK methods: Expose in
CavosSDK.tsâCavosContext.tsxâ updateCavosContextValueinterface. - uint256 in calldata is always
[low, high]â two felts. - After SDK changes: Run
npm run buildinreact/, then copydist/to consumer’snode_modules/@cavos/react/dist/. - Session storage is
sessionStorage(cleared on tab close) â this is intentional for security. - Wallet names are currently stored in
localStorage(cavos_seen_wallets_${appId}_${sub}) â not persistent across devices.
For detailed reference documents, see the references/ directory. For runnable code examples, see the scripts/ directory.