7.1. 1-Click Trade Interface
The 1-Click Trade Interface represents a fundamental shift in decentralized user experience, eliminating the repetitive wallet pop-ups and signing friction typical of traditional Web3 applications. In high-frequency environments like sealed-bid auctions, requiring a user to sign every bid or refund claim is not only tedious but exposes them to potential social engineering and “signing blindness.”
Fhenix-FairMarket v2.0 resolves this by integrating ERC-4337 Account Abstraction. Upon initial connection, the protocol generates an Ephemeral Session Key with scoped permissions and a strict Time-To-Live (TTL). This allows users to interact with the auction seamlessly—locking escrow, placing encrypted bids, and claiming refunds—without further interaction from their browser wallet, while maintaining rigorous security through isolated memory storage and cryptographic bounds.
Core Design Principles
| Principle | Technical Implementation |
|---|---|
| Ephemeral Session Keys | Temporary signing keys generated per session with a hard 24-hour TTL. They expire automatically to limit the attack window. |
| Scoped Permissions | Session keys are cryptographically restricted to specific functions: placeBid(), lockEscrow(), and claimRefund(). They cannot approve arbitrary token transfers or upgrade contracts. |
| Memory-Only Storage | Session permits are stored in secure application memory or encrypted IndexedDB via the Web Crypto API. localStorage and cookies are strictly prohibited to neutralize XSS vectors. |
| Bundler Integration | Transactions are routed through ERC-4337 Bundlers (e.g., Gelato, Pimlico), enabling gas sponsorship options and batch execution capabilities. |
| Fail-Safe Fallback | If a session expires or the Smart Account fails, the UI automatically reverts to standard wallet signing (Metamask/WalletConnect) without losing user context. |
️ Technical Implementation
1. Session Key Generation (useERC4337Session.ts)
The core logic resides in a custom React hook that manages the lifecycle of the Smart Account and its session keys.
// packages/frontend/src/lib/hooks/useERC4337Session.ts
import { createSmartAccountClient } from 'permissionless';
import { encryptWithWebCrypto, storeInIndexedDB } from '@lib/crypto';
export function useERC4337Session() {
const [sessionPermit, setSessionPermit] = useState<SessionPermit | null>(null);
// 1. Generate Ephemeral Key on User Authentication
const createSession = async () => {
const smartAccount = await createSmartAccountClient({
signer: window.ethereum, // Initial user wallet
paymaster: process.env.NEXT_PUBLIC_PAYMASTER
});
const permit = await smartAccount.createSessionKey({
ttl: 24 * 60 * 60, // 24-hour Time-To-Live
scope: ['placeBid', 'lockEscrow', 'claimRefund'], // Granular permissions
safeStorage: true // Enforces Web Crypto API + IndexedDB
});
// Encrypt and store in IndexedDB only (No localStorage)
const encrypted = await encryptWithWebCrypto(permit);
await storeInIndexedDB('ffm_session', encrypted);
setSessionPermit(permit);
return permit;
};
return { createSession, executeSessionAction, isSessionActive };
}2. Zero-Friction Bid Execution
When a user clicks “Place Bid,” the interface checks for a valid session permit. If active, the transaction is signed locally and sent to the Bundler instantly.
// packages/frontend/src/app/auction/[id]/components/BidForm.tsx
const handleBid = async (amount: number) => {
if (!sessionPermit || isSessionExpired) {
// Fallback to standard wallet signing if session invalid
await promptWalletSignature();
return;
}
try {
// 1. Encrypt bid locally
const encryptedBid = await encryptBid(amount);
// 2. Execute via Session Key (No Metamask Pop-up)
await executeSessionAction({
to: CONTRACT_ADDRESS,
data: fairMarketInterface.encodeFunctionData('placeBid', [auctionId, encryptedBid]),
});
// 3. Optimistic UI Update
setBidStatus('Processing');
} catch (err) {
// Rollback UI on failure
setBidStatus('Failed');
}
};3. Security Enforcement (CI/CD Level)
To guarantee the “Memory-Only” principle, the project enforces a zero-tolerance policy for insecure browser storage at the build level.
// .eslintrc.js
{
"rules": {
"no-restricted-properties": [
"error",
{ "object": "localStorage", "message": "Forbidden: Use secure memory or encrypted IndexedDB via Web Crypto API." },
{ "object": "document", "property": "cookie", "message": "Forbidden: No cookies allowed for cryptographic permits." }
]
}
}User Flow
️ Security Guarantees & Threat Mitigations
| Threat Vector | Mitigation Strategy |
|---|---|
| XSS Key Theft | Session keys are never stored in localStorage. They are encrypted via Web Crypto API before persistence in IndexedDB, making them useless to injected scripts without the master password/seed. |
| Session Hijacking | Strict 24-hour TTL ensures that even if a key is compromised, the attacker has a severely limited window to exploit it before the key cryptographically expires. |
| Unauthorized Spending | Scoped Permissions limit the session key to auction-specific functions. A compromised key cannot be used to drain the user’s wallet or interact with external contracts. |
| Phishing / Signing Blindness | By reducing the need for signatures, users are less likely to fall into the habit of blindly signing transactions. Critical state changes (like EmergencyHalt) still require explicit main-wallet confirmation. |
Audit Gate Compliance (P0)
Progression to Phase 6 is strictly blocked until all P0 items pass:
- [] Zero
localStorage/cookiesusage: Enforced via ESLintno-restricted-propertiesrule. - [] 24-Hour TTL Enforced: Session permits automatically invalidate post-expiry; UI prompts for re-auth.
- [] Granular Scoping: Keys cannot authorize
upgradeToAndCallor arbitrary fund transfers. - [] Fail-Safe Fallback: UI correctly prompts for wallet signature upon session expiry or Bundler failure.
- [] Memory Encryption: IndexedDB payloads encrypted using Web Crypto API before persistence.
- [] Bundler Revert Handling: UI automatically rolls back optimistic state if the Bundler reports transaction failure.
Unresolved Points & Explicit Gaps
| Gap / Unresolved Point | Impact | Current Status | Recommended Action |
|---|---|---|---|
| Gas Sponsorship Logic | Who pays the gas for the 1-Click bid? The user’s smart account or the protocol bundler? | Docs imply user pays; explicit sponsorship configuration not detailed in Phase 5. | Configure Paymaster in createSmartAccountClient to subsidize gas for verified users to enhance the “1-Click” feel. |
| Offline Bidding Queue | Can users encrypt and queue bids while offline for later broadcast? | Not supported in current architecture. | Implement a local queue mechanism via Service Workers to allow bid preparation during connectivity loss. |
| Device Binding | Is the session key bound to a specific device fingerprint? | Currently bound only to the browser storage. | Consider adding device-bound attestation (e.g., Passkeys) for higher security tiers in v2.1. |
Fact vs. Analysis Distinction: The use of ERC-4337, 24h TTL, IndexedDB storage, and scoped permissions are verified facts from the Phase 5 Matrix and Technical Spec. Gas sponsorship models, offline queuing, and device binding are unresolved architectural gaps requiring explicit definition before Mainnet launch.
Next Steps
- Proceed to 7.2. Session Ephemeral Keys for detailed lifecycle management and revocation logic.
- Review Security Model → Session Key Isolation for XSS mitigation strategies and Web Crypto API implementation.
- Explore Developer Quickstart → Frontend Setup for local environment configuration and ERC-4337 testing instructions.