| 3. Any digest? | Yes. isValidSignature (L640–685) takes the signer from the 0x6492… envelope, checks only block.timestamp < sessionSignerAuthorizedUntil(signer), then calls Solady ERC1271, which accepts an ERC-7739 TypedDataSign for any app domain or a PersonalSign of any hash. No check on verifying contract, type or scope | DepositWallet.sol, lib/solady/src/accounts/ERC1271.sol L24–46, L98–285 |
| 3. Can the key move funds? | Yes, through execute (L271–322): a session-signed batch may call any target except the wallet and the beacon, so pUSD.transfer/approve and CTF safeTransferFrom/setApprovalForAll pass. execute is onlyFactory; the factory’s proxy is onlyOperator (the relayer) | DepositWallet.sol; DepositWalletFactory.sol L206–210, L317 |
| 3. Token permits | pUSD permit uses ecrecover only, so it cannot sign for a contract wallet; no transferWithAuthorization. CTF has no signature approval. Not exploitable through the any-digest rule | pUSD impl 0xce84…25de (Solady ERC20); CTF source |
| 3. What auditors say | Zellic 3.1: a stale session signer “can perform token transfers and approvals”; Polymarket: handled “offchain … through our relayer”. Certora: session signer can “sign batches only (cannot call wallet itself)”, relayer “semi-trusted” | Zellic (Mar 2026), Certora (Mar 2026) |
| 4. Limits | Scopes (CLOB, COMBOSRFQ, ALL) exist only off-chain: the contract stores validUntil per signer and nothing else. Expiry is fixed at 180 days. No notional cap, no exchange allowlist | DepositWallet.sol L176–187, L332–338; session-keys.md |
| 5. Revocation | revokeSessionSigner is onlySelf: an owner-signed batch through the relayer. It takes effect when mined. The docs: revocation “cancels its open orders” and “may take several minutes”. Owner-only fallback: pause(), wait timelockDelay (3600 s on-chain), revokeSessionSignerEmergency; pausing alone does not stop the key. Whether L2 credentials stop at once: UNVERIFIED | DepositWallet.sol L343–347, L407, L492; session-keys.md |
| 6. Check at order time | Placement: off-chain only; the docs say keys are usable once listed by /v1/user/session-signers. How the CLOB checks scope: UNVERIFIED. Settlement: the exchange calls isValidSignatureNow(maker, …) on the wallet, so an expired or revoked key fails at match, except a preapproved order hash | CTF Exchange V2 Signatures.sol L47–56, L156–166 |
valid_until | Unix seconds; valid while block.timestamp < validUntil; authorizeSessionSigner requires it in the future | DepositWallet.sol L332–338, L661 |
| 1–2. Creation | Generated on the trading host; only the address is authorised by an owner-signed batch sent to the relayer with a Builder API key | session-keys.md, wallets-auth.md |