# Security at MoonPay Wallets

MoonPay Wallets uses multi-party computation (MPC) shares for standard signing. The client share is protected by passkeys, identity-backed encryption, or both. The server-side share participates through an isolated signer.

The wallet's recovery and custody guarantees depend on how the client share is protected. [Identity-backed encryption](/security/identity-backed-encryption) adds trust in account access and a MoonPay-operated KMS key.

<Info>
  MoonPay Wallets signs with published, peer-reviewed threshold protocols: DKLs23 for ECDSA and FROST for EdDSA. See [MPC key custody](/security/key-custody) for protocol references and audit history.
</Info>

## Architecture at a glance

Standard wallets use a 2-of-2 MPC model. One share participates from the client, and the server-side MPC signer holds the other. Both shares must participate to produce a signature. The full private key is not assembled during standard signing.

<div className="mx-passkey-diagram mx-object-model" role="group" aria-label="MoonPay Wallets signing architecture">
  <div className="mx-model-summary">
    <span className="mx-diagram-kicker">Signing architecture</span>
    <strong>2-of-2 signing: the client share and the signer share must both participate</strong>
    <span>Client-share access depends on the user's passkey or identity-backed wrap.</span>
  </div>

  <svg className="mx-object-model-svg" width="100%" viewBox="0 0 720 348" role="img" aria-label="The client MPC share in the MoonPay Wallets secure iframe and the server-side MPC signer exchange encrypted protocol messages. A passkey or identity-backed wrap unlocks the client share. The signer runs in a trusted execution environment and encrypts its share at rest with cloud KMS.">
    <defs>
      <marker id="mxSecArrowPrimary" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
        <path d="M2 1L8 5L2 9" fill="none" stroke="var(--mx-diagram-accent)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
      </marker>

      <marker id="mxSecArrowSecondary" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
        <path d="M2 1L8 5L2 9" fill="none" stroke="var(--mx-diagram-secondary)" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
      </marker>
    </defs>

    <rect x="10" y="10" width="205" height="300" rx="12" fill="none" stroke="currentColor" strokeOpacity="0.2" strokeDasharray="5 5" />

    <text x="28" y="34" fontSize="13" fontWeight="650" fill="currentColor">Browser</text>
    <text x="28" y="52" fontSize="11.5" fill="currentColor" opacity="0.58">Secure wallet iframe</text>

    <rect x="250" y="10" width="205" height="300" rx="12" fill="none" stroke="currentColor" strokeOpacity="0.2" strokeDasharray="5 5" />

    <text x="268" y="34" fontSize="13" fontWeight="650" fill="currentColor">MoonPay Wallets</text>
    <text x="268" y="52" fontSize="11.5" fill="currentColor" opacity="0.58">wallet and session APIs</text>

    <rect x="490" y="10" width="220" height="300" rx="12" fill="none" stroke="currentColor" strokeOpacity="0.2" strokeDasharray="5 5" />

    <text x="508" y="34" fontSize="13" fontWeight="650" fill="currentColor">Signing infrastructure</text>
    <text x="508" y="52" fontSize="11.5" fill="currentColor" opacity="0.58">isolated signer and relay</text>

    <rect x="30" y="90" width="165" height="90" rx="8" fill="var(--mx-diagram-card)" stroke="var(--mx-diagram-accent)" strokeOpacity="0.75" strokeWidth="1.25" />

    <text x="112" y="110" fontSize="13" fontWeight="650" fill="currentColor" textAnchor="middle" dominantBaseline="central">Client MPC share</text>
    <text x="112" y="128" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="middle" dominantBaseline="central">DEK unlocked by a passkey</text>
    <text x="112" y="142" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="middle" dominantBaseline="central">or an identity-backed wrap</text>
    <text x="112" y="156" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="middle" dominantBaseline="central">decrypted in the iframe to sign</text>

    <rect x="270" y="80" width="165" height="52" rx="8" fill="currentColor" fillOpacity="0.04" stroke="currentColor" strokeOpacity="0.25" />

    <text x="352" y="98" fontSize="12.5" fontWeight="650" fill="currentColor" textAnchor="middle" dominantBaseline="central">Wallet API</text>
    <text x="352" y="116" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="middle" dominantBaseline="central">key create / sign / prove</text>

    <rect x="270" y="210" width="165" height="66" rx="8" fill="currentColor" fillOpacity="0.04" stroke="currentColor" strokeOpacity="0.25" />

    <text x="352" y="228" fontSize="12.5" fontWeight="650" fill="currentColor" textAnchor="middle" dominantBaseline="central">Authentication API</text>
    <text x="352" y="246" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="middle" dominantBaseline="central">identity and sessions</text>
    <text x="352" y="260" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="middle" dominantBaseline="central">encrypted client shares</text>

    <rect x="510" y="70" width="180" height="92" rx="8" fill="var(--mx-diagram-card)" stroke="var(--mx-diagram-accent)" strokeOpacity="0.75" strokeWidth="1.25" />

    <text x="600" y="88" fontSize="13" fontWeight="650" fill="currentColor" textAnchor="middle" dominantBaseline="central">MPC signer</text>
    <text x="600" y="106" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="middle" dominantBaseline="central">holds the server share</text>
    <text x="600" y="120" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="middle" dominantBaseline="central">TEE (AWS Nitro Enclave)</text>
    <text x="600" y="134" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="middle" dominantBaseline="central">cloud KMS at rest</text>

    <rect x="510" y="212" width="180" height="76" rx="8" fill="var(--mx-diagram-card)" stroke="var(--mx-diagram-secondary)" strokeOpacity="0.58" />

    <text x="600" y="230" fontSize="13" fontWeight="650" fill="currentColor" textAnchor="middle" dominantBaseline="central">Relay room</text>
    <text x="600" y="248" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="middle" dominantBaseline="central">end-to-end encrypted MPC</text>
    <text x="600" y="262" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="middle" dominantBaseline="central">messages, no key material</text>

    <path className="mx-flow-line" d="M112 180C112 355 600 355 600 288" fill="none" stroke="var(--mx-diagram-accent)" strokeWidth="1.5" markerStart="url(#mxSecArrowPrimary)" markerEnd="url(#mxSecArrowPrimary)" />

    <text x="356" y="341" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="middle">MPC protocol messages</text>

    <path className="mx-flow-line" d="M600 162L600 212" fill="none" stroke="var(--mx-diagram-accent)" strokeWidth="1.5" markerStart="url(#mxSecArrowPrimary)" markerEnd="url(#mxSecArrowPrimary)" />

    <path className="mx-flow-line mx-flow-secondary" d="M435 106C480 116 500 170 508 212" fill="none" stroke="var(--mx-diagram-secondary)" strokeWidth="1.35" markerEnd="url(#mxSecArrowSecondary)" />

    <text x="448" y="150" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="end">orchestrates</text>
    <text x="448" y="164" fontSize="10.5" fill="currentColor" opacity="0.58" textAnchor="end">the room</text>
  </svg>
</div>

A standard signature requires both the client share and the signer share. Passkey-only wallets require the user's passkey to unlock the client share. Identity-backed wallets also permit access through an eligible signed-in session. The MPC signer runs in an AWS Nitro Enclave and encrypts its share at rest with cloud KMS.

The relay is untrusted by design. All MPC protocol traffic through it is end-to-end encrypted between the participating shares, it holds no key material and provides no cryptographic services, so a relay compromise can cause downtime but cannot expose key shares or forge signatures.

## The security model in depth

<CardGroup cols={2}>
  <Card title="What is MPC?" icon="signature" href="/security/what-is-mpc">
    Multi-party computation from scratch: threshold signing versus key splitting, and why recovery needs the user.
  </Card>

  <Card title="MPC key custody" icon="lock" href="/security/key-custody">
    How wallet keys exist as shares, the signature schemes and audit history, and what each party can and cannot do.
  </Card>

  <Card title="Passkeys and recovery" icon="shield-check" href="/security/passkeys-and-recovery">
    How client-share protection determines recovery and private-key export requirements.
  </Card>

  <Card title="Identity-backed encryption" icon="fingerprint" href="/security/identity-backed-encryption">
    Session-authorized wallet access, the KMS trust model, and recovery without a passkey.
  </Card>

  <Card title="Sessions and presence" icon="key" href="/security/sessions-and-presence">
    The token model, refresh rotation and reuse detection, and the presence checks behind high-risk operations.
  </Card>

  <Card title="Delegated signing" icon="robot" href="/security/delegated-signing">
    User-provisioned agents, enclave attestation, and the two credentials required to sign.
  </Card>

  <Card title="Compliance and data handling" icon="list-check" href="/security/compliance-and-data-handling">
    Wallet screening, address integrity proofs, blocked-account behavior, and what MoonPay Wallets does not hold.
  </Card>
</CardGroup>
