The Problem: Front-Running
Without encryption, transactions in the mempool are publicly visible before they are included in a block. On AMM pools this means:
- Sandwich attacks: A bot sees your swap, inserts a buy before it and a sell after, profiting at your expense
- Front-running: Bots copy and accelerate profitable transactions
- Transaction snooping: Anyone can see what you are doing before it executes
The Solution: Encrypted Mempool
NEXUS encrypts transactions before submission. The content is hidden from everyone — including node operators — until the miner decrypts and executes it at inclusion time.
You ──encrypt──► mempool (stores encrypted blob) ──decrypt──► miner ──► execute
No one in the middle can see what the transaction does.
Encrypted mempool is live in V1, with protocol version 2. It is particularly important for protecting AMM V3 swaps from sandwich attacks.
How it Works
Encryption (You → Mempool)
1. Generate a random ephemeral keypair (r, R = r×G)
2. ECDH: shared_point = r × protocol_pubkey
3. HKDF-SHA256: symmetric_key = HKDF(
ikm = shared_point.x,
salt = R,
info = "nexus-encrypted-mempool-chacha20poly1305-v2",
len = 32 bytes
)
4. Encrypt with ChaCha20-Poly1305 (RFC 8439):
ciphertext = Encrypt(symmetric_key, nonce, raw_transaction)
5. Transaction ID = SHA256(version || R || ciphertext)
6. Submit: { ciphertext, R, nonce, version, tx_id }
Decryption (Miner, at inclusion)
Only the miner holds the protocol private key. On inclusion:
1. ECDH: shared_point = protocol_privkey × R
2. Derive same symmetric_key via HKDF
3. Decrypt ciphertext → raw transaction
4. Execute
Why ChaCha20-Poly1305?
| Property | Benefit |
|---|
| Authenticated encryption | Detects tampered ciphertexts |
| 256-bit security | Quantum-resistant margin |
| No padding oracles | Safe against adaptive attacks |
| Fast (software-optimized) | Low overhead per transaction |
Using the Encrypted Mempool (TypeScript SDK)
import { encryptTransaction, serializeEncryptedTransaction } from '@yattacorp/nexus-sdk';
// Fetch the protocol's public key
const { pubkey: protocolPubkeyHex } = await client.getProtocolPubkey();
// Serialize your transaction (bincode format)
const rawTx = serializeTransaction(myTransaction);
// Encrypt it
const encrypted = encryptTransaction(rawTx, protocolPubkeyHex);
// Serialize the encrypted envelope (bincode)
const payload = serializeEncryptedTransaction(encrypted);
// Submit — mempool only sees the encrypted blob
await client.submitEncryptedTransaction(payload);
// Track by encrypted transaction ID
console.log('Tx ID:', encryptedTxIdHex(encrypted));
MEV Protection Properties
| Attack | Protected? |
|---|
| Sandwich attacks on AMM swaps | ✅ |
| Front-running profitable calls | ✅ |
| Transaction content snooping | ✅ |
| Replay attacks | ✅ (authenticated ciphertext) |
| Mempool ordering manipulation | ⚠️ Ordering is still visible, content is not |
Encrypted mempool hides transaction content. Transaction ordering within a block is still controlled by the miner. For full ordering protection, combine with private RPC submission (direct to trusted miner).
Cryptographic Details
| Component | Specification |
|---|
| Key agreement | ECDH on secp256k1 |
| Key derivation | HKDF-SHA256 (RFC 5869) |
| Symmetric encryption | ChaCha20-Poly1305 (RFC 8439) |
| Nonce | 12 bytes, random per transaction |
| Auth tag | 16 bytes (Poly1305, appended to ciphertext) |
| Protocol version | 2 |
| Transaction ID | SHA256(version || ephemeral_pubkey || ciphertext) |