Contributing Guide
How to add new wallets and contribute to the comparison
Summary: How to add new wallets and contribute to the comparison
Keep the tables accurate and sourced. Tables are the source of truth.
Quick Links
Software Wallets (EVM)
- Main comparison: SOFTWARE_WALLETS.md | Details
- Refresh script: scripts/refresh-github-data.sh
Hardware Wallets (Cold Storage)
- Hardware comparison: HARDWARE_WALLETS.md | Details
- Refresh script: scripts/refresh-hardware-wallet-data.sh
Crypto Cards
- Card comparison: CRYPTO_CARDS.md | Details
Ramps (On/Off-Ramp Providers)
Score Sync Workflow
Scores and recommendation cells are generated from the visible table columns. Do not hand-edit the score cells unless you are also changing the underlying data.
Run this after any change to the comparison tables:
bun scripts/sync_table_scores.js --write
cd frontend
bun test
What this does:
- Recomputes
Scoreand recommendation cells for software wallets, hardware wallets, cards, and ramps. - Sorts rows by computed score.
- Refreshes the generated snapshot blocks near the top of the matching
*_DETAILS.mdfiles. - Fails the frontend smoke test if the markdown tables drift from the generated output.
Current methodology version: 2026-04-visible-columns-v3 (SCORING_METHODOLOGY_VERSION in frontend/src/lib/scoring.js).
How the Rec mark is set
The Rec mark is a rank band, not a fixed score cutoff. assignRecommendationBands in frontend/src/lib/scoring.js sets it per table every time the sync script or the site build runs:
- Inactive rows are 🔴 Avoid, whatever their score.
- Software wallets only: a row with Core not full, or Developer Safety & Control of 10 or less, is ⚪ Not for dev.
- The remaining rows (N of them) are sorted by score, lowest first. The bottom
floor(N × 0.25)are 🔴 Avoid, the rows up tofloor(N × 0.5)are 🟡 Situational, and the rest are 🟢 Recommended. Rows with equal scores keep their table order, so the cutoffs are rounded down and ties are not split by any other rule. - A row with status "launching" cannot be 🟢. It is capped at 🟡.
So the same score can land in different bands in different tables, and in the same table after other rows change. Never write a Rec by hand.
Adding a New Software Wallet
Prerequisites
Before adding a wallet, verify:
- ✅ It's an EVM-compatible wallet (Ethereum, Polygon, Arbitrum, etc.)
- ✅ It has been publicly released (not alpha/private beta)
- ✅ It has a GitHub repo OR is a well-known proprietary wallet
Step 1: Gather Required Data
| Column | How to Verify |
|---|---|
| Score | Generated from the visible columns after sync |
| GitHub | Find the main wallet repo (not SDK/packages) |
| Active | Check last commit date on default branch |
| Chains | Count from official docs or registry files |
| Devices | Check app stores + Chrome Web Store |
| Testnets | Check if custom RPC/chains can be added |
| License | Read LICENSE file in repo root |
| Audits | Search repo for /audits folder or security page |
| Funding | Research company backing, funding rounds |
| Tx Sim | Test wallet or check WalletBeat |
| Scam | Test wallet or check WalletBeat |
| Account Type | EOA, Safe, EIP-4337, or EIP-7702 |
| HW Wallets | Check settings for Ledger/Trezor support |
| EIP-4337 | Check if smart account creation is supported |
| Best For | Your assessment of ideal use case |
| Rec | Generated from the computed score and activity status |
Step 2: Fill The Scoring Inputs
Software wallet scores are generated from the visible columns in frontend/src/lib/scoring.js. The current categories are:
Core Readiness
Release Discipline
Developer Safety & Control
Ecosystem & Accounts
Transparency & Access
Maintenance & Assurance
If you want to change the formula, update the scoring code first, then rerun the sync script.
Step 3: Add to Main Table
Add your row to data/tables/SOFTWARE_WALLETS.md. Ordering does not need to be perfect before sync because the score script will sort rows automatically.
| **WalletName** | XX | [repo](https://github.com/org/repo) | ✅ | 50+ | 📱🌐 | ✅ | ✅ MIT | ✅ 2024 | 🟢 Company | ✅ | ✅ | EOA | ✅ Multiple | ❌ | Use Case | 🟢 |
Step 4: Update Other Sections
If applicable, also update:
- Scoring table (if in top 10)
- Security Audits table (if audited)
- Account Type Support table
- Hardware Wallet Support table
- ENS & Address Resolution table
- Browser Integration table
- Monetization table
- Privacy & Data Collection table
Adding a New Hardware Wallet
Prerequisites
Before adding a hardware wallet, verify:
- ✅ It's an actual hardware device (not software/mobile wallet)
- ✅ It's commercially available (not crowdfunding/prototype)
- ✅ It stores private keys on device (true cold storage)
Step 1: Gather Required Data
| Column | How to Verify |
|---|---|
| Score | Generated from the visible columns after sync (see hardware wallet scoring) |
| Air-Gap | Check if device requires USB/BT connection during signing |
| Open Source | Find firmware repo on GitHub; verify it's actual firmware, not just SDK |
| Secure Element | Check official specs for SE chip (e.g., ATECC608, Optiga) |
| Display | Screen type, size, touch capability |
| Chains | Count from official supported assets list |
| Price | Check official store (not Amazon/resellers) |
| Connectivity | USB, Bluetooth, QR, NFC, MicroSD, WiFi |
| Company | Research company background, funding, location |
Hardware Wallet Scoring
Hardware scores are generated by computeHardwareScore in frontend/src/lib/scoring.js from the visible columns. Do not calculate them by hand. The categories and their maximum points (100 in total):
Security Architecture 34
Transparency & Maintenance 28
Usability & Value 32
Company Track Record 6
The Founded and Funding columns feed Company Track Record, and the Price column feeds Usability & Value. The Rec mark follows the rank bands. If you want to change the formula, update the scoring code first, then rerun the sync script.
Step 2: Add to Main Table
Add your row to data/tables/HARDWARE_WALLETS.md in score order:
| [**WalletName**](https://example.com/) | 0 | [firmware](https://github.com/org/repo) | ✅/❌ | ✅/⚠️/❌ | ✅/❌ SE Type | Display | ~$XXX | Conn | ✅/⚠️/❌/🔒 | YYYY | 🟢/🟡/🔴 Source | 🔴 |
Notes:
FoundedandFundingare now required hardware scoring inputs.- Keep placeholder score/recommendation (
0/🔴) and runbun scripts/sync_table_scores.js --write.
Step 3: Update Other Sections
If applicable, also update:
- Scoring breakdown table
- GitHub Metrics table (if open source)
- Security Features table
- Funding section
- Known Quirks section
- Software integration tables
- Changelog — Add entry to CHANGELOG.md
Step 4: Run Verification
cd scripts
./refresh-hardware-wallet-data.sh --markdown
Adding a New Ramp Provider
Prerequisites
Before adding a ramp provider, verify:
- ✅ It's a legitimate on-ramp and/or off-ramp service (not just a wallet feature)
- ✅ It's publicly available (not private/enterprise-only without public docs)
- ✅ It has developer documentation or API/SDK available
Step 1: Gather Required Data
| Column | How to Verify |
|---|---|
| Score | Generated from the visible columns after sync (see ramp scoring) |
| Type | Both, On-Ramp only, or Off-Ramp only |
| On-Ramp | ✅ if supports fiat → crypto, ❌ otherwise |
| Off-Ramp | ✅ if supports crypto → fiat, ❌ otherwise |
| Coverage | Check official docs for supported countries/regions |
| Fee Model | Check pricing page or API docs |
| Min Fee | Check pricing page (use ~ prefix if approximate) |
| Dev UX | Check developer docs (SDK, Widget, API) |
| Status | ✅ Active, ⚠️ Verify (needs verification), 🚧 Launching |
| Best For | Your assessment of ideal use case |
| Rec | Generated by the rank bands (see How the Rec mark is set) |
| URL | Official website URL |
Ramp Scoring
Ramp scores are generated by computeRampScore in frontend/src/lib/scoring.js from the visible columns. Do not calculate them by hand. The categories and their maximum points (100 in total):
Coverage 25
Product Breadth 15
Developer UX 18
Pricing Shape 25
Operational Confidence 15
Company Track Record 2
Operational Confidence comes from the Status column: 15 for active, 9 for verify, 5 for launching, 0 otherwise. Pricing Shape adds the Fee Model and Min Fee points. The Rec mark follows the rank bands. Inactive and launching rows are handled by the band rules.
Step 2: Add to Main Table
Add your row to data/tables/RAMPS.md in score order (highest first):
| [**ProviderName**](https://provider.com/) | XX 🟢 | Both | ✅ | ✅ | ~160+ Countries | Medium | ~$5.00 | Excellent (React SDK) | ✅ | Developers |
Important: Use markdown link format [**Name**](url) for provider name to enable clickable links.
Step 3: Update Other Sections
If applicable, also update:
- Provider-Specific Notes section
- Fee Analysis section
- Developer Experience section
- Changelog — Add entry to CHANGELOG.md
Step 4: Frontend Integration
When adding a new comparison type (like ramps), you must update:
4a. Type Definitions (frontend/src/types/wallets.ts)
- Add interface (e.g.,
Ramp) with all required fields includingurl: string | null - Add to
WalletDataunion type
4b. Data Parsing (frontend/src/lib/wallet-data.ts)
- Add parsing function (e.g.,
parseRamps()) - Extract name and URL from markdown links:
[**Name**](url) - Add to
getAllWalletData()return object - Export parsing function
4c. Filtering (frontend/src/lib/wallet-filtering.ts)
- Add filtering function (e.g.,
filterRamps()) - Map status types correctly if different from filter types
- Export filtering function
- Add to
wallet-data.tsexports
4d. Components
- WalletTable.tsx: Add item component (e.g.,
RampItem) for table/grid views - ComparisonTool.tsx: Add comparison component (e.g.,
RampComparison) - WalletFilters.tsx: Add filter options if needed
- ExploreContent.tsx: Add tab, state management, filtering
4e. Pages
- explore/page.tsx: Call parsing function, pass to ExploreContent
- docs/[slug]/page.tsx: Add to
isTablePagecheck - sitemap.ts: Add to
isComparisonTablecheck
4f. Navigation (See Rule #127)
- Navigation.tsx: Add to burger menu
- Footer.tsx: Add to Comparisons section
- InternalLinks.tsx: Add card to FeaturedCategoryLinks
- page.tsx: Add to hero section, stats section, Top Developer Picks
4g. SEO (frontend/src/lib/seo.ts)
- Add OG image mappings for table and details pages
- Add keyword detection for new type (e.g., ramp-specific keywords)
- Update ItemList schema to handle new type correctly
4h. OG Images (frontend/scripts/generate-og-images.js)
- Add data to
WALLET_DATAobject - Create generator function for table image
- Create generator function for details image
- Add to
main()function - Run
bun run generate-ogand commit PNGs - Update CI workflow to check for new images
4i. Markdown Config (frontend/src/lib/markdown.ts)
- Add file to
DOCUMENT_CONFIG - Add to
relatedMapfor table/details navigation
Step 5: Verification
cd frontend
bun run type-check # Verify TypeScript
bun run lint # Verify linting
bun run build # Verify build
bun run generate-og # Regenerate OG images
Adding a New Crypto Card
See existing data/tables/CRYPTO_CARDS.md for card-specific guidelines. Follow similar pattern to software/hardware wallets.
Updating Existing Data
Activity Status Updates
For Software Wallets:
cd scripts
./refresh-github-data.sh --markdown
For Hardware Wallets:
cd scripts
./refresh-hardware-wallet-data.sh --markdown
If a wallet's status changes, update:
- Main table
Activecolumn (or strikethrough if abandoned) - GitHub Metrics table
- Recalculate score if needed
- Add changelog entry to CHANGELOG.md
Audit Updates
When a wallet publishes a new audit:
- Update
Auditscolumn in main table - Update Security Audits section
- Recalculate score if applicable
- Add changelog entry to CHANGELOG.md
Verification Standards
What Requires Verification
| Claim | Verification Method |
|---|---|
| License | Read LICENSE file in repo |
| Activity | Check last commit via GitHub API |
| Chain count | Official docs or registry file |
| Audit | Link to audit report |
| Funding | Press releases, Crunchbase, etc. |
| Ramp coverage | Official docs or API documentation |
| Ramp fees | Pricing page or API docs |
What Doesn't Require Verification
- Feature claims from official docs (trust but verify when possible)
- WalletBeat data (already verified)
- GitHub stars/issues (automated)
Pull Request Template
Use this template for your PR:
## New [Wallet/Card/Ramp]: [Name]
### Data Sources
- GitHub: [link] (if applicable)
- Official docs: [link]
- WalletBeat: [link if available]
### Verification
- [x] GitHub repo verified (if applicable)
- [x] Last commit date checked: YYYY-MM-DD (if applicable)
- [x] License verified: [LICENSE] (if applicable)
- [x] Chain count verified: [N] chains (if applicable)
- [x] Score calculated: XX/100
### Score Breakdown
- [Component 1]: XX/pts
- [Component 2]: XX/pts
- **Total: XX/100**
### Changes
- Added row to main comparison table
- Added to [list other sections updated]
- Updated [CHANGELOG.md](./CHANGELOG.md)
- Updated frontend (if new comparison type)
Renaming Files or Changing URLs
⚠️ IMPORTANT: Changing file names or URL slugs requires updates across the whole codebase. Follow this checklist to avoid breaking links and SEO.
When to Rename
Only rename files/URLs if:
- URLs are too long or unclear (e.g.,
wallet-comparison-unified-table→software-wallets) - File names don't match the URL pattern
- You're consolidating multiple files into a clearer structure
File Naming Convention
Comparison pages follow this pattern:
- Table view:
CATEGORY.md→/docs/category(e.g.,data/tables/SOFTWARE_WALLETS.md→/docs/software-wallets) - Details view:
CATEGORY_DETAILS.mdrenders inside the category page at/docs/category/#details(e.g.,data/tables/SOFTWARE_WALLETS_DETAILS.md→/docs/software-wallets/#details)
Slug generation formula: filename.replace('.md', '').toLowerCase().replace(/_/g, '-')
Rename Checklist
When renaming files or changing URL patterns, you MUST update:
1. File System
- Rename markdown files
- Verify files exist in correct location
2. Frontend Configuration (frontend/src/lib/markdown.ts)
- Update
DOCUMENT_CONFIGwith new file names - Verify slug generation matches expected URLs
- Update
relatedMapingetRelatedDocument()function - Update
getWalletStats()function if it references specific slugs
3. SEO & Metadata (frontend/src/lib/seo.ts)
- Update
getOgImagePath()mapping for new slugs - Verify OG image paths are correct
- Check that image files exist in
public/directory - Add keyword detection if needed
4. Frontend Components
- Update
Navigation.tsxnav items - Update
Footer.tsxlinks - Update
InternalLinks.tsx(FeaturedCategoryLinks) - Update
page.tsx(homepage links and structured data) - Update any page-specific links (e.g.,
companies/page.tsx)
5. Page Logic (frontend/src/app/docs/[slug]/page.tsx)
- Update table/details detection logic
- Verify
isTablePageandisDetailsPagedetection - Update
RelatedDocumentscomponent logic if needed - Update ItemList schema to handle new type correctly
6. Sitemap (frontend/src/app/sitemap.ts)
- Update
isComparisonTabledetection logic - Verify priority logic still works correctly
7. Data Parsers (frontend/src/lib/wallet-data.ts)
- Update file paths in parsing functions
- Update any comments referencing old file names
8. Scripts
- Update
scripts/generate-og-images.jsfile references and comments - Update
scripts/smoke-test-wallet-data.jsfile paths - Verify any other scripts that reference file names
9. Documentation
- Update
frontend/README.mdfile mapping table - Update
README.md(root) file references - Update internal markdown links in comparison files
- Update
CONTRIBUTING.mdif it references specific files
10. Verification
- Run verification script to check file existence
- Verify slug generation produces expected URLs
- Test related document mapping (table ↔ details)
- Check for any remaining old references:
rg -n "old-name" frontend/ - Verify no broken internal links in markdown files
- Run
bun run type-check,bun run lint,bun run build
SEO Considerations
When changing URLs, be aware:
-
Broken External Links: Old URLs will 404 unless you add redirects
- Consider adding Next.js redirects in
next.config.jsif URLs are public-facing - Update any social media posts or external documentation
- Consider adding Next.js redirects in
-
OG Images: Social media caches OG images
- Increment
ogImageVersioninlayout.tsxwhen regenerating images - Verify OG image paths match new slugs
- Increment
-
Sitemap: Search engines need updated sitemap
- Sitemap auto-generates from
getAllDocuments(), so it updates automatically - Verify sitemap priorities are correct for new naming pattern
- Sitemap auto-generates from
-
Structured Data: Schema.org markup includes URLs
- Verify structured data URLs in
page.tsxmatch new slugs - Check breadcrumb and article schema URLs
- Verify structured data URLs in
Example: Complete Rename Workflow
# 1. Rename files
mv OLD_NAME.md NEW_NAME.md
mv OLD_NAME_DETAILS.md NEW_NAME_DETAILS.md
# 2. Update frontend config
# Edit frontend/src/lib/markdown.ts: DOCUMENT_CONFIG
# 3. Update all references
# Edit: seo.ts, Navigation.tsx, Footer.tsx, etc.
# 4. Verify
cd frontend
bun run type-check
bun run lint
bun run build
Testing After Rename
- Build check:
cd frontend && bun run build - Type check:
cd frontend && bun run type-check - Lint check:
cd frontend && bun run lint - Smoke test:
cd frontend && bun run test - Manual verification: Check that all URLs load correctly
Adding a New Comparison Type
See docs/ADDING_A_CATEGORY.md for the checklist. For card re-verification passes see docs/CARD_RESWEEP_RUNBOOK.md.
Questions?
Open an issue if you're unsure about:
- How to classify a wallet's license
- What activity status to assign
- How to score a particular feature
- How to rename files without breaking links
- How to add a new comparison type
We're happy to help!