> ## Documentation Index
> Fetch the complete documentation index at: https://dev.enterprise.moonpay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Wallet as a Service

> Self-custodial embedded wallets, MPC signing, delegated agents, and fiat onramp and offramp for your users.

MoonPay WaaS gives your users a self-custodial, embedded wallet without asking them to install an extension, manage a seed phrase, or leave your app. A wallet is minted with a single SDK call for Ethereum/EVM, Solana/SVM, or Tron, and it is ready to receive, hold, and send stablecoins immediately.

WaaS is a separate integration with its own SDK, credentials, and dashboard. It does not run on your MoonPay Enterprise API key, and you can adopt it with or without the rest of MoonPay Enterprise.

<CardGroup cols={2}>
  <Card title="Multi-chain" icon="link">
    Ethereum/EVM, Solana/SVM, and Tron from one integration.
  </Card>

  <Card title="Self-custodial by construction" icon="lock">
    2-of-2 MPC signing. No party, including MoonPay, can sign alone.
  </Card>

  <Card title="On-demand creation" icon="wand-magic-sparkles">
    Mint a wallet the moment a user needs one. Never automatic at signup.
  </Card>

  <Card title="Exportable" icon="arrow-up-right-from-square">
    Users can export their private key at any time. No lock-in.
  </Card>
</CardGroup>

## How it works

A wallet key is never stored whole. It exists as two MPC (multi-party computation) shares: one held by the user's browser and protected by their passkey, one held by an isolated server-side signer. Both must participate to produce a signature, so neither MoonPay nor your app can move funds unilaterally.

<Card title="MoonPay WaaS SDK documentation" icon="book" href="https://x-docs.moonpay.com/get-started/frontend-sdks/react-native/quick-start" horizontal>
  Install the SDK, log a user in, and create a wallet.
</Card>

## Why it matters

Partners building banks, fintechs, remittance platforms, payroll products, and PSPs on MoonPay Enterprise all face the same problem. Once fiat becomes a stablecoin, it has to live somewhere. Standing up wallet infrastructure yourself means owning key management, custody risk, and passkey and recovery UX that has nothing to do with your core product.

Wallet as a Service removes that build. If you also run MoonPay Enterprise, the two compose in your own code: [Virtual Accounts](/onramp) turn incoming fiat into stablecoins, and a WaaS wallet is one place those stablecoins can land, self-custodial and under the end customer's control. You pass the address the SDK returns into the MoonPay Enterprise flow yourself.

<Note>
  Sending funds to a WaaS wallet through an [Autoramp](/autoramp) flow means registering its address against the customer first, the same as any other external wallet. See [Crypto Addresses](/crypto-addresses).
</Note>

## Chain support

|                                        | Ethereum & EVM                                                                                                | Solana                    | Tron                                       |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------- | ------------------------------------------ |
| Networks                               | Mainnet, all EVM-compatible L2s and sidechains (Base, Arbitrum, Optimism, Polygon, custom EVMs), and testnets | Mainnet, Devnet, Testnet  | Mainnet                                    |
| Embedded wallet creation               | ✅                                                                                                             | ✅                         | ✅                                          |
| Sign message                           | ✅ EIP-191                                                                                                     | ✅                         | ✅ TIP-191                                  |
| Sign typed data (EIP-712)              | ✅                                                                                                             | ❌                         | ❌                                          |
| Sign transaction                       | ✅                                                                                                             | ✅                         | ✅ client builds with TronWeb, wallet signs |
| Send transaction (sign and broadcast)  | ✅                                                                                                             | ✅                         | ✅                                          |
| Sign raw hash                          | ✅                                                                                                             | ❌                         | ❌                                          |
| EIP-7702 authorization signing         | ✅                                                                                                             | ❌                         | ❌                                          |
| Import and export private key          | ✅                                                                                                             | ✅                         | ✅                                          |
| Native balance and token account reads | ✅                                                                                                             | ✅ plus SPL token accounts | ✅                                          |

Every chain shares the same wallet creation, passkey protection, import/export, and delegated signing model described below. Only the signing surface differs per chain.

## Wallet lifecycle

### Creation

Wallets are never minted automatically at signup or login. Your app calls the chain-specific creation hook explicitly. The first wallet a user creates also triggers passkey enrollment, since the passkey is what protects the wallet's key material from then on.

```tsx theme={null}
import { useCreateWallet } from '@moon-x/react-sdk/ethereum';

function CreateWalletButton() {
  const { createWallet } = useCreateWallet();

  const handleCreate = async () => {
    const wallet = await createWallet();
    console.log('Wallet created:', wallet.address);
  };

  return <button onClick={handleCreate}>Create Wallet</button>;
}
```

For a brand-new user, collapse passkey enrollment and the first wallets into a single biometric prompt instead of two:

```tsx theme={null}
import { useRegisterPasskey } from '@moon-x/react-sdk';

const { registerPasskey } = useRegisterPasskey();

const { wallets } = await registerPasskey({
  createWallets: [{ chain: 'ethereum' }, { chain: 'solana' }],
});
```

### Listing a user's wallets

```tsx theme={null}
import { useWallets } from '@moon-x/react-sdk/ethereum';

// PublicWallet[]: address, chain, algorithm. Never key material.
const { wallets } = useWallets();
```

### Importing an existing wallet

Users can bring a wallet they already hold, from either a raw private key or a 12 or 24 word BIP-39 seed phrase, with optional passphrase and account/address index selection matching the derivation conventions of MetaMask, Ledger Live, Phantom, and Solflare. The import runs the split into MPC shares client-side. The plaintext key is never sent to MoonPay and is discarded after the ceremony.

```tsx theme={null}
import { useImportKey } from '@moon-x/react-sdk/ethereum';

const { importKey } = useImportKey();
const { wallet } = await importKey({ key: privateKeyFromUserInput });
```

A `bulkImport` variant imports up to 20 keys, potentially mixing chains, in a single passkey prompt instead of one prompt per key. It returns per-key success and failure detail.

Imported addresses are screened for sanctions and AML risk before the wallet is persisted, the same as newly created ones.

### Exporting a private key

Export is the one flow where a complete private key is ever assembled, and it happens only in the user's own browser after a fresh passkey check. Never on MoonPay servers. This is what keeps the model self-custodial: a user can always take their assets and leave.

```tsx theme={null}
import { useExportKey } from '@moon-x/react-sdk/ethereum';

const { exportKey } = useExportKey();
await exportKey({ wallet: userWallet });
```

<Note>
  Export stays available even to compliance-blocked accounts. Blocking prevents new platform activity, it does not confiscate funds.
</Note>

## Security model

### Passkeys protect the key, not login

A passkey here is not a login method. Users sign in with email OTP or OAuth. Each enrolled passkey wraps the encryption key that protects a user's wallet share, and a fresh passkey assertion proves the user is present for sensitive operations: signing, export, adding a passkey, revoking an agent.

<Danger>
  On passkey-only apps, losing every enrolled passkey with no synced copy means the wallet cannot be recovered. Prompt users to enroll more than one, or enable [identity-backed encryption](#identity-backed-encryption-no-passkey) for a recovery path.
</Danger>

### Identity-backed encryption (no passkey)

An optional second encryption path lets a signed-in session read and write key shares, prove key ownership, and sign, with no passkey prompt. Users can then hold a wallet without ever enrolling a passkey. Enrolling or adding a wrap still takes a passkey assertion or an emailed code, and removing the identity wrap takes a passkey.

This is a different trust trade. The share is wrapped by a cloud KMS key that MoonPay operates, which decrypts only for a request proving it acts for one specific user of one app. MoonPay is therefore in the unwrap path, where passkey wrapping leaves it unable to unwrap at all. Users gain recovery if they lose their passkeys and accept that custody risk. That fits consumer apps where device loss is common. It does not fit applications whose users expect that no party but themselves can ever reach key material.

To run identity-first, ask MoonPay to enable it for your app, then:

* Read `kmsWrapEnabled`, `hasKmsWrap`, and `hasPasskey` from `usePasskeyStatus()`
* Call `enableAccountRecovery()` once per authenticated user who has no wrap yet
* Gate wallet operations on `hasPasskey === true || hasKmsWrap === true`, not on `hasPasskey` alone
* Offer `registerPasskey()` from settings as an optional upgrade

<Info>
  There is nothing to configure in your app. MoonPay enables identity-backed encryption per app during onboarding, and once your app stores its first identity-backed wrap the configuration behind it is fixed. See [Identity-backed encryption](https://x-docs.moonpay.com/wallets/identity-backed-encryption) and [Identity-first setup](https://x-docs.moonpay.com/wallets/identity-first-setup).
</Info>

### Delegated and server-side signing

A user can authorize a scoped, revocable agent identity, such as a trading bot, a payroll scheduler, or an AI agent, to sign on their wallet's behalf without handing over the private key.

Provisioning runs inside an attested secure enclave. The browser verifies the enclave's attestation before sealing key shares to it, and the resulting agent keypair is shown to your app exactly once. Server-side signing then requires two independent credentials, your app's secret key and a signature from the agent's own key, so neither one alone is enough to forge a signature.

The user can revoke any agent at any time via a fresh passkey check.

## Signing and transactions

Every chain exposes chain-specific hooks, imported from `@moon-x/react-sdk/ethereum`, `/solana`, or `/tron`, with a consistent shape. Pass the target wallet and get back a signature, signed transaction, or broadcast result.

### Ethereum and EVM

| Hook                       | Purpose                                                                                                                                                                |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `useSignMessage`           | EIP-191 personal message signing                                                                                                                                       |
| `useSignTypedData`         | EIP-712 structured data signing (permits, meta-transactions, order signing)                                                                                            |
| `useSignHash`              | Raw 32-byte digest signing for custom protocols                                                                                                                        |
| `useSignTransaction`       | Sign without broadcasting                                                                                                                                              |
| `useSendTransaction`       | Sign and broadcast in one call                                                                                                                                         |
| `useSign7702Authorization` | Sign an EIP-7702 authorization, letting an EOA temporarily delegate execution to a smart-contract implementation (account abstraction, gas sponsorship, batched calls) |
| `useSwitchChain`           | Switch the wallet's active EVM network                                                                                                                                 |
| `useGetBalance`            | Read the wallet's native balance                                                                                                                                       |

```tsx theme={null}
import { useSendTransaction } from '@moon-x/react-sdk/ethereum';

const { sendTransaction } = useSendTransaction();

const result = await sendTransaction({
  transaction: { to: '0xRecipient...', value: '0x38d7ea4c68000' },
  wallet: userWallet,
});
```

### Solana

| Hook                                                         | Purpose                                |
| ------------------------------------------------------------ | -------------------------------------- |
| `useSignMessage`, `useSignTransaction`, `useSendTransaction` | Same shape as EVM                      |
| `useGetBalance`                                              | Read the wallet's native SOL balance   |
| `useGetTokenAccounts`                                        | Read SPL token balances for the wallet |

### Tron

| Hook                 | Purpose                                                                |
| -------------------- | ---------------------------------------------------------------------- |
| `useSignMessage`     | TIP-191 message signing                                                |
| `useSignTransaction` | Sign a TronWeb-built transaction. Your app builds it, the wallet signs |
| `useSendTransaction` | Sign and broadcast to a configured Tron fullnode                       |
| `useGetBalance`      | Read the wallet's native TRX balance                                   |

## UI components

Pre-built, brand-customizable modals cover the four sensitive wallet moments: sign message, sign transaction, send transaction, and export key. Each accepts `uiConfig` overrides for title, description, button copy, and success and failure screens, so the confirmation experience matches your product without you building custody UI from scratch.

## Funding: onramp and cash out

A wallet can be funded directly and cashed back out to fiat without the user leaving your app. Both flows run inside the WaaS SDK and do not touch the MoonPay Enterprise API.

* **Card payments (onramp)**: debit and credit card, Apple Pay, Google Pay. Runs on a MoonPay Buy widget session, opened in a managed popup and signed server-side so the wallet address and amount cannot be tampered with after signing.
* **Cash out (offramp)**: the reverse flow. The user sells from their embedded wallet and receives fiat to a card or bank account. The wallet handles the on-chain deposit to the payment provider itself, behind a first-party confirmation the user approves before anything is sent.

Both directions run on your own payment-provider account, with keys configured per environment. Real transfers are mainnet only. Sandbox mode tests the full flow with no real money movement.

## REST API

Wallet creation and signing are MPC ceremonies driven by the client SDK, not single REST calls. Key material only ever exists as shares assembled through the ceremony.

The REST API's role is server-side: querying a user's existing wallets, running compliance actions, and submitting agent-signed requests for delegated signing.

<Info>
  WaaS credentials are issued with your WaaS account, separately from any MoonPay Enterprise API key. Contact your MoonPay representative for the Wallets API reference.
</Info>

## Get started

<Steps>
  <Step title="Request a WaaS account">
    Email [developers@iron.xyz](mailto:developers@iron.xyz) to get set up. WaaS is provisioned on its own, so there is nothing to switch on in the MoonPay Enterprise Partner Dashboard.
  </Step>

  <Step title="Install the SDK">
    Add the React or React Native SDK, point it at your WaaS credentials, and configure the chains you need. See the [SDK documentation](https://x-docs.moonpay.com/get-started/frontend-sdks/react-native/quick-start).
  </Step>

  <Step title="Decide on identity-backed encryption">
    Pick passkey-only for the strongest custody guarantee, or identity-backed to drop the passkey prompt from routine signing. Choose before your first users enroll, since it is provisioned per app up front.
  </Step>

  <Step title="Go live">
    Test wallet creation, signing, import and export, and funding flows in the SDK's sandbox mode before switching to mainnet.
  </Step>
</Steps>

<Card title="Contact sales" icon="envelope" href="https://www.moonpay.com/business/contact?referral=stablecoins" horizontal>
  Tell the team what you are building and which chains you need.
</Card>

<Note>
  Custodial wallets are in development. If you need MoonPay to hold keys on behalf of your users, we are working with a small number of design partners. [Get in touch](https://www.moonpay.com/business/contact?referral=stablecoins).
</Note>
