Skip to content

Introduce spark accounts#699

Merged
gudnuf merged 19 commits intomasterfrom
introduce-spark-accounts
Dec 5, 2025
Merged

Introduce spark accounts#699
gudnuf merged 19 commits intomasterfrom
introduce-spark-accounts

Conversation

@gudnuf
Copy link
Contributor

@gudnuf gudnuf commented Nov 5, 2025

This is a work in progress spark implementation based on this GDoc.

I've broken each piece up into their own commit

What I've Done

  • Defined a new account type for spark
  • poll spark balance
  • modified the upsert_user_with_accounts function to allow creating a user with just a Spark wallet.
  • Enforce that a user has 1 and only 1 Spark account
  • receive via lightning to a spark account through the UI
  • added spark to our LNURL server

What to do

  • Improve balance tracking so that it updates as soon as a receive completes. We might use the transfer:claimed event for this, but that would only work for receives
  • Implement spark lightning sends
  • Receive cashu tokens to a Spark account
  • Sync Spark transfers to the Agicash transactions table on app load and whenever a send or receive completes

Questions

  • How should we handle the Spark network? I wrote in the doc that we would have an environment variable, but then decided to define the network on the Spark account. If we will always assume mainnet for production then maybe we don't need to put the network on the account record and can just rely on an environment variable to toggle for development

@vercel
Copy link

vercel bot commented Nov 5, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
agicash Ready Ready Preview Comment Dec 4, 2025 10:55pm

@supabase
Copy link

supabase bot commented Nov 5, 2025

Updates to Preview Branch (introduce-spark-accounts) ↗︎

Deployments Status Updated
Database ⚠️ Wed, 05 Nov 2025 22:54:38 UTC
Services ⚠️ Wed, 05 Nov 2025 22:54:38 UTC
APIs ⚠️ Wed, 05 Nov 2025 22:54:38 UTC

Tasks are run on every commit but only new migration files are pushed.
Close and reopen this PR if you want to apply changes from existing seed or migration files.

Tasks Status Updated
Configurations Wed, 05 Nov 2025 22:55:07 UTC
Migrations ⏸️ Wed, 05 Nov 2025 22:52:02 UTC
Seeding ⏸️ Wed, 05 Nov 2025 22:52:02 UTC
Edge Functions ⏸️ Wed, 05 Nov 2025 22:52:02 UTC

❌ Branch Error • Wed, 05 Nov 2025 22:55:08 UTC

unexpected status 403: {"message":"Forbidden resource"}

⚠️ Warning — Service health check failed


View logs for this Workflow Run ↗︎.
Learn more about Supabase for Git ↗︎.

@gudnuf gudnuf self-assigned this Nov 5, 2025
@gudnuf gudnuf added enhancement New feature or request P1 High labels Nov 5, 2025
@gudnuf gudnuf requested a review from jbojcic1 November 5, 2025 22:51
This was referenced Nov 5, 2025
@gudnuf gudnuf force-pushed the introduce-spark-accounts branch from 4c7939c to e89e243 Compare November 26, 2025 00:58
@jbojcic1
Copy link
Collaborator

  • How should we handle the Spark network? I wrote in the doc that we would have an environment variable, but then decided to define the network on the Spark account. If we will always assume mainnet for production then maybe we don't need to put the network on the account record and can just rely on an environment variable to toggle for development

Putting it on the account would allow us to have different accounts for different networks. How likely that is?

unit: getDefaultUnit(commonData.currency),
}),
network: details.network,
isOnline: true,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we make it offline if call to get balance fails?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now the wallet will crash if spark wallet fails to initialize. Instead of setting offline if get balance fails, would it be better to make it so that the wallet doesn't crash if initialization fails, and instead sets offline?

Maybe we should do both.

Btw, sometimes if the Spark infrastructure is having problems while we are in the middle of a receive the SDK will throw and crash the app. It seems like the internal logic of the SDK is throwing when it tries to claim the transfer, but I don't remember exactly

Copy link
Collaborator

@jbojcic1 jbojcic1 Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now the wallet will crash if spark wallet fails to initialize. Instead of setting offline if get balance fails, would it be better to make it so that the wallet doesn't crash if initialization fails, and instead sets offline?

Yeah I would say it's much nicer to show it as offline (Spark being offline shouldn't prevent me from spending my gift card for example). The problem is that we will not know the balance in that case. We could treat it as 0 but users might panic in that case as they would think they lost the money. Alternative is to store the last known balance to local storage (or even our db under account details) and use that and if not present show something other than number.

Btw, sometimes if the Spark infrastructure is having problems while we are in the middle of a receive the SDK will throw and crash the app. It seems like the internal logic of the SDK is throwing when it tries to claim the transfer, but I don't remember exactly

what exactly throws? can we catch it and where?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember, I will have to check next time it happens

unit: getDefaultUnit(commonData.currency),
}),
network: details.network,
isOnline: true,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now the wallet will crash if spark wallet fails to initialize. Instead of setting offline if get balance fails, would it be better to make it so that the wallet doesn't crash if initialization fails, and instead sets offline?

Maybe we should do both.

Btw, sometimes if the Spark infrastructure is having problems while we are in the middle of a receive the SDK will throw and crash the app. It seems like the internal logic of the SDK is throwing when it tries to claim the transfer, but I don't remember exactly

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just looked at this lockfile and saw how much crap was added. Bundlephobia gives an install error for this package, so I asked claude to do some digging.

TLDR; "Spark SDK adds roughly 5.4 MB raw / 3.0 MB gzipped to your client bundle - nearly a 4x increase"

Here's the full convo with some tables comparing with and without spark. The last question I asked output a breakdown of the different packages.

I'm just bringing this up because its very large, but I'm not sure there's anything we can really do. Claude says it pulls in 300-500 kB of node dependencies that are irrelevant for the browser. I think the best we can do is complain to the spark team

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TLDR; "Spark SDK adds roughly 5.4 MB raw / 3.0 MB gzipped to your client bundle - nearly a 4x increase"

That's a lot. Did you try doing a prod build before and after adding it to confirm the num? We should do that before contacting Spark

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea this analysis was from doing bun run build before and after adding it

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets also analyse what this means for the app load on slower (3g and 4g) network. If the difference in load time is not huge I guess we can just ignore it for now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this by emptying the cache and hard reloading then looking at the "Finish time" in the network tab on Brave

Network Speed Without Spark (ms) With Spark (ms) Spark Bundle Load Time (ms)
3G 57,000 100,000  65,000  
Slow 4G 20,000  30,000 18,000 
Fast 4G 6,000  7,690  3,600
No Throttling  1,700  2,500  37

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is Spark Bundle Load Time?

You can do this better with Chrome's lighthouse performance analysis (Chrome dev tools -> Lighthouse tab). There you can see how long does it actually take to load the page, for page to become interactive etc. These are better metrics then just checking the network time because there could be some slow paths in the code that is being executed as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is Spark Bundle Load Time?

The time I observed in the network tab for what I saw of the Spark SDK being downloaded. I see two things on load, one is a spark index.js file and the other is like http://localhost:3000/assets/spark-{some-hash}.js

You can do this better with Chrome's lighthouse performance analysis

Lighthouse says it takes too long without spark on fast 4G and won't give me the full results, so here's with the lighthouse default "Simulated throttling":

Without Spark

image

With Spark

image

@gudnuf
Copy link
Contributor Author

gudnuf commented Nov 27, 2025

  • How should we handle the Spark network? I wrote in the doc that we would have an environment variable, but then decided to define the network on the Spark account. If we will always assume mainnet for production then maybe we don't need to put the network on the account record and can just rely on an environment variable to toggle for development

Putting it on the account would allow us to have different accounts for different networks. How likely that is?

Seems unlikely to me unless Spark started doing stuff on other chains (ie. solana mainnet), but hopefully we wouldn't need to use that even if they did. Otherwise the only reason I see for not using mainnet is testing/dev

@jbojcic1
Copy link
Collaborator

balance doesn't get updated for me. I send 2 sats from Strike and it worked. I got the toast success message but balance was never udpated. Had to reload the app

@jbojcic1
Copy link
Collaborator

  • How should we handle the Spark network? I wrote in the doc that we would have an environment variable, but then decided to define the network on the Spark account. If we will always assume mainnet for production then maybe we don't need to put the network on the account record and can just rely on an environment variable to toggle for development

Putting it on the account would allow us to have different accounts for different networks. How likely that is?

Seems unlikely to me unless Spark started doing stuff on other chains (ie. solana mainnet), but hopefully we wouldn't need to use that even if they did. Otherwise the only reason I see for not using mainnet is testing/dev

lets just keep it as is

@jbojcic1 jbojcic1 force-pushed the introduce-spark-accounts branch from e89e243 to c2e84c9 Compare November 28, 2025 11:32
@jbojcic1
Copy link
Collaborator

I rebased it on top of master to resolve conflicts.

@gudnuf
Copy link
Contributor Author

gudnuf commented Dec 1, 2025

  • How should we handle the Spark network? I wrote in the doc that we would have an environment variable, but then decided to define the network on the Spark account. If we will always assume mainnet for production then maybe we don't need to put the network on the account record and can just rely on an environment variable to toggle for development

Putting it on the account would allow us to have different accounts for different networks. How likely that is?

Seems unlikely to me unless Spark started doing stuff on other chains (ie. solana mainnet), but hopefully we wouldn't need to use that even if they did. Otherwise the only reason I see for not using mainnet is testing/dev

lets just keep it as is

If we just keep it as is, then does that mean that we need to create the account before initializing the spark wallet? If we always use mainnet, then we can initialize spark wallet along with the user's keys because all that is needed is the seed from open secret.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets also analyse what this means for the app load on slower (3g and 4g) network. If the difference in load time is not huge I guess we can just ignore it for now

export async function getSparkIdentityPublicKeyFromMnemonic(
mnemonic: string,
network: NetworkType,
accountNumber?: number,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to make this function not take the network and instead require the accountNumber to be provided? The reason I did it this way is because the spark sdk is not very transparent on which account numbers are used, but it might be better to create a new getDefaultAccountNumberForNetwork helper that needs to be called first then pass that account number to this function?

So I'd change the signature to :

async function getSparkIdentityPublicKeyFromMnemonic(
  mnemonic: string,
  accountNumber: number,
): Promise<string>

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems fine as is

@gudnuf gudnuf marked this pull request as ready for review December 4, 2025 21:48
const cardContent =
accountType === 'spark'
? 'Spark is offline. Your balance will be shown when you are online again.'
: 'Account is offline. Your balance will be shown when you are online again.';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't we show cashu balance even if offline?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea. I just liked this so that the parent component doesn't need to check the account type. Do you have a suggestion to do it differently? We could call this SparkBalanceOfflineHoverCard and then check the account type whenever its used. Or maybe we don't even need to check because only spark balance will be null, but that seems too implicit.

export async function getSparkIdentityPublicKeyFromMnemonic(
mnemonic: string,
network: NetworkType,
accountNumber?: number,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems fine as is

@gudnuf gudnuf merged commit 1080a7c into master Dec 5, 2025
5 checks passed
@gudnuf gudnuf deleted the introduce-spark-accounts branch December 5, 2025 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request P1 High

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants