tenzro-agent-custody
v0.1.0
Published
Open-protocol agent custody SDK on Tenzro: TEE-sealed keys + ERC-7579 modules + passkey-first onboarding. A decentralized alternative to hosted custody (Turnkey / Coinbase Agentic Wallets / Privy).
Readme
tenzro-agent-custody
An open-protocol agent custody SDK on Tenzro — a decentralized alternative to hosted agent-custody products (Turnkey, Coinbase Agentic Wallets, Privy).
It packages the full lifecycle of giving an autonomous agent a self-custodied smart account: the human controller onboards with a passkey (no custodian holds keys), the agent gets a machine DID and a scoped ERC-7579 session key, an on-chain spending ceiling bounds every transaction, and guardian-based social recovery lets the human rotate the passkey without a custodian.
Why it's different
Hosted custody products hold your keys on a trusted server. This SDK holds no keys and runs no trusted server. Every primitive is a Tenzro RPC:
- Passkey-first onboarding — WebAuthn + hybrid post-quantum ML-DSA-65 enrollment. The smart account is recovered by the human, not held by a custodian.
- ERC-7579 SessionKeyValidator — scopes the agent to specific call targets, 4-byte selectors, a time window, and per-call / cumulative value ceilings.
- ERC-7579 SpendingLimitValidator — an on-chain per-tx + rolling-daily cap, enforced at signing time (the primary control surface, not advisory).
- Guardian social recovery — N-of-M guardians with hybrid Ed25519 + ML-DSA signatures rotate the controlling passkey.
Install & build
npm install
npm run buildQuick start
import { AgentCustody } from "tenzro-agent-custody";
const custody = new AgentCustody({ endpoint: "https://rpc.tenzro.network" });
// Opinionated end-to-end provisioning.
const agent = await custody.provisionAgent({
enrollment: {
passkeyPublicKeyHex, // from a WebAuthn registration
credentialIdHex,
mlDsaPublicKeyHex, // from the hybrid PQ enrollment
displayName: "Alice",
},
capabilities: ["payments", "trading"],
session: {
sessionPubkeyHex, // the agent's signing key
allowedSelectorsHex: ["0xa9059cbb"], // ERC-20 transfer
maxValuePerCallWei: "1000000000000000000",
maxTotalValueWei: "100000000000000000000",
validAfterUnix: Math.floor(Date.now() / 1000),
validUntilUnix: Math.floor(Date.now() / 1000) + 7 * 86400,
},
ceiling: {
perTxCapWei: "5000000000000000000",
dailyCapWei: "50000000000000000000",
authenticatorPubkeyHex: passkeyPublicKeyHex,
},
guardians: [
{ ed25519PubkeyHex, mlDsaPubkeyHex, label: "hardware-key" },
],
recoveryThreshold: 1,
});
console.log(agent.accountAddress, agent.agentDid);Or compose the primitives yourself — each AgentCustody method is a thin,
typed wrapper over one Tenzro RPC:
| Method | RPC |
|--------|-----|
| enrollPasskey(enrollment) | passkey enroll (WebAuthn + hybrid PQ) |
| registerAgentDid(controllerDid, capabilities) | TDIP machine DID registration |
| grantSession(account, scope) | install ERC-7579 SessionKeyValidator |
| setSpendingLimit(account, ceiling) | install ERC-7579 SpendingLimitValidator |
| addGuardian(account, guardian, threshold?) | add a social-recovery guardian |
| getAccount(account) | read installed modules + guardians |
Demo
npm run demoWithout WebAuthn credential material the demo runs a read-only liveness check
(lists smart accounts) so you can confirm the RPC path is reachable. To run the
full provisionAgent flow, supply real enrollment material via
TENZRO_CUSTODY_PASSKEY_PUBKEY_HEX, TENZRO_CUSTODY_CREDENTIAL_ID_HEX, and TENZRO_CUSTODY_MLDSA_PUBKEY_HEX — these
come from a browser/authenticator WebAuthn registration plus the hybrid ML-DSA
enrollment, and cannot be synthesized server-side.
Notes
- The SDK holds no signing keys. Onboarding produces a smart account recovered by the human's passkey; the agent only ever holds a scoped session key.
- On-chain validator modules are the enforcement surface. The session key and
spending limit are checked when the
UserOperationis validated — an agent cannot exceed its scope even if its runtime is compromised. - Configuration is a single
endpoint(defaults tohttps://rpc.tenzro.network).
