Greed Terminal

Your positions. Your keys. Our servers can't read either at rest.

Greed Terminal is a free portfolio view across Kalshi, Gemini Predictions and Polymarket. Sign in with a passkey. Your exchange API keys are encrypted in your browser with a key that only your passkey can produce, and they are never stored in cleartext on our side.

Create account with a passkeyNo email. No password. Free.

Stored

Ciphertext only. Your vault key, exchange credentials and cached exchange data are AES-256-GCM encrypted with keys we never hold.

In flight

To talk to an exchange, your browser decrypts the credential and sends it over TLS, through our CDN (Cloudflare), to our relay. It exists in memory for one request, then it's dropped.

Never

Credentials, cache keys and exchange responses are never logged, never written to disk in cleartext, and never sent anywhere except through our CDN and relay to the exchange they belong to.

1. Sign-in is a passkey

There is no password to leak and no email to phish. Your account is a passkey (WebAuthn, user verification required) stored in iCloud Keychain, Google Password Manager, 1Password, Bitwarden or a hardware security key. We store its public key.

The same passkey also unlocks your vault. Through the WebAuthn PRF extension your authenticator derives a secret from a fixed input. Only that passkey can compute it, it is computed on your device, and it is never sent to us. Without it the vault can't be opened, by you or by us.

2. The key hierarchy

  your passkey (Face ID / Touch ID / security key)
        │  WebAuthn PRF extension: a secret only this passkey can produce,
        │  computed on your device, never sent to us
        ▼
  wrapping key ── HKDF-SHA256
        │  decrypts (AES-256-GCM)
        ▼
  vault key ───── random 256-bit key, created in your browser at sign-up
        │                      stored by us only in wrapped (encrypted) form
        ├── HKDF ──▶ item key   encrypts your exchange credentials (browser only)
        └── HKDF ──▶ cache key  encrypts cached exchange data (sent per request)

Every ciphertext is bound to your account and to its slot through AES-GCM additional data, so blobs can't be swapped between users or items. Unlocking happens in the tab; the vault locks itself after 15 minutes of inactivity, when you click Lock, or when you close the tab.

3. What happens on every exchange request

  browser               Cloudflare          terminal.greed.bot relay           exchange
  ───────               ──────────          ────────────────────────           ────────
  decrypt credentials
  with item key
        │  TLS 1.2+     CDN / DDoS edge     in memory only:
        ├─────────────▶ re-encrypts ──TLS─▶ sign request with your key ──────▶ Kalshi
        │  credentials  to our origin       (fixed hosts, fixed endpoints)     Gemini
        │  + cache key                                                         Polymarket
        │                                   encrypt the response with
        │                                   your cache key, store ciphertext
        │◀─────────────────────────────────  return positions
  render portfolio                          drop credentials + cache key

Exchanges authenticate with request signatures that need your secret, and order entry needs the same credential, so every exchange call goes through one path: cleartext in flight only. The relay:

4. Cached exchange data follows the same rule

To keep the terminal fast and stay inside exchange rate limits, the latest snapshot of each account is cached for up to 24 hours. Your browser sends the cache key alongside the credential. The relay derives an encryption key and an HMAC key from it, stores the snapshot as AES-256-GCM ciphertext, and indexes it by an HMAC of the account ID. Without your cache key we can't read a cached snapshot or tell which account it belongs to.

5. What our database actually contains

DataStored asReadable by us?
Accountrandom ID, creation timeyes (no name, no email)
Passkeycredential ID, public key, signature counteryes, but these are public values
Vault keyAES-256-GCM ciphertext under your passkey's PRFno
Exchange credentials, labels, exchange namesAES-256-GCM ciphertext under your item keyno
Cached positions & balancesAES-256-GCM ciphertext under your cache key, HMAC-indexed, expires in 24hno
SessionsSHA-256 of a random token, expires in 12hhash only

"Delete account" removes all of it immediately.

6. What this design can't protect you from

7. Connecting exchanges

KalshiAccount → API keys → create a key. Paste the key ID and the private key (PEM). RSA and Ed25519 keys are supported. Use a dedicated key, with a read-only scope if your account offers one.
GeminiCreate an API key with the Trader role (required by Gemini's positions endpoint), time-based nonce, and no fund-management permissions. Add 136.90.85.84 to the key's trusted IPs.
PolymarketPaste your profile (proxy wallet) address. Positions are public on-chain data, so we never ask for a Polymarket private key. The address is still encrypted in your vault, because it links you to your positions.

Requirements

A current browser and a passkey provider that supports the WebAuthn PRF extension: iCloud Keychain (iOS / macOS 18+), Google Password Manager (Chrome), 1Password, Bitwarden, or a FIDO2 security key with hmac-secret. Older browsers are intentionally unsupported.

Open Terminal →