MEW Wallet → MoonPay URL Decrypt

MEW Wallet obfuscates MoonPay purchase URLs using a 3-layer anti-bot scheme.
This doc explains the decryption flow step by step so your dev can replicate it in any language.

Architecture

LayerWhat it does
1. MEW /buy endpointReturns a form URL with a short-lived token
2. MEW /form/moonpayReturns obfuscated JS — XOR arrays + positions + verify token
3. MEW /form/verifyReturns XOR key k after server-side validation
XOR decryptClient-side: XOR arrays with key → positions → MoonPay URL

Step-by-step (cURL)

Step 1 — Hit MEW /buy to get the form token

This returns JSON with all provider entries. Grab the MoonPay form URL.

curl -s 'https://mainnet.mewwallet.dev/v5/purchase/buy?id=0x7dcf9a8ebbb9f59881ed9d64d30a22e64af2e6cb&address=YOUR_WALLET&fiatCurrency=USD&amount=150&cryptoCurrency=USDC&chain=POL&iso=US&platform=web' \
  -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36' \
  -H 'Accept: */*'

Extract: .url field from the MOONPAY entry → parse token=XYZ from it.

Step 2 — Fetch the obfuscated JS from /form/moonpay

Request the form page with the token. Extract the inline <script> tag.

curl -s 'https://mainnet.mewwallet.dev/v5/purchase/form/moonpay?token=TOKEN_FROM_STEP1' \
  -H 'User-Agent: Mozilla/5.0 ...' \
  -H 'Referer: https://mainnet.mewwallet.dev/v5/purchase/buy?...'

Parse from the script tag:

Step 3 — Call /verify to get XOR key k
curl -s 'https://mainnet.mewwallet.dev/v5/purchase/form/verify?token=VERIFY_TOKEN' \
  -H 'User-Agent: Mozilla/5.0 ...' \
  -H 'Referer: https://mainnet.mewwallet.dev/v5/purchase/buy?...' \
  -H 'Origin: https://mainnet.mewwallet.dev'

Response: {"k": "abc123...", ...}

Step 4 — XOR decrypt

With arrays, positions, and k:

  1. For each pair in arrays: XOR each substring with key k at the corresponding index
  2. Using the result + positions, pick characters out of the decoded result to build the final URL

See decrypt.js for the exact algorithm — it's the same for all providers.

Node.js Decryptor (decrypt.js)

Pass JSON on stdin: {"arrays": [...], "positions": "...", "k": "..."}

echo '{"arrays":[[...],[...]],"positions":"...","k":"..."}' | node decrypt.js

Output: the fully resolved MoonPay purchase URL.

Key files

FilePurpose
decrypt.jsXOR decryptor (Node.js, no deps)
server.pyFlask server — orchestrates steps 1-4, exposes /api/generate
index.htmlWeb UI (standalone — works locally without server)

Running locally

cd mew-moonpay-generator
python3 server.py                     # Flask on :8080 — needs decrypt.js + internet
# OR just open index.html in browser  # standalone — calls the same /api/generate
The /verify endpoint validates Origin/Referer headers and the token is single-use. Each generate call produces a fresh MoonPay URL. MoonPay URLs expire after ~10 minutes.

Python (no Node.js) Porting Guide

If you want to skip Node.js, the XOR decrypt is trivial to port:

import json

def xor_decrypt(arrays, positions, k):
    results = []
    for pair in arrays:
        parts = []
        for i, s in enumerate(pair):
            key_char = k[i % len(k)]
            decoded = ''.join(chr(ord(c) ^ ord(key_char)) for c in s)
            parts.append(decoded)
        results.append(''.join(parts))

    # Build URL from decoded results and position instructions
    url = ''
    for pos in positions.split(','):
        num = int(pos)
        which = ''  # positive → result index, negative → char index
        url += results[abs(num)]
    return url

Exact implementation is in decrypt.js — translate the 15-line function.