Monorepo for Aesthetic.Computer aesthetic.computer

Keeps Wallet - LLM Context#

Overview#

Tezos wallet for aesthetic.computer "keeps" (NFTs). Two deployment modes:

  1. Integrated - For logged-in prompt.ac users (server-stored encrypted keys)
  2. Extension - Chrome extension for standalone/cross-dApp use

Quick Build#

cd wallet/extension
npm install
npm run build:icons
npm run build
# Load dist/ as unpacked extension in chrome://extensions

Key Concepts#

Keeps#

  • NFTs minted on Tezos via aesthetic.computer
  • Contract: See tezos/keeps.mjs for existing implementation
  • Metadata stored on IPFS

Wallet Architecture#

Extension Mode:
  popup.js <--message--> background.js (has keys) <--taquito--> Tezos RPC

Integrated Mode:
  prompt.ac <--decrypt--> client-side keys <--taquito--> Tezos RPC
                ↑
        encrypted keys from server (user account)

Tezos Key Derivation (lib/crypto.mjs)#

// From 24-word mnemonic to Tezos keypair
mnemonic  seed (bip39)  ed25519 keypair (libsodium)  tz1 address
// Encryption: Argon2id + XChaCha20-Poly1305

Extension Files#

wallet/extension/
├── manifest.json       # Chrome Manifest V3
├── background.js       # Service worker - key mgmt, signing, API calls
├── content.js          # Message relay between page and extension
├── inpage.js           # Creates window.keeps API for dApps
├── popup/
│   ├── popup.html      # Extension popup UI
│   └── popup.js        # Popup logic
├── lib/
│   └── crypto.mjs      # Key derivation, encryption, signing
├── scripts/
│   ├── build.mjs       # esbuild bundler
│   └── generate-icons.mjs
└── dist/               # Built extension (load this in Chrome)
  • tezos/keeps.mjs - Existing keeps contract CLI
  • system/public/aesthetic.computer/disks/wallet.mjs - Wallet UI piece
  • system/public/aesthetic.computer/lib/wallet.mjs - Beacon wallet state

APIs Used#

  • TzKT: https://api.tzkt.io (mainnet), https://api.ghostnet.tzkt.io (testnet)
  • RPC: https://mainnet.api.tez.ie or https://ghostnet.teztnets.com
  • IPFS: https://ipfs.io/ipfs/ for keeps metadata

window.keeps API (injected by extension)#

// Check if extension installed
await keeps.isInstalled()  // true/false

// Get wallet state
await keeps.getState()  // { exists, unlocked, address, network }

// Connect (throws if locked/no wallet)
await keeps.connect()  // returns address

// Get data
await keeps.getBalance()  // { balance: number }
await keeps.getKeeps()    // { keeps: [...] }

// Sign operation
await keeps.sign({ forgedBytes: '...' })  // { signature, signedBytes }

// Listen for lock
keeps.onLocked(() => console.log('Wallet locked!'))

Security Model#

  1. Seed phrase encrypted with Argon2id + XChaCha20-Poly1305
  2. Keys only in memory while unlocked (15 min auto-lock)
  3. Page never sees keys - signs via message passing
  4. User confirmation required for signing (TODO: popup)

Testing#

TODO#

  • Signing confirmation popup
  • Integrated mode (server-side for logged-in users)
  • Connect button in aesthetic.computer (detect window.keeps)
  • Network switching UI in popup
  • Transaction history in popup