Skip to content

Conversation

@juansebsol
Copy link

@juansebsol juansebsol commented Nov 20, 2025

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.

  • Vanity Wallet Generation:
    • Adds generateVanityKeyPair function in generate-vanity-key-pair.ts to generate key pairs with specific prefixes/suffixes.
    • Implements worker in vanity-worker.ts to handle key pair generation asynchronously, reporting progress and results.
    • Adds generateVanityKeyPair.spec.ts for testing key pair generation with various conditions.
  • UI Components:
    • Introduces SettingsFeatureWalletGenerateVanity component in settings-feature-wallet-generate-vanity.tsx for the vanity wallet generation interface.
    • Adds form component SettingsUiWalletFormGenerateVanity in settings-ui-wallet-form-generate-vanity.tsx for user input.
    • Updates settings-ui-wallet-create-options.tsx to include a link to the vanity wallet generation feature.
  • Routing:
    • Updates settings-routes.tsx to include a route for the vanity wallet generation feature.

This description was created by Ellipsis for 35ab83b. You can customize this summary. It will automatically update as commits are pushed.

Copy link

@ellipsis-dev ellipsis-dev bot left a 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 526 lines of code in 7 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft 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 Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Contributor

@beeman beeman left a 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.

Copy link
Contributor

@tobeycodes tobeycodes left a 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.

Copy link
Contributor

@beeman beeman left a 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.

Image

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).

Image

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!

@juansebsol juansebsol force-pushed the main branch 4 times, most recently from ee778cc to e6e699a Compare November 23, 2025 06:47
@juansebsol juansebsol force-pushed the main branch 2 times, most recently from ca70c31 to a780758 Compare November 23, 2025 07:41
@juansebsol juansebsol force-pushed the main branch 3 times, most recently from f5c499a to 952484f Compare November 23, 2025 08:35
beeman
beeman previously approved these changes Nov 23, 2025
Copy link
Contributor

@beeman beeman left a 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.

@juansebsol
Copy link
Author

juansebsol commented Nov 24, 2025

Been thinking about the naming for this feature and I think Vanity address might not be the best term for users.
I’m considering renaming it to something more user friendly.
Custom Address, Flex Address, Glyph Address, or Tag Address.
Do any of these feel like a better fit? @beeman @tobeycodes

@juansebsol
Copy link
Author

juansebsol commented Nov 24, 2025

Also had a small design idea today, I took a pass at slightly cleaning up the logo and tightening some of the shapes. Not sure if there’s already an updated version in the works, but figured I’d drop it here in case it’s useful.
Happy to share the svg if anyone wants to take a look or iterate on it.

Artboard 1

@beeman
Copy link
Contributor

beeman commented Nov 24, 2025

Been thinking about the naming for this feature and I think Vanity address might not be the best term for users. I’m considering renaming it to something more user friendly. Custom Address, Flex Address, Glyph Address, or Tag Address. Do any of these feel like a better fit? @beeman @tobeycodes

I agree it may not be the most accurate but I think most people know it and refer to it as vanity address. Happy to keep it for now and keep it in the back of our minds if we come up with a better alternative.

@beeman
Copy link
Contributor

beeman commented Nov 24, 2025

Also had a small design idea today, I took a pass at slightly cleaning up the logo and tightening some of the shapes. Not sure if there’s already an updated version in the works, but figured I’d drop it here in case it’s useful. Happy to share the svg if anyone wants to take a look or iterate on it.

Artboard 1

Thanks! I appreciate the suggestion.

For now, we'll stick with the island as-is. Besides figuring out what's the best direction, designing a logo is one thing, applying it everywhere is another.

Once we get funding we'll get a team to create a proper branding, complete with fonts, colors, etc, etc. I already have an agency in mind :)

@tobeycodes
Copy link
Contributor

Also had a small design idea today, I took a pass at slightly cleaning up the logo and tightening some of the shapes. Not sure if there’s already an updated version in the works, but figured I’d drop it here in case it’s useful. Happy to share the svg if anyone wants to take a look or iterate on it.

Artboard 1

Thank you for sharing this! I think it's very cool. When it comes time to work on branding we will definitely want to revisit this. Are you in our Discord? This is definitely the best place to share this sort of stuff.

beeman
beeman previously approved these changes Nov 24, 2025
Copy link
Contributor

@beeman beeman left a 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?

Copy link
Contributor

@tobeycodes tobeycodes left a 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
Copy link
Contributor

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 = {
Copy link
Contributor

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

Comment on lines +113 to +117
worker.onerror = (event) => {
dispatch({ payload: event.message ?? 'Worker error', type: 'error' })
workerRef.current?.terminate()
workerRef.current = null
}
Copy link
Contributor

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',
Copy link
Contributor

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') {
Copy link
Contributor

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
Copy link
Contributor

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 () => {
Copy link
Contributor

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 ? (
Copy link
Contributor

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 && (
Copy link
Contributor

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 tobeycodes self-requested a review November 25, 2025 02:13
Copy link
Contributor

@tobeycodes tobeycodes left a 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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants