-
Notifications
You must be signed in to change notification settings - Fork 44
feat(settings): add vanity wallet generation #536
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caution
Changes requested ❌
Reviewed everything up to 35ab83b in 1 minute and 34 seconds. Click for details.
- Reviewed
526lines of code in7files - Skipped
0files when reviewing. - Skipped posting
0draft comments. View those below. - Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
Workflow ID: wflow_0WECmwX7t9q3f3x4
You can customize by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.
packages/settings/src/settings-feature-wallet-generate-vanity.tsx
Outdated
Show resolved
Hide resolved
beeman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments on how we can simplify the generateVanityKeyPair a bit.
packages/settings/src/ui/settings-ui-wallet-form-generate-vanity.tsx
Outdated
Show resolved
Hide resolved
packages/settings/src/settings-feature-wallet-generate-vanity.tsx
Outdated
Show resolved
Hide resolved
tobeycodes
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really cool. Thanks for the contribution.
packages/settings/src/settings-feature-wallet-generate-vanity.tsx
Outdated
Show resolved
Hide resolved
packages/settings/src/settings-feature-wallet-generate-vanity.tsx
Outdated
Show resolved
Hide resolved
beeman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just tried this locally and the generation works great! I can see myself using this often!
There's one thing I think we should change and that's where this feature is placed.
In this PR, it's placed where we add a Wallet. Currently, a Wallet is a source we can derive accounts from (right now only a mnemonic, soon we'll have hardware wallets).
A Wallet has many Account, either a derived one, you can import a secret key or watch a public key.
At some point, I want to get rid of the requirement of the Wallet being a derivation source and create basically a Wallet that's just a bucket, but this is not something I want to do before adding support for hardware wallets.
With the above in mind, I think it makes most sense to allow people to generate a vanity Account, and place this option inside the Add account screen (and rename the files/routes accordingly).
This should also make it possible to make the Copy & Import work, as the found vanity address can be imported in the active wallet.
Hope this makes sense, happy to answer questions either here or on Discord!
Excited to get this landed!
packages/settings/src/ui/settings-ui-wallet-form-generate-vanity.tsx
Outdated
Show resolved
Hide resolved
packages/settings/src/settings-feature-wallet-generate-vanity.tsx
Outdated
Show resolved
Hide resolved
packages/settings/src/settings-feature-wallet-generate-vanity.tsx
Outdated
Show resolved
Hide resolved
ee778cc to
e6e699a
Compare
ca70c31 to
a780758
Compare
f5c499a to
952484f
Compare
beeman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love this! 🥳
Over to @tobeycodes for a final review.
5271f12 to
80572b3
Compare
|
Been thinking about the naming for this feature and I think Vanity address might not be the best term for users. |
I agree it may not be the most accurate but I think most people know it and refer to it as |
beeman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just gave it another spin on my machine and I'm happy to land this as-is! Wdyt @tobeycodes?
tobeycodes
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Functionality wise this is perfect. Great work!
I left some comments for things I'd like us to improve before merging. I tried to do some of these myself but it seems you have not enabled the setting for maintainers to make edits to your branch.
| const signerStub = { | ||
| address: '11111111111111111111111111111111' as solanaKit.Address, | ||
| keyPair: {} as CryptoKeyPair, | ||
| } as KeyPairSigner |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not use as throughout this PR?
| const hasSuffix = sanitizedSuffix.length > 0 | ||
|
|
||
| if (!hasPrefix && !hasSuffix) { | ||
| const errorMessage: VanityWorkerMessage = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we put each message inside the postMessage call? We don't need to assign this to a variable in memory if we are only using it immediately and once
| worker.onerror = (event) => { | ||
| dispatch({ payload: event.message ?? 'Worker error', type: 'error' }) | ||
| workerRef.current?.terminate() | ||
| workerRef.current = null | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When can this happen if our worker does not throw an error?
| } | ||
| if (type === 'error') { | ||
| dispatch({ | ||
| payload: typeof payload === 'string' ? payload : 'Failed to generate vanity address', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use type inference here? We should know the type of payload within this if statement
|
|
||
| worker.onmessage = (event) => { | ||
| const { type, payload } = event.data ?? {} | ||
| if (type === 'progress' && typeof payload === 'number') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use type inference here and throughout this file? We should not need to check the type of payload when we check the value of type
| } | ||
|
|
||
| const isPending = state.status === 'pending' | ||
| const { attempts: count, error: generationError, result } = state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's call this either attempts or count everywhere. There is no reason to give it a different name here
| return <UiNotFound /> | ||
| } | ||
|
|
||
| const handleCopyAndImport = async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use the use-handle-copy-text hook?
| </AlertDescription> | ||
| </Alert> | ||
|
|
||
| {!result ? ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we reverse the order so it's result ? ... : ...
| {showSecret ? 'Hide' : 'Show'} | ||
| </Button> | ||
| </div> | ||
| {showSecret && ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not use && and use bool ? ... : null throughout the file
tobeycodes
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accidently approved before instead of request changes
Signed-off-by: Juan Sebastian Solano <[email protected]>



Description
This adds a Vanity Wallet creation path to Settings, wiring up the worker based generator, UI form, progress/cancel controls, and copy/import result card. It reuses @workspace/keypair for the underlying keypair work.
Screenshots / Video
Screen.Recording.2025-11-19.at.11.23.56.PM.mov
Important
Adds vanity wallet generation feature with backend logic, worker for async processing, and UI components for user interaction.
generateVanityKeyPairfunction ingenerate-vanity-key-pair.tsto generate key pairs with specific prefixes/suffixes.vanity-worker.tsto handle key pair generation asynchronously, reporting progress and results.generateVanityKeyPair.spec.tsfor testing key pair generation with various conditions.SettingsFeatureWalletGenerateVanitycomponent insettings-feature-wallet-generate-vanity.tsxfor the vanity wallet generation interface.SettingsUiWalletFormGenerateVanityinsettings-ui-wallet-form-generate-vanity.tsxfor user input.settings-ui-wallet-create-options.tsxto include a link to the vanity wallet generation feature.settings-routes.tsxto include a route for the vanity wallet generation feature.This description was created by
for 35ab83b. You can customize this summary. It will automatically update as commits are pushed.