Skip to content

feat(wallet): replace cocod with coco-core#40

Open
omsant02 wants to merge 4 commits into
Routstr:mainfrom
omsant02:feat/integrate-coco-wallet
Open

feat(wallet): replace cocod with coco-core#40
omsant02 wants to merge 4 commits into
Routstr:mainfrom
omsant02:feat/integrate-coco-wallet

Conversation

@omsant02

@omsant02 omsant02 commented Jun 1, 2026

Copy link
Copy Markdown

Previously routstrd relied on cocod - a separate Cashu wallet daemon for all wallet operations.

Before

routstrd spawns cocod process, talks to it over ~/.cocod/cocod.sock
cocod manages the wallet and reads/writes to ~/.cocod/coco.db

routstrd -> cocod (separate process, Unix socket) -> ~/.cocod/coco.db

After

routstrd uses coco-core library directly in the same process
reads mnemonic from ~/.cocod/config.json, same db at ~/.cocod/coco.db
no separate process, no socket communication

routstrd -> coco-core (same process) -> ~/.cocod/coco.db

Same wallet data, no separate process needed.

Changes

  • added src/daemon/wallet/coco-client.ts which implements the existing
    CocodClient interface using @cashu/coco-core and @cashu/coco-sqlite-bun
  • updated daemon/index.ts to use createCocoClient() instead of createCocodClient()
  • onboard no longer installs @routstr/cocod or runs cocod init,
    generates the mnemonic directly using @scure/bip39 and saves it
    to ~/.cocod/config.json in the same format
  • start command no longer checks if cocod is installed

New dependencies

  • @cashu/coco-core
  • @cashu/coco-sqlite-bun
  • @scure/bip39

Tested

onboard flow, balance reads, and ai requests all working

@omsant02 omsant02 force-pushed the feat/integrate-coco-wallet branch from 30348ef to 2f58137 Compare June 1, 2026 17:09

@sh1ftred sh1ftred left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the PR. Please look into the comments :)

Comment thread src/cli.ts
.option("-y, --yes", "Skip confirmation prompt", false)
.option("--xcashu", "Refund xcashu tokens only (uses refundXcashuTokens)", false)
.action(async (options: { mintUrl?: string; yes: boolean; xcashu: boolean }) => {
await ensureDaemonRunning();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

these changes are just cosmetic. not needed. your formatting is different from mine haha.

Comment thread src/daemon/wallet/coco-client.ts Outdated
},

async getStatus(): Promise<CocodState> {
return "UNLOCKED";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this correct? It literally just says "UNLOCKED" for status?

Comment thread src/daemon/wallet/coco-client.ts Outdated
},

async unlock(_passphrase: string): Promise<string> {
return "already unlocked";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Also this function? Aren't there any coco-core statuses we can return?

@omsant02

omsant02 commented Jun 2, 2026

Copy link
Copy Markdown
Author

hey @sh1ftred

-the formatting issue was prettier auto-formatting on save, reverted the unnccessary changes

-earlier i forgot to document that getstatus() and unlock(), coco-core has no lock/unlock concept at all. checked the full type definitions, there is no LOCKED/UNINITIALIZED state in coco-core. the wallet is always ready once initializeCoco() completes, so returning UNLOCKED is intentional

@sh1ftred

sh1ftred commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

In coco-client.ts, getStatus() returns a hardcoded "UNLOCKED" — previously this was backed by a real HTTP call to the cocod daemon. Three endpoints in src/daemon/http/index.ts depend on this to report actual wallet state (errors, lockout, etc):

  • /wallet/status (line 221) — will never report errors, always returns daemon: "running"
  • /balance guard (line 258) — always passes through, even if wallet is broken
  • /wallet/unlock response (line 338) — always returns state: "UNLOCKED" regardless

Could we at minimum do a lightweight health check here (e.g. a DB ping or balance query) and return "ERROR" if the wallet isn't actually accessible? Something like:

async getStatus(): Promise<CocodState> {
  try {
    await coco.wallet.balances.total();
    return "UNLOCKED";
  } catch {
    return "ERROR";
  }
}

@sh1ftred

sh1ftred commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

My agent wrote that haha.

I think you didn't understand why getStatus exists in the first place.
When you first create a wallet, initializeCoco() will be instantaneous. Because it wouldn't have any lightining invoices to check or any other chores. But as the wallet grows, it will take longer to initialize. That's the it's good to have getStatus because routstrd relies on it.

@omsant02 omsant02 force-pushed the feat/integrate-coco-wallet branch from 255024d to 450e6c2 Compare June 8, 2026 05:09
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.

2 participants