Development of Embedded Wallets System
Embedded wallet — wallet that lives inside the app: user doesn't know about seed phrase, doesn't install MetaMask, doesn't think about private keys. They just log in via Google/email and get ability to own assets. This is key pattern for onboarding mass audience to Web3.
Problem Embedded Wallets Solve
Requirement to install MetaMask kills conversion. Research shows 99%+ of potential Web3 app users never interacted with crypto. Embedded wallet removes this barrier: application itself manages wallet, providing familiar UX.
Key requirements for embedded wallet:
- Non-custodial (or verifiably MPC-based) — app can't steal funds
- Recoverable — user doesn't lose access on device change
- Exportable — user can opt into self-custody
- Seamless — doesn't interrupt app UX
Technical Approaches to Key Storage
MPC (Multi-Party Computation)
Key is divided between user device, app server, and (optionally) third party. Signing requires interaction of minimum two participants.
Implementations: Privy (Shamir Secret Sharing + key sharding), Dynamic (Turnkey under the hood), Particle Network (own MPC-TSS), Web3Auth (threshold signatures).
Key Share 1: User device (localStorage encrypted / SecureEnclave)
Key Share 2: Provider server (HSM)
Key Share 3: Recovery factor (email/social provider)
Signature = MPC protocol between Share 1 + Share 2
Recovery = MPC between Share 2 + Share 3
Neither participant can recover full key alone.
TEE (Trusted Execution Environment)
Key is generated and stored in protected enclave environment (Intel SGX, AWS Nitro Enclaves). Turnkey uses this approach. Code in TEE is verifiable (attestation), TEE operator can't access data inside.
Client-side Encryption + Cloud Backup
Simplest approach: key pair generated in browser, encrypted with user password, encrypted blob stored in cloud. On login — blob downloaded, decrypted with password. Privy uses variation of this as fallback.
Downside: security = password complexity + cloud security.
Implementation via Privy
Privy — most mature solution for embedded wallets. Supports social login, embedded wallet with MPC, key export.
import { PrivyProvider, usePrivy, useWallets } from "@privy-io/react-auth";
function App() {
return (
<PrivyProvider
appId="YOUR_APP_ID"
config={{
loginMethods: ["email", "google", "twitter", "wallet"],
embeddedWallets: {
createOnLogin: "users-without-wallets",
requireUserPasswordOnCreate: false,
showWalletUIs: true,
},
appearance: {
theme: "dark",
accentColor: "#6366f1",
},
}}
>
<Main />
</PrivyProvider>
);
}
function Main() {
const { login, authenticated, user } = usePrivy();
const { wallets } = useWallets();
const embeddedWallet = wallets.find(w => w.walletClientType === "privy");
async function signMessage() {
if (!embeddedWallet) return;
const provider = await embeddedWallet.getEthereumProvider();
const signature = await provider.request({
method: "personal_sign",
params: ["Hello World", embeddedWallet.address],
});
return signature;
}
return authenticated ? (
<div>
<p>Address: {embeddedWallet?.address}</p>
<button onClick={signMessage}>Sign</button>
</div>
) : (
<button onClick={login}>Login</button>
);
}
Own Implementation Based on Web3Auth
Web3Auth provides MPC infrastructure which can be integrated directly without extra layers:
import { Web3Auth } from "@web3auth/modal";
import { CHAIN_NAMESPACES, WEB3AUTH_NETWORK } from "@web3auth/base";
const web3auth = new Web3Auth({
clientId: "YOUR_CLIENT_ID",
web3AuthNetwork: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET,
chainConfig: {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: "0x1",
rpcTarget: "https://rpc.ankr.com/eth",
},
uiConfig: {
appName: "My App",
mode: "dark",
loginMethodsOrder: ["google", "twitter", "email_passwordless"],
},
});
await web3auth.initModal();
// User clicks button → selects social provider → gets wallet
const provider = await web3auth.connect();
const accounts = await provider.request({ method: "eth_accounts" });
Web3Auth uses Shamir Secret Sharing: key split into shares between network nodes (threshold network). Minimum T of N nodes must agree to recover key. Architecture verifiable via attestation.
Custom Recovery Flow
Embedded wallet without recovery = disaster on device change. Need to implement:
Email recovery. On login from new device — confirmation code on email → recovery of key share.
Social recovery. Owner appoints guardians (other addresses). On access loss — guardians vote to change owner. Implemented via smart contract on top of embedded wallet.
Passkey (WebAuthn). Biometric auth as second factor. Face ID/Touch ID as key share. Supported in iOS Safari, Chrome on Android, macOS.
// Passkey registration
async function registerPasskey() {
const credential = await navigator.credentials.create({
publicKey: {
challenge: await getChallenge(),
rp: { name: "My App", id: "myapp.com" },
user: {
id: new TextEncoder().encode(userId),
name: userEmail,
displayName: userName,
},
pubKeyCredParams: [{ type: "public-key", alg: -7 }], // ES256
authenticatorSelection: {
authenticatorAttachment: "platform",
userVerification: "required",
residentKey: "required",
},
},
});
// Save credential ID and public key
await savePasskeyCredential(credential);
}
Session Keys for Seamless UX
For apps with frequent transactions (games, trading) — session keys allow signing transactions without user confirming each:
interface SessionKeyConfig {
expiresAt: number; // unix timestamp
allowedContracts: string[]; // only these contracts
maxValuePerTx: bigint; // ETH limit per transaction
dailySpendLimit: bigint; // daily limit
allowedFunctions: string[]; // function selectors
}
User once confirms session (like "allow app X operations during Y"), then app uses session key without requests.
Provider Comparison
| Provider | Approach | Key Export | Self-hosted | Passkeys |
|---|---|---|---|---|
| Privy | MPC (Shamir) | Yes | No | Yes |
| Dynamic | Turnkey (TEE) | Yes | No | Yes |
| Web3Auth | MPC (threshold) | Yes | Partial | Yes |
| Magic | DKMS (HSM) | Pro plan | No | No |
| Particle Network | MPC-TSS | Yes | Yes (enterprise) | Yes |
Security and Compliance
Key export. Must be implemented: user clicks "Export Key", passes additional verification (email OTP + password), gets private key or seed phrase. Critical for non-custodial positioning.
Server-side validation. Server must not be able to conduct transaction without user consent. MPC architecture must guarantee this — and it must be verifiable (open-source SDK, attestation).
Audit trail. All operations logged (without private key data). User can view activity history with their wallet.
Stack
Ready providers: Privy, Dynamic, Web3Auth, Particle Network Smart contracts for social recovery: Safe{Core} Recovery Module, ERC-4337 compatible accounts Session keys: Kernel (ZeroDev), Alchemy Modular Account Passkeys: SimpleWebAuthn (server), navigator.credentials (browser)
Timeline
- Basic integration (Privy/Dynamic + social login + embedded wallet): 1-2 weeks
- Custom UI + recovery flows: +1-2 weeks
- Session keys + gasless transactions: +1-2 weeks
- Own MPC infrastructure (enterprise): 3-4 months







