feat(wallet): encrypt private keys at rest using eth-keystore#45
feat(wallet): encrypt private keys at rest using eth-keystore#45Aboudjem wants to merge 5 commits intoPolymarket:mainfrom
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…g keystore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| let password = crate::password::prompt_new_password()?; | ||
| config::migrate_to_encrypted(&password)?; | ||
| eprintln!("Wallet key encrypted successfully."); | ||
| return config::load_key_encrypted(password.expose_secret()); |
There was a problem hiding this comment.
Redundant costly scrypt decryption after migration
Medium Severity
After migration, resolve_key_string calls config::load_key_encrypted(password.expose_secret()) to decrypt the keystore that was just encrypted moments earlier. Since scrypt is intentionally slow (~1–2 seconds with default parameters), this doubles the wait time during migration. The plaintext key is already available inside migrate_to_encrypted (from load_config()) but is discarded. Having migrate_to_encrypted return the key would avoid the redundant scrypt computation.
Additional Locations (1)
| ); | ||
| } | ||
| Ok((None, KeySource::None)) | ||
| (None, KeySource::None) |
There was a problem hiding this comment.
Config file errors silently swallowed in resolve_key
Low Severity
resolve_key changed from returning Result<(Option<String>, KeySource)> to (Option<SecretString>, KeySource), silently discarding load_config() errors via if let Ok(Some(config)). A corrupted or unreadable config file is now indistinguishable from "no config" — callers like cmd_show and setup::execute will report "not configured" instead of surfacing the actual parse/IO error.


Summary
POLYMARKET_PASSWORDenv var for CI/automationwallet exportsubcommand to decrypt and display key when needed--private-keyflag → env var → auto-migrate → keystore promptChanges
src/password.rssrc/config.rssrc/auth.rssrc/commands/wallet.rscreate/importuse encryption, newexportsubcommandsrc/commands/setup.rsCargo.tomlalloy/signer-keystore,rpassword,rand,secrecyTest plan
cargo clippy -D warnings— cleancargo fmt --check— cleanFixes #18
Note
Medium Risk
Touches wallet key storage and authentication key-resolution paths; while changes are localized, mistakes could lock users out of keys or mishandle secrets during migration/export.
Overview
Private keys are no longer stored in plaintext config. Wallet creation/import now encrypts the key into a
keystore.json(via Alloy keystore) and writesconfig.jsonwith only non-sensitive settings.Key resolution is updated to support password-protected keystores (with retry +
POLYMARKET_PASSWORDenv var) and includes auto-migration from legacy plaintext config on first use. Adds a newwallet exportcommand to decrypt and print the private key, updates setup/wallet flows accordingly, and expands dependencies (alloysigner-keystore,secrecy,rpassword,rand) plus lockfile updates.Written by Cursor Bugbot for commit 52452f6. This will update automatically on new commits. Configure here.