create_accounts.rs 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. //! Connect to a SQLite-backed ledger and create accounts.
  2. //!
  3. //! Run with:
  4. //! ```sh
  5. //! cargo run -p kuatia --example create_accounts
  6. //! ```
  7. use std::collections::BTreeMap;
  8. use std::sync::Arc;
  9. use kuatia::ledger::Ledger;
  10. use kuatia_core::*;
  11. use kuatia_storage_sql::SqlStore;
  12. #[tokio::main]
  13. async fn main() -> Result<(), Box<dyn std::error::Error>> {
  14. let ledger = connect().await?;
  15. // The common case is one line: a version-1 account with the given policy.
  16. ledger
  17. .create_account(Account::new(AccountId::new(1), AccountPolicy::NoOverdraft))
  18. .await?;
  19. ledger
  20. .create_account(Account::new(AccountId::new(2), AccountPolicy::NoOverdraft))
  21. .await?;
  22. // A system account (fees, settlement, market-making) — no balance floor.
  23. ledger
  24. .create_account(Account::new(
  25. AccountId::new(50),
  26. AccountPolicy::SystemAccount,
  27. ))
  28. .await?;
  29. // The same thing spelled out, so you can see every field of an `Account`.
  30. // This boundary account is where value enters/leaves the ledger.
  31. let external = Account {
  32. id: AccountId::new(99),
  33. version: 1, // accounts always start at version 1
  34. policy: AccountPolicy::ExternalAccount, // boundary for deposits/withdrawals
  35. flags: AccountFlags::empty(), // not frozen, not closed
  36. book: DEFAULT_BOOK, // the implicit default book
  37. metadata: BTreeMap::new(), // free-form key/value metadata
  38. };
  39. ledger.create_account(external).await?;
  40. // Read them back (latest version of each).
  41. println!("accounts:");
  42. let mut accounts = ledger.list_accounts().await?;
  43. accounts.sort_by_key(|a| (a.id.id, a.id.sub));
  44. for a in &accounts {
  45. println!(" {:?} policy={:?} v{}", a.id, a.policy, a.version);
  46. }
  47. Ok(())
  48. }
  49. /// Open a fresh in-memory SQLite database, run migrations, and wrap it in a
  50. /// `Ledger`. Point the connection string at a file (e.g.
  51. /// `"sqlite://ledger.db?mode=rwc"`) or a Postgres URL for a persistent ledger.
  52. async fn connect() -> Result<Arc<Ledger>, Box<dyn std::error::Error>> {
  53. sqlx::any::install_default_drivers();
  54. let pool = sqlx::any::AnyPoolOptions::new()
  55. .max_connections(1)
  56. .connect("sqlite::memory:")
  57. .await?;
  58. let store = SqlStore::new(pool);
  59. store.migrate().await?;
  60. let ledger = Arc::new(Ledger::new(store));
  61. // On startup, finish any commit a crash interrupted (idempotent roll-forward).
  62. // A clean store has nothing pending, so this returns 0.
  63. ledger.recover().await?;
  64. Ok(ledger)
  65. }