@cavos/kit 0.0.1
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 +151 -0
- package/dist/chunk-XWBX2ZIO.mjs +1061 -0
- package/dist/chunk-XWBX2ZIO.mjs.map +1 -0
- package/dist/constants-C530TZFF.d.mts +89 -0
- package/dist/constants-C530TZFF.d.ts +89 -0
- package/dist/index.d.mts +529 -0
- package/dist/index.d.ts +529 -0
- package/dist/index.js +1103 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +15 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react/index.d.mts +140 -0
- package/dist/react/index.d.ts +140 -0
- package/dist/react/index.js +2055 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/index.mjs +999 -0
- package/dist/react/index.mjs.map +1 -0
- package/package.json +77 -0
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# @cavos/kit
|
|
2
|
+
|
|
3
|
+
Device-native, verifiable smart accounts. Users get a deterministic wallet bound
|
|
4
|
+
to their identity, controlled by **silent device signers** — non-extractable
|
|
5
|
+
secp256r1 (P-256) keys that live on the device and sign **invisibly** (no passkey,
|
|
6
|
+
no Face ID / Touch ID, no popups). OAuth / email is used only to derive the
|
|
7
|
+
address, never to sign. No exported keys, no MPC, no on-chain JWT/RSA.
|
|
8
|
+
|
|
9
|
+
**Phase 1: Starknet only.** The API is chain-configurable by design so Stellar
|
|
10
|
+
and Solana adapters slot in behind the same `ChainAdapter` interface later.
|
|
11
|
+
|
|
12
|
+
> New package. Does **not** replace `@cavos/react` / `react-native` (legacy
|
|
13
|
+
> OAuth/session-key SDKs), which continue on the old flow.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @cavos/kit
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Concepts
|
|
22
|
+
|
|
23
|
+
| Piece | Role |
|
|
24
|
+
|-------|------|
|
|
25
|
+
| `deriveAddressSeed` | Stable `address_seed` from `{ userId, appSalt }`. Identity → wallet, device-independent. |
|
|
26
|
+
| `StarknetAdapter` | Computes the deterministic address, builds deploy/initialize/add/remove calls, serializes signatures. |
|
|
27
|
+
| `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
|
+
| `CavosAccount` | High-level facade tying identity + adapter + signer together. |
|
|
30
|
+
| `RecoveryClient` | Interface to the (non-custodial) backend for the email-approval multi-device flow. |
|
|
31
|
+
|
|
32
|
+
## Quickstart — high-level (Privy-like)
|
|
33
|
+
|
|
34
|
+
One call logs the user in and returns a ready, deployed, gas-sponsored smart
|
|
35
|
+
account controlled by a silent device key. The user only sees the login.
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { Cavos, StaticIdentity, CavosPaymaster } from "@cavos/kit";
|
|
39
|
+
|
|
40
|
+
const cavos = await Cavos.connect({
|
|
41
|
+
network: "sepolia",
|
|
42
|
+
appSalt: "my-app",
|
|
43
|
+
// Identity from your login (Cavos-hosted auth lands here; or pass your own userId)
|
|
44
|
+
auth: new StaticIdentity({ userId: user.id, email: user.email }),
|
|
45
|
+
// Gas sponsor — deploy + execute are gasless
|
|
46
|
+
sponsor: new CavosPaymaster({ network: "sepolia", apiKey: process.env.CAVOS_API_KEY! }),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
console.log(cavos.address); // deterministic; auto-deployed on first connect
|
|
50
|
+
await cavos.execute(calls); // gasless; signed invisibly by the device key
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
> **Status:** `Cavos.connect` orchestration (auth → device key → address →
|
|
54
|
+
> auto-deploy → execute) is built. Fully-gasless execution needs the contract to
|
|
55
|
+
> add SNIP-6 `is_valid_signature` + SNIP-9 `execute_from_outside_v2` (tracked
|
|
56
|
+
> follow-up) and the Cavos paymaster to support the new class. The self-funded
|
|
57
|
+
> path below is proven on-chain today.
|
|
58
|
+
|
|
59
|
+
## Quickstart — low-level (Starknet)
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import {
|
|
63
|
+
CavosAccount, StarknetAdapter, WebCryptoSigner,
|
|
64
|
+
deriveAddressSeed, DEVICE_ACCOUNT_CLASS_HASH,
|
|
65
|
+
} from "@cavos/kit";
|
|
66
|
+
|
|
67
|
+
// 1. Identity (from your OAuth/email login) derives the address. No device key
|
|
68
|
+
// needed for this — the address depends only on identity + salt.
|
|
69
|
+
const identity = { userId: user.id, appSalt: "my-app" };
|
|
70
|
+
const classHash = DEVICE_ACCOUNT_CLASS_HASH.sepolia; // from deployments/sepolia.json
|
|
71
|
+
const address = new StarknetAdapter({ classHash }).computeAddress({
|
|
72
|
+
addressSeed: deriveAddressSeed(identity),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// 2. Create/load the SILENT device key (keyed by the address). No prompt, ever.
|
|
76
|
+
const signer = await WebCryptoSigner.loadOrCreate({ keyId: address });
|
|
77
|
+
|
|
78
|
+
// 3. Build the account.
|
|
79
|
+
const adapter = new StarknetAdapter({ classHash, signer });
|
|
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.
|
|
90
|
+
import { Account, RpcProvider } from "starknet";
|
|
91
|
+
import { StarknetDeviceSigner } from "@cavos/kit";
|
|
92
|
+
|
|
93
|
+
const provider = new RpcProvider({ nodeUrl: "https://api.cartridge.gg/x/starknet/sepolia" });
|
|
94
|
+
const snAccount = new Account(provider, account.address, new StarknetDeviceSigner(signer), "1");
|
|
95
|
+
await snAccount.execute(someCalls); // signed silently; DeviceAccount validates on-chain
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`StarknetDeviceSigner` is a drop-in starknet.js `SignerInterface`, so it also
|
|
99
|
+
plugs into paymaster SDKs (AVNU) for gasless flows. The kit does **not** own gas
|
|
100
|
+
sponsorship — route execution through your paymaster of choice.
|
|
101
|
+
|
|
102
|
+
## How signing works
|
|
103
|
+
|
|
104
|
+
The device key signs `sha256(tx_hash)` with no user interaction (WebCrypto's
|
|
105
|
+
ECDSA hashes the message internally). The signature is serialized as
|
|
106
|
+
`[r_low, r_high, s_low, s_high, y_parity]` — exactly what
|
|
107
|
+
`DeviceAccount.__validate__` decodes. The contract recomputes `sha256(tx_hash)`,
|
|
108
|
+
normalizes high-s, and recovers the secp256r1 signer. This 5-felt encoding is
|
|
109
|
+
covered by a cross-checked contract test (`test_sdk_signature_payload_authorized`
|
|
110
|
+
in `account-contracts/starknet`).
|
|
111
|
+
|
|
112
|
+
**Security model:** the private key is non-extractable (never visible to JS) and
|
|
113
|
+
device-bound — non-custodial, no MPC, verified on-chain. Because signing is
|
|
114
|
+
silent there is no per-signature user-verification gate (unlike a biometric
|
|
115
|
+
passkey); this is the standard embedded-wallet trade-off. Multi-device + the
|
|
116
|
+
non-custodial recovery relay cover device loss.
|
|
117
|
+
|
|
118
|
+
## Status (Phase 1)
|
|
119
|
+
|
|
120
|
+
- ✅ Silent secp256r1 device signer (`WebCryptoSigner`) + 5-felt signature
|
|
121
|
+
serialization, cross-checked against the live contract.
|
|
122
|
+
- ✅ Deterministic address, deploy/initialize/add/remove call builders.
|
|
123
|
+
- ✅ `starknet.js` `Account` integration via `StarknetDeviceSigner`.
|
|
124
|
+
- ✅ **Proven on-chain (Sepolia):** silent device key signs a real STRK `approve`,
|
|
125
|
+
the deployed DeviceAccount validates it ([tx](https://sepolia.starkscan.co/tx/0x51e0e961ee535bf3c45ea020b9c258aee544ed18aea57dbbc80767f8e86ab9e)).
|
|
126
|
+
- ✅ `Cavos.connect` orchestration: auth → device key → address → auto-deploy → execute.
|
|
127
|
+
- ✅ `CavosPaymaster` client + `Sponsor` interface (Cavos-hosted gasless).
|
|
128
|
+
- ✅ **Gasless proven on-chain (Sepolia):** relayer-paid `execute_from_outside_v2`,
|
|
129
|
+
authorized solely by the silent device signature, executed a real STRK approve
|
|
130
|
+
([tx](https://sepolia.starkscan.co/tx/0x05ade4008f4ccbcfe4a7f016c61eb0eb591c8f696db3f5dad6f0db3ea3b5d2e6)).
|
|
131
|
+
- ✅ Contract SNIP-6 `is_valid_signature` + SNIP-9 `execute_from_outside_v2` (OZ SRC9 component).
|
|
132
|
+
- ✅ `CavosAuth` (hosted Google/Apple/email/OTP login, mirroring `@cavos/react`).
|
|
133
|
+
- ✅ Recovery client interface (non-custodial multi-device email-approval flow).
|
|
134
|
+
- 🚧 Cavos paymaster backend must register the new class hash (backend, out of repo).
|
|
135
|
+
- 🚧 Recovery backend service + session keys (Phase 2).
|
|
136
|
+
|
|
137
|
+
## Demo
|
|
138
|
+
|
|
139
|
+
A runnable end-to-end demo lives in `my-app/app/kit-demo` (Next.js): log in
|
|
140
|
+
(identity only), see the deterministic address, create the silent device key,
|
|
141
|
+
build onboarding calls, sign a tx with zero prompts, and walk the non-custodial
|
|
142
|
+
add-device flow. Run `npm run dev` in `my-app` and open `/kit-demo`.
|
|
143
|
+
|
|
144
|
+
## Develop
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
npm install
|
|
148
|
+
npm run type-check
|
|
149
|
+
npm test # signature <-> contract payload compatibility
|
|
150
|
+
npm run build # tsup -> dist (cjs + esm + d.ts)
|
|
151
|
+
```
|