Skip to content

Make Starknet a native account on OpenZeppelin AccountUpgradeable - #44

Merged
adrianvrj merged 3 commits into
mainfrom
starknet-native-oz
Oct 13, 2026
Merged

adrianvrj merged 3 commits into
mainfrom
starknet-native-oz

Conversation

@adrianvrj

@adrianvrj adrianvrj commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Starknet now works like Solana and Stellar: the key derives from the MasterDEK, recovery is off-chain (enclave or passkey PRF), and there is no on-chain device management. The account is the standard OpenZeppelin AccountUpgradeable v3.0.0 instead of the custom Cairo DeviceAccount.

  • Key: HKDF(DEK, appSalt, "cavos-stark-starknet-v1") → grindKey (EIP-2645 rejection sampling) → stark key.
  • Address: calculateContractAddressFromHash(pubKey, OZ_ACCOUNT_CLASS_HASH, [pubKey], 0), the OZ convention from the starknet.js guide. The Cavos paymaster deploys through UDC with unique=0, which yields the same address.
  • Class hash: 0x01d1777d…02381 (OZ v3.0.0, Scarb 2.13.1 --release, audited in audits/2025-11-v3.0.0.pdf). It is declared on mainnet and Sepolia, and its ABI matches v4.0.1's: constructor (public_key), SRC-9 V2, upgrade. It is pinned forever, because the address derives from it. Later changes go through the account's upgrade, which keeps the address. That is also the path to post-quantum (OZ Falcon-512) later.
  • Deploy: lazy, on the first sponsored execute (executePaymasterTransaction with deploymentData), same as before.
  • signMessage: SNIP-12 revision 1 typed data, verifiable with the account's is_valid_signature. Returns curve: "stark" plus the typedData.
  • Guard: execute/signTransaction refuse set_public_key on the account itself, by name or selector. A rotated key would no longer be controlled by the DEK.
  • Vault: the Starknet branch derives through resolveNativeStarknet, like Solana. signStarknetMessage is removed; messages go through signStarknetTypedData.
  • Removed:
    • the Starknet adapter and device signer;
    • the WebCrypto and passkey P-256 signers, and the WebAuthn and P-256 signature helpers;
    • SocialRecoveryCoordinator, HttpRecoveryClient, BackupSigner, identity.ts;
    • the device approval and revoke pages;
    • React addSigner, removeSigner, listDevices, resendDeviceApproval, enrollPasskey, and Cavos.recover;
    • dead throwing stubs on CavosSolana.
  • The recovery-phrase UI in the auth modal now shows only on Stellar, the one chain where recovery codes work.

Released as 0.4.2. This is a breaking change shipped as a patch, so any app on ^0.4.x picks it up on its next install.

Trade-offs

  • WebCrypto cannot hold a stark key. Outside the vault, the key is re-derived into memory from the device-wrapped DEK. The DEK at rest stays protected by the non-extractable device key. On React Native the Starknet key is no longer hardware-backed.

Rollout notes

  • Vault protocol: the Starknet vault protocol changed. cavos-web serves the vault host from the npm package (lib/vault/copyAssets.mjs), so it must be redeployed with 0.4.2 before apps use 0.4.2 on Starknet. Any cavos-web redeploy picks up 0.4.2 through ^0.4.1.
  • Dead backend code: the cavos-web /api/devices/* routes and the enclave's ChainAuthorization::Starknet are now unused. Their cleanup is a separate change.

Test plan

  • tsc --noEmit clean.
  • jest: 57 suites, 381 passed, 2 skipped.
  • New tests:
    • pinned derivation vector (seed → key → address);
    • OZ address formula;
    • deploymentData shape on the first execute;
    • status transitions;
    • the key-rotation guard (name, selector, zero padding);
    • SNIP-12 signature verified against the typed-data hash;
    • the vault host Starknet branch.
  • Not yet verified on-chain: the sponsored OZ deploy through the Cavos paymaster, and is_valid_signature on a deployed account.

Starknet now follows the Solana and Stellar model: the account key is a stark
key ground from HKDF of the MasterDEK, and the account is the standard OZ
AccountUpgradeable v4.0.1 (class 0x03013bf2...26144, pinned because the
address derives from it). Recovery is off-chain through the enclave or a
passkey, like the other chains.

Removes the custom DeviceAccount model: the Starknet adapter, P-256 device
signers, on-chain passkey approvers, on-chain social recovery, the backup
signer, the device approval and revoke pages, and the React APIs built on
them. signMessage on Starknet is SNIP-12 typed data. The kit refuses
set_public_key on the account, since a rotated key would no longer be
controlled by the DEK.

Breaking, so 0.5.0.
The v4.0.1 class is only declared on Sepolia. v3.0.0 is declared on both
networks, was audited (audits/2025-11-v3.0.0.pdf), and its account and SRC9
code differs from v4.0.1 only in a type conversion: same constructor, SRC9 V2
and upgrade.
@adrianvrj
adrianvrj merged commit c077933 into main Oct 13, 2026
2 checks passed
@adrianvrj
adrianvrj deleted the starknet-native-oz branch October 13, 2026 01:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant