@cavos/kit 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -42
- package/dist/Cavos-BH2_tOQ2.d.mts +994 -0
- package/dist/Cavos-BH2_tOQ2.d.ts +994 -0
- package/dist/chunk-BNGLH3Q3.mjs +2777 -0
- package/dist/chunk-BNGLH3Q3.mjs.map +1 -0
- package/dist/index.d.mts +156 -242
- package/dist/index.d.ts +156 -242
- package/dist/index.js +1989 -151
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +88 -2
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +42 -5
- package/dist/react/index.d.ts +42 -5
- package/dist/react/index.js +1786 -86
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +48 -7
- package/dist/react/index.mjs.map +1 -1
- package/package.json +4 -1
- package/dist/chunk-XWBX2ZIO.mjs +0 -1061
- package/dist/chunk-XWBX2ZIO.mjs.map +0 -1
- package/dist/constants-C530TZFF.d.mts +0 -89
- package/dist/constants-C530TZFF.d.ts +0 -89
package/README.md
CHANGED
|
@@ -6,8 +6,10 @@ secp256r1 (P-256) keys that live on the device and sign **invisibly** (no passke
|
|
|
6
6
|
no Face ID / Touch ID, no popups). OAuth / email is used only to derive the
|
|
7
7
|
address, never to sign. No exported keys, no MPC, no on-chain JWT/RSA.
|
|
8
8
|
|
|
9
|
-
**
|
|
10
|
-
|
|
9
|
+
**Chains:** **Starknet** and **Solana** are implemented today, behind a single
|
|
10
|
+
unified `Cavos.connect({ chain, network })` entry point. The API is
|
|
11
|
+
chain-configurable by design — Stellar (and others) will slot in behind the same
|
|
12
|
+
`ChainAdapter` interface.
|
|
11
13
|
|
|
12
14
|
> New package. Does **not** replace `@cavos/react` / `react-native` (legacy
|
|
13
15
|
> OAuth/session-key SDKs), which continue on the old flow.
|
|
@@ -22,45 +24,94 @@ npm install @cavos/kit
|
|
|
22
24
|
|
|
23
25
|
| Piece | Role |
|
|
24
26
|
|-------|------|
|
|
25
|
-
| `
|
|
26
|
-
| `
|
|
27
|
+
| `Cavos.connect` | Unified entry point: log in → derive deterministic address → create/load device key → auto-deploy → ready, gas-sponsored wallet. |
|
|
28
|
+
| `deriveAddressSeed` / `deriveAddressSeedSolana` | Stable `address_seed` from `{ userId, appSalt }`. Identity → wallet, device-independent. |
|
|
29
|
+
| `StarknetAdapter` / `SolanaAdapter` | Per-chain: compute the deterministic address, build deploy/initialize/add/remove calls, serialize signatures. |
|
|
27
30
|
| `WebCryptoSigner` | Browser silent device signer: non-extractable P-256 key in IndexedDB, no UI on sign. |
|
|
28
|
-
| `StarknetDeviceSigner` | Drop-in starknet.js `SignerInterface` backed by a device signer. |
|
|
29
|
-
| `
|
|
30
|
-
| `RecoveryClient` | Interface to the (non-custodial) backend for the email-approval multi-device flow. |
|
|
31
|
+
| `StarknetDeviceSigner` | Drop-in starknet.js `SignerInterface` backed by a device signer (advanced). |
|
|
32
|
+
| `SolanaRelayer` | Cavos gasless sponsor for Solana: co-signs as fee payer so the integrator holds no keypair. |
|
|
33
|
+
| `RecoveryClient` | Interface to the (non-custodial) backend for the email-approval multi-device flow (Starknet). |
|
|
31
34
|
|
|
32
|
-
## Quickstart —
|
|
35
|
+
## Quickstart — Starknet
|
|
33
36
|
|
|
34
37
|
One call logs the user in and returns a ready, deployed, gas-sponsored smart
|
|
35
38
|
account controlled by a silent device key. The user only sees the login.
|
|
36
39
|
|
|
37
40
|
```ts
|
|
38
|
-
import { Cavos, StaticIdentity
|
|
41
|
+
import { Cavos, StaticIdentity } from "@cavos/kit";
|
|
39
42
|
|
|
40
|
-
const
|
|
41
|
-
|
|
43
|
+
const wallet = await Cavos.connect({
|
|
44
|
+
chain: "starknet",
|
|
45
|
+
network: "testnet", // "testnet" (sepolia) | "mainnet"
|
|
42
46
|
appSalt: "my-app",
|
|
43
|
-
// Identity from your login (
|
|
47
|
+
// Identity from your login (use CavosAuth for hosted Google/Apple/email, or
|
|
48
|
+
// wrap your own userId with StaticIdentity)
|
|
44
49
|
auth: new StaticIdentity({ userId: user.id, email: user.email }),
|
|
45
|
-
//
|
|
46
|
-
|
|
50
|
+
appId: process.env.NEXT_PUBLIC_CAVOS_APP_ID, // hosted registry + recovery
|
|
51
|
+
paymasterApiKey: process.env.CAVOS_PAYMASTER_API_KEY!, // gas sponsor
|
|
47
52
|
});
|
|
48
53
|
|
|
49
|
-
console.log(
|
|
50
|
-
|
|
54
|
+
console.log(wallet.address); // deterministic; auto-deployed on first connect
|
|
55
|
+
|
|
56
|
+
if (wallet.chain === "starknet" && wallet.status === "ready") {
|
|
57
|
+
await wallet.execute(calls); // gasless; signed invisibly by the device key
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`wallet` is a discriminated union (`Cavos | CavosSolana`); narrow on
|
|
62
|
+
`wallet.chain` before calling `execute`, since its signature differs per chain.
|
|
63
|
+
|
|
64
|
+
## Quickstart — Solana
|
|
65
|
+
|
|
66
|
+
Same unified entry point; pass `chain: "solana"`. Gas is sponsored by the Cavos
|
|
67
|
+
relayer (activated by `appId`) — no `paymasterApiKey` and no fee-payer keypair
|
|
68
|
+
needed.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { Cavos, StaticIdentity } from "@cavos/kit";
|
|
72
|
+
|
|
73
|
+
const wallet = await Cavos.connect({
|
|
74
|
+
chain: "solana",
|
|
75
|
+
network: "testnet", // -> solana-devnet ("mainnet" -> solana-mainnet)
|
|
76
|
+
appSalt: "my-app",
|
|
77
|
+
auth: new StaticIdentity({ userId: user.id, email: user.email }),
|
|
78
|
+
appId: process.env.NEXT_PUBLIC_CAVOS_APP_ID, // activates the gasless relayer
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
if (wallet.chain === "solana" && wallet.status === "ready") {
|
|
82
|
+
const signature = await wallet.execute(1_000_000n, recipient); // lamports, base58 dest
|
|
83
|
+
console.log(signature);
|
|
84
|
+
}
|
|
51
85
|
```
|
|
52
86
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
> path below is proven on-chain today.
|
|
87
|
+
On Solana every guarded action (initialize, add/remove signer, execute) is a
|
|
88
|
+
two-instruction bundle pairing Solana's **native secp256r1 precompile** with the
|
|
89
|
+
Cavos `cavos-device-account` program instruction. The address is a deterministic
|
|
90
|
+
PDA derived from `deriveAddressSeedSolana` (`{ userId, appSalt }`).
|
|
58
91
|
|
|
59
|
-
|
|
92
|
+
```ts
|
|
93
|
+
// Arbitrary program calls (SPL transfers, swaps, staking):
|
|
94
|
+
import type { InstructionData } from "@cavos/kit";
|
|
95
|
+
|
|
96
|
+
if (wallet.chain === "solana" && wallet.status === "ready") {
|
|
97
|
+
const instructions: InstructionData[] = [/* … SPL/swap instructions … */];
|
|
98
|
+
await wallet.executeInstructions(instructions); // CPIs run with the PDA signing
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
> **Note:** `execute(amount, destination)` moves **lamports** (SOL); use
|
|
103
|
+
> `executeInstructions(instructions)` for arbitrary program calls. Sponsored
|
|
104
|
+
> `executeInstructions` is gated by the app's Solana program allowlist (dashboard
|
|
105
|
+
> → Solana Programs); targets outside the allowlist + safe set are rejected.
|
|
106
|
+
|
|
107
|
+
## Quickstart — low-level (Starknet, advanced)
|
|
108
|
+
|
|
109
|
+
If you want to drive the pieces yourself (own paymaster, custom deploy), use the
|
|
110
|
+
adapter + signer directly instead of `Cavos.connect`:
|
|
60
111
|
|
|
61
112
|
```ts
|
|
62
113
|
import {
|
|
63
|
-
|
|
114
|
+
StarknetAdapter, WebCryptoSigner,
|
|
64
115
|
deriveAddressSeed, DEVICE_ACCOUNT_CLASS_HASH,
|
|
65
116
|
} from "@cavos/kit";
|
|
66
117
|
|
|
@@ -75,47 +126,46 @@ const address = new StarknetAdapter({ classHash }).computeAddress({
|
|
|
75
126
|
// 2. Create/load the SILENT device key (keyed by the address). No prompt, ever.
|
|
76
127
|
const signer = await WebCryptoSigner.loadOrCreate({ keyId: address });
|
|
77
128
|
|
|
78
|
-
// 3. Build
|
|
79
|
-
|
|
80
|
-
const account = new CavosAccount({ identity, adapter, signer });
|
|
81
|
-
console.log(account.address); // deterministic, pre-deploy
|
|
82
|
-
|
|
83
|
-
// 4. Onboarding: deploy + register first signer (route through your paymaster).
|
|
84
|
-
const calls = await account.buildOnboarding(); // [UDC deploy, initialize] — submit atomically
|
|
85
|
-
|
|
86
|
-
// 5. Add another device later (must be self-submitted by an existing signer).
|
|
87
|
-
const addCall = account.buildAddSigner(otherDevicePublicKey);
|
|
88
|
-
|
|
89
|
-
// 6. Submit transactions through a standard starknet.js Account.
|
|
129
|
+
// 3. Build deploy/initialize/add/remove calls, then submit through your own
|
|
130
|
+
// paymaster. Route signing through a standard starknet.js Account:
|
|
90
131
|
import { Account, RpcProvider } from "starknet";
|
|
91
132
|
import { StarknetDeviceSigner } from "@cavos/kit";
|
|
92
133
|
|
|
93
134
|
const provider = new RpcProvider({ nodeUrl: "https://api.cartridge.gg/x/starknet/sepolia" });
|
|
94
|
-
const snAccount = new Account(provider,
|
|
135
|
+
const snAccount = new Account(provider, address, new StarknetDeviceSigner(signer), "1");
|
|
95
136
|
await snAccount.execute(someCalls); // signed silently; DeviceAccount validates on-chain
|
|
96
137
|
```
|
|
97
138
|
|
|
98
139
|
`StarknetDeviceSigner` is a drop-in starknet.js `SignerInterface`, so it also
|
|
99
140
|
plugs into paymaster SDKs (AVNU) for gasless flows. The kit does **not** own gas
|
|
100
|
-
sponsorship — route execution through your paymaster of
|
|
141
|
+
sponsorship in the low-level path — route execution through your paymaster of
|
|
142
|
+
choice.
|
|
101
143
|
|
|
102
144
|
## How signing works
|
|
103
145
|
|
|
104
|
-
|
|
105
|
-
ECDSA hashes the message internally). The signature is serialized
|
|
106
|
-
`[r_low, r_high, s_low, s_high, y_parity]` — exactly what
|
|
146
|
+
On **Starknet**, the device key signs `sha256(tx_hash)` with no user interaction
|
|
147
|
+
(WebCrypto's ECDSA hashes the message internally). The signature is serialized
|
|
148
|
+
as `[r_low, r_high, s_low, s_high, y_parity]` — exactly what
|
|
107
149
|
`DeviceAccount.__validate__` decodes. The contract recomputes `sha256(tx_hash)`,
|
|
108
150
|
normalizes high-s, and recovers the secp256r1 signer. This 5-felt encoding is
|
|
109
151
|
covered by a cross-checked contract test (`test_sdk_signature_payload_authorized`
|
|
110
152
|
in `account-contracts/starknet`).
|
|
111
153
|
|
|
154
|
+
On **Solana**, each guarded action pairs the native `Secp256r1SigVerify`
|
|
155
|
+
precompile (which records the device's P-256 signature of a domain-separated
|
|
156
|
+
message) with the Cavos program instruction that consumes it. The fee payer is
|
|
157
|
+
not bound by the device signature, so the relayer co-signs without re-authorizing
|
|
158
|
+
the action.
|
|
159
|
+
|
|
112
160
|
**Security model:** the private key is non-extractable (never visible to JS) and
|
|
113
161
|
device-bound — non-custodial, no MPC, verified on-chain. Because signing is
|
|
114
162
|
silent there is no per-signature user-verification gate (unlike a biometric
|
|
115
163
|
passkey); this is the standard embedded-wallet trade-off. Multi-device + the
|
|
116
164
|
non-custodial recovery relay cover device loss.
|
|
117
165
|
|
|
118
|
-
## Status
|
|
166
|
+
## Status
|
|
167
|
+
|
|
168
|
+
### Starknet
|
|
119
169
|
|
|
120
170
|
- ✅ Silent secp256r1 device signer (`WebCryptoSigner`) + 5-felt signature
|
|
121
171
|
serialization, cross-checked against the live contract.
|
|
@@ -124,7 +174,6 @@ non-custodial recovery relay cover device loss.
|
|
|
124
174
|
- ✅ **Proven on-chain (Sepolia):** silent device key signs a real STRK `approve`,
|
|
125
175
|
the deployed DeviceAccount validates it ([tx](https://sepolia.starkscan.co/tx/0x51e0e961ee535bf3c45ea020b9c258aee544ed18aea57dbbc80767f8e86ab9e)).
|
|
126
176
|
- ✅ `Cavos.connect` orchestration: auth → device key → address → auto-deploy → execute.
|
|
127
|
-
- ✅ `CavosPaymaster` client + `Sponsor` interface (Cavos-hosted gasless).
|
|
128
177
|
- ✅ **Gasless proven on-chain (Sepolia):** relayer-paid `execute_from_outside_v2`,
|
|
129
178
|
authorized solely by the silent device signature, executed a real STRK approve
|
|
130
179
|
([tx](https://sepolia.starkscan.co/tx/0x05ade4008f4ccbcfe4a7f016c61eb0eb591c8f696db3f5dad6f0db3ea3b5d2e6)).
|
|
@@ -132,7 +181,29 @@ non-custodial recovery relay cover device loss.
|
|
|
132
181
|
- ✅ `CavosAuth` (hosted Google/Apple/email/OTP login, mirroring `@cavos/react`).
|
|
133
182
|
- ✅ Recovery client interface (non-custodial multi-device email-approval flow).
|
|
134
183
|
- 🚧 Cavos paymaster backend must register the new class hash (backend, out of repo).
|
|
184
|
+
|
|
185
|
+
### Solana
|
|
186
|
+
|
|
187
|
+
- ✅ `SolanaAdapter` — PDA derivation, the `[secp256r1 precompile, program]`
|
|
188
|
+
instruction builders, low-S normalization, anchor discriminators.
|
|
189
|
+
- ✅ `CavosSolana` high-level client — `connect`, `execute(amount, destination)`,
|
|
190
|
+
`executeInstructions(instructions)`, `addSigner`, `setupRecovery`, static
|
|
191
|
+
`recover`; gasless by default via the relayer when `appId` is set.
|
|
192
|
+
- ✅ `executeInstructions` arbitrary CPI — the device key signs over a hash of the
|
|
193
|
+
instruction set; the on-chain `execute` instruction invokes the CPIs with the
|
|
194
|
+
PDA signing. Sponsored calls are gated by the app's program allowlist.
|
|
195
|
+
- ✅ `SolanaRelayer` — co-signs as fee payer for seedless/gasless execution
|
|
196
|
+
(integrator holds no fee-payer keypair); self-funded `feePayer` fallback.
|
|
197
|
+
- ✅ Unit tests + end-to-end scripts (`scripts/solana_e2e.ts`,
|
|
198
|
+
`scripts/solana_relayer_e2e.ts`).
|
|
199
|
+
- ✅ Recovery (`setupRecovery` / `recover`) — same self-custodial model as Starknet.
|
|
200
|
+
|
|
201
|
+
### Cross-chain / next
|
|
202
|
+
|
|
203
|
+
- ✅ Unified `Cavos.connect({ chain, network })` dispatcher with a `CavosWallet`
|
|
204
|
+
discriminated union.
|
|
135
205
|
- 🚧 Recovery backend service + session keys (Phase 2).
|
|
206
|
+
- 🚧 Stellar adapter (planned).
|
|
136
207
|
|
|
137
208
|
## Demo
|
|
138
209
|
|