Starknet
Use @cavos/kit on Starknet — silent device signing, gasless execution via paymaster, and the Cairo DeviceAccount.
Starknet is one of the current adapters in Cavos' every-chain architecture. A
deterministic address derived from the user's identity is controlled by a
silent secp256r1 (P-256) device key, validated on-chain by the Cairo
DeviceAccount account contract. Deploy and execution are sponsored by the
Cavos paymaster, so the user pays no gas.
Connect
Cavos.connect with chain: "starknet" (or chains: ["starknet"]) does
everything: authenticate, derive the deterministic address, create/load the
silent device key, and wire up the gas sponsor. Connect never deploys. The
account is created lazily on the first execute.
import { Cavos } from "@cavos/kit";
const session = await Cavos.connect({
chains: ["starknet"],
defaultChain: "starknet",
network: "testnet", // "testnet" (sepolia) | "mainnet"
appSalt: "my-app", // device-key namespace
identity: { // from your login (see Authentication)
userId: user.id,
email: user.email,
},
appId: process.env.NEXT_PUBLIC_CAVOS_APP_ID,
paymasterApiKey: process.env.NEXT_PUBLIC_CAVOS_PAYMASTER_API_KEY!, // app-scoped, client-visible
});
const wallet = session.wallet("starknet");
console.log(wallet.address); // deterministic address
console.log(wallet.status); // "undeployed" | "ready" | "needs-device-approval"wallet.chain narrows to "starknet". The instance members (address,
status, execute, addSigner, setupRecovery) are documented in the
API reference.
Status values
| Status | Meaning | Can execute? |
|---|---|---|
undeployed | Address derived, no on-chain account yet | Yes — first execute deploys + runs atomically |
ready | Account deployed and this device authorized | Yes |
needs-device-approval | Account deployed but this device not authorized | No — route to device approval |
Lazy deploy: An undeployed wallet can sign messages and execute. The
first execute deploys the account and runs the user's calls in a single
sponsored transaction. After that, status becomes ready.
Execute a transaction
Both undeployed and ready wallets can execute. Only needs-device-approval
must be handled differently.
if (wallet.chain === "starknet" && wallet.status !== "needs-device-approval") {
const { transactionHash } = await wallet.execute([
{
contractAddress: STRK_TOKEN,
entrypoint: "approve",
calldata: [spender, amountLow, amountHigh],
},
]);
console.log(transactionHash);
}When the account is undeployed, this call deploys the account first, then
executes the calls — atomically in a single paymaster-sponsored transaction.
If status is "needs-device-approval", this device is new to an existing
wallet. Approve it from an already-registered device — see
Multi-device or Passkeys.
How signing works
The device key is a non-extractable secp256r1 key held in IndexedDB via
WebCrypto. When you call execute:
- starknet.js computes the v3 transaction hash.
- The device key signs
sha256(tx_hash)— WebCrypto's ECDSA hashes the message internally, so there is no user interaction. - The signature is serialized as 5 felts:
[r_low, r_high, s_low, s_high, y_parity]. - On-chain,
DeviceAccount.__validate__recomputessha256(tx_hash), normalizes high-s, recovers the secp256r1 signer, and checks it is authorized.
This 5-felt encoding is byte-compatible with the contract and covered by a
cross-checked test in the account-contracts repo.
Gasless execution
execute routes through the Cavos paymaster (SNIP-9 execute_from_outside),
so the user pays no gas. Both account deployment (first execute) and
every subsequent execution are sponsored — the user never needs ETH or STRK.
Sign messages
Sign arbitrary messages off-chain with the device key. Works on both
undeployed and ready wallets:
const sig = await wallet.signMessage("Hello, Cavos!");
// sig.signature: Uint8Array (64 bytes, r||s)
// sig.publicKey: "04..." (uncompressed secp256r1)
// sig.curve: "secp256r1"The message is prefixed with "Cavos Signed Message:\n<len>\n" before signing.
Recovery and passkeys
Set up recovery factors so the user can regain access from a new device:
// On a ready or undeployed wallet
const code = generateRecoveryCode();
await wallet.setupRecovery(code); // registers backup signer (pending if undeployed)
// Show `code` to the user once — the kit never persists itFor undeployed wallets, setupRecovery stores the backup signer pending. It
gets included in the first deploy transaction automatically.
See Recovery and Passkeys for the full model.
Advanced: a plain starknet.js Account
StarknetDeviceSigner is a drop-in starknet.js SignerInterface, so you can
plug the device key into a standard Account and your own paymaster flow:
import { Account, RpcProvider } from "starknet";
import { StarknetDeviceSigner, WebCryptoSigner } from "@cavos/kit";
const provider = new RpcProvider({ nodeUrl: "https://api.cartridge.gg/x/starknet/sepolia" });
const signer = await WebCryptoSigner.loadOrCreate({ keyId: address });
const account = new Account({
provider,
address,
signer: new StarknetDeviceSigner(signer),
cairoVersion: "1",
});Gas estimation gotcha (self-funded path). secp256r1 validation is heavy
(~27M L2 gas). Default fee estimation uses SKIP_VALIDATE, which under-bounds
and causes "Out of gas". Estimate with validation on and pass those bounds:
const fee = await account.estimateInvokeFee(calls, { skipValidate: false });
await account.execute(calls, { resourceBounds: fee.resourceBounds });The Cavos paymaster path handles this for you — this only matters when you submit transactions yourself.
Networks & constants
import { STARKNET_NETWORKS, DEVICE_ACCOUNT_CLASS_HASH } from "@cavos/kit";
STARKNET_NETWORKS.sepolia; // RPC + chain config
DEVICE_ACCOUNT_CLASS_HASH.sepolia; // deployed DeviceAccount class hashnetwork accepts "testnet" (resolves to sepolia) and "mainnet". The class
hash is the declared DeviceAccount contract; the kit ships the current values.
What's available
- ✅ Silent secp256r1 device signer, deterministic address.
- ✅ Lazy deploy — first execute creates the account atomically.
- ✅ Gasless execute + deployment via the Cavos paymaster.
- ✅ Sign messages off-chain while undeployed.
- ✅ Multi-device approval + recovery (recovery-code backup) — non-custodial.
- ✅ Passkeys as approvers for new-device authorization.
For the cross-chain model and how Solana and Stellar compare, see Chains, Solana, and Stellar.