Skip to main content

Grant a dApp Less Than the Whole Account

Connect most wallets to a dApp and the dApp effectively gets the whole account β€” there's no standard way to ask for less. Session-key systems exist, but each ships as a different vendor SDK with its own validator shape, so nothing is portable across wallets. LSP6 Key Manager makes scoped access a standard, on-chain vocabulary every Universal Profile speaks: a permission bitfield per controller, plus optional allowed calls (target, standard, selector) and allowed ERC725Y data keys. Granting a narrow session controller is one transaction. Revoking it is one transaction. And because the profile checks permissions on every call, the scope is enforced on-chain β€” not just hidden behind a wallet UI that a compromised frontend could ignore.

Before / after​

ModelScope granularityEnforced wherePortable across wallets
Default wallet connectfull accountnowhere β€” the dApp gets whatever it asks the user to signn/a
Argent session keysper-contract allowlistwallet-specific validatorno
ERC-4337 validation modulespluggable per walletvalidator contractmechanism is standard, policy is not
Zodiac scope guards (Safe)module-levelSafe moduleSafe-only
LSP6 Key Managerpermission bitfield + allowed calls + allowed data keysthe account contract itselfevery Universal Profile

Why "connect wallet" defaults to full access​

EOAs sign every action with the same key, so there's no narrower unit of authority to hand out in the first place. Even most smart wallets expose the full account on connect, because there's no standard way for a dApp to ask for something less than everything. When fine-grained authority does exist today, it usually lives in custom validator code written per wallet β€” interoperability is poor, and revocation tends to be all-or-nothing rather than scoped to the one controller that should lose access.

What people try today​

Argent session keys issue temporary signing keys scoped to an allowed-contract list, but the mechanism is vendor-specific to Argent's wallet. ERC-4337 validation modules make pluggable validators possible, which standardizes the mechanism for defining what a key may do, without standardizing the policy vocabulary itself β€” every wallet SDK still defines its own shape. Zodiac scope guards on Safe gate access at the module level, which is powerful but complex to author and scoped entirely to Safe accounts. Off-chain delegation via signed capability objects is flexible, but enforcement depends entirely on the relayer honoring the capability β€” there's no on-chain check backing it up.

How LSP6 makes scope a standard vocabulary​

LSP6 Key Manager assigns each controller a permission bitfield β€” CALL, SETDATA, TRANSFERVALUE, ADDCONTROLLER, SIGN, and more β€” plus optional allowed calls (target contract, standard interface, function selector) and allowed ERC725Y data keys:

Controller: app session key 0xabc...
Permission: CALL
AllowedCalls:
- target: 0x<token>, standard: LSP7, selector: transfer

Granting an app a session controller is one transaction. Revoking it is one transaction. The Universal Profile checks permissions on every call through LSP20, so the scope is enforced on-chain, not at a wallet UI layer that a malicious or compromised frontend could bypass. Core LSP6 has no controller-expiry field β€” a controller's permissions stay live until someone explicitly revokes them in a transaction. An app can layer its own off-chain "session" convention on top (e.g. stop using a key after N hours), but that's an app-level policy, not something the account itself enforces; a direct call with that controller's key still works until the on-chain permission is actually revoked.

Ask for less, by default

A Universal Profile lets a dApp request exactly the permission it needs β€” one token, one function, one target contract β€” instead of defaulting to full account access just because there was no standard way to ask for less.

Related reading: The ERC-20 approval problem Β· Social recovery without a seed phrase Β· The EOA key-risk problem Β· Grant controller permissions Β· Get controller permissions