# Livre Wallet

Livre Wallet is a Flutter wallet for Solana privacy workflows. It combines a
public Solana wallet, shielded notes, local note import/export between devices,
desktop-assisted private withdrawals, and public SOL staking controls.

The project is intended to be inspectable and buildable from source. Private
note secrets, wallet seeds, keypair files, and deployment environment files are
not part of the public source release.

## Features

- Solana wallet with public balances and receive addresses.
- Shielded-note UI for supported assets and pools.
- Private note import/export between desktop and iPhone.
- Public SOL staking with separate stake accounts per deposit.
- Stake account discovery from on-chain authorized stake accounts so devices
  converge after refresh.
- Confirmation warnings before staking, unstaking, and stake withdrawals.
- No-Kora direct withdraw mode on desktop: bundled local proving tools read
  Solana RPC, prove locally, sign locally, and submit without a relayer.
- Optional community relayer support for users who deliberately configure one.
- Current devnet fee model: fresh final-fee devnet pools enforce a 0.5%
  protocol deposit fee and a 0.05% withdrawal submitter incentive.
- Mainnet target fee model: fresh pools should use a 0.5% protocol deposit fee
  to the pinned Livre fee wallet, plus a 0.05% relayer/submitter incentive
  when a relayer pays withdrawal gas.
- Fee collector is pinned in-app and does not accept client-provided collector
  overrides.

## Repository Layout

- `lib/` - Flutter application code.
- `assets/` - bundled wallet/proving/web assets.
- `ios/`, `macos/`, `android/`, `linux/`, `windows/`, `web/` - platform
  projects generated and maintained by Flutter.
- `circuits/` - local circuit-related assets.
- `rust/`, `rust_builder/` - Flutter/Rust bridge scaffolding.
- `test/` - unit tests.

## Build Requirements

- Flutter stable SDK.
- Dart SDK bundled with Flutter.
- Xcode and CocoaPods for iOS/macOS builds.
- Android Studio / Android SDK for Android builds.
- Bundled Node/direct-withdraw runtime for desktop no-relayer withdrawals.

## App Configuration

The app uses Dart compile-time environment values:

```bash
--dart-define=SOLANA_RPC_URL=https://api.devnet.solana.com
--dart-define=SOLANA_WS_URL=wss://api.devnet.solana.com
--dart-define=DIRECT_WITHDRAW_RPC_URLS=https://api.devnet.solana.com
--dart-define=KORA_BASE_URL=
```

If no values are provided, the app defaults to Solana devnet RPC/WebSocket
endpoints and no bundled Kora/relayer endpoint. A relayer is optional and must
be configured deliberately with `KORA_BASE_URL` or inside the app.

## Build Instructions

Install dependencies:

```bash
flutter pub get
```

Analyze:

```bash
flutter analyze
```

Run on macOS:

```bash
flutter run -d macos
```

Build macOS release:

```bash
flutter build macos
```

Run on a connected iPhone:

```bash
flutter devices
flutter run -d <DEVICE_ID> --release
```

Build web:

```bash
flutter build web
```

## Emergency Withdrawal

The emergency desktop withdrawal path does not require a Kora backend. The app
uses bundled proving assets and configured Solana RPC endpoints to:

- read pool and commitment data from Solana,
- generate the withdraw proof locally,
- sign with the selected local keypair,
- submit the transaction through RPC.

Private Relay is the preferred withdrawal path because the relayer pays gas.
Emergency Withdrawal exists for recovery/testing when relayers are unavailable.
Do not put wallet seeds, private notes, keypair files, or treasury keys in a
public repository.

## Fee Model

- Current final-fee devnet pools: 0.5% protocol deposit fee and 0.05%
  withdrawal submitter incentive.
- Mainnet target pools: 0.5% of the pool denomination should go to the pinned
  Livre fee wallet.
- Mainnet target relayer incentive: 0.05% of the shielded note value when a
  Private Relay submits the withdrawal and pays gas.
- Emergency Withdrawal: the wallet user pays Solana gas directly, so no relayer
  is required.

## Permissionless Relayers

Livre supports proof-only relayers. A relayer submits the shielded withdrawal
transaction for a user, which lets the recipient wallet receive SOL even if it
has no SOL for gas yet. The wallet proves locally on desktop/mobile and sends
only the finished proof package to a Kora-compatible relayer.

The proof package binds the recipient, nullifier, pool, amount, fee collector,
and relayer address. That means the relayer can pay gas and earn the configured
submitter fee, but cannot redirect funds, change the amount, change the pool, or
spend the note twice.

Anyone should be able to run a relayer. A compatible service should expose:

- `GET /v1/health`
- `GET /v1/pools/config`
- `GET /v1/relayers`
- `POST /v1/pools/<asset>/withdraw/submit-proof`

The wallet remains usable without any relayer because the direct path rebuilds
Merkle data from Solana RPC and submits locally. Kora is convenience and
fee-payer privacy, not a single required server.

See `RELAYER_OPERATOR_GUIDE.md` for the operator quick start and systemd setup.

## Privacy Wait Guidance

The wallet shows a per-note wait score:

- Fresh deposit: withdrawal works, but waiting is recommended.
- Wait recommended: privacy improves as time and later deposits accumulate.
- Better privacy: 10+ later deposits have entered the same pool.
- Strongest window: 24h and 50+ later deposits.

## Contract / Program IDs

Current status: the shielded program fallback is pinned in app configuration.

When mainnet programs are deployed, document them here:

| Network | Program | Program ID | Notes |
| --- | --- | --- | --- |
| Devnet | Livre shield pool | TBD | Pinned in app config |
| Mainnet | Livre shield pool | TBD | Not published yet |

The app currently pins its fee collector fallback in source and ignores remote
`feeCollector` overrides from client config.

## Mainnet Decentralization Plan

- Final fee collector address published before launch.
- Final relayer config documented, with permissionless community relayers.
- Fresh mainnet pools starting from leaf 0.
- Upgrade authority moved to multisig or frozen when ready.
- Source, circuits, proving helper, and release tooling published.
- Static website mirror and download checksums published.

## Security Notes

- Private note sync JSON contains spendable note secrets. Treat it like a
  private key.
- Do not commit `.env`, wallet keypair JSON, mnemonic backups, note-sync JSON,
  or private deployment material.
- Do not rely on `build/`, `.dart_tool/`, `node_modules/`, `ios/Pods/`, or
  `macos/Pods/` as source-of-truth. These are generated locally.
- Use separate test/devnet wallets from production wallets.
- Verify program IDs, RPC endpoints, and any optional relayer endpoints before
  signing real transactions.
- Review all generated transactions before approving them.
- Keep release signing keys outside the repository.
- Pinning a fee collector in the app is not a substitute for on-chain program
  validation. The deployed program should also enforce its own fee-account
  constraints.

## Preparing A Public Source Release

For a clean source release, create a fresh repository without local Git history:

```bash
cp -R /path/to/chanis_wallet /path/to/chanis_wallet_public
cd /path/to/chanis_wallet_public
rm -rf .git build .dart_tool ios/Pods macos/Pods node_modules
git init
git config user.name "Livre Wallet"
git config user.email "dev@chanis.wallet"
git add .
git commit -m "Initial Livre Wallet source release"
```

Before publishing, check for personal or secret material:

```bash
rg -i "seed|mnemonic|private|secret|keypair|personal-name|\\.env"
find . -iname "*.json"
```

Manually inspect any matches before pushing.

## Reproducible Builds

See `Livre_Wallet_REPRODUCIBLE_BUILDS.md` for the intended verification
workflow.

## License

This project is released under the MIT License. See `LICENSE`.
