create_accounts.rs 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  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. user_data: UserData::default(), // fixed-width correlation slots
  38. metadata: BTreeMap::new(), // free-form key/value metadata
  39. };
  40. ledger.create_account(external).await?;
  41. // Read them back (latest version of each).
  42. println!("accounts:");
  43. let mut accounts = ledger.list_accounts().await?;
  44. accounts.sort_by_key(|a| a.id.0);
  45. for a in &accounts {
  46. println!(" {:?} policy={:?} v{}", a.id, a.policy, a.version);
  47. }
  48. Ok(())
  49. }
  50. /// Open a fresh in-memory SQLite database, run migrations, and wrap it in a
  51. /// `Ledger`. Point the connection string at a file (e.g.
  52. /// `"sqlite://ledger.db?mode=rwc"`) or a Postgres URL for a persistent ledger.
  53. async fn connect() -> Result<Arc<Ledger>, Box<dyn std::error::Error>> {
  54. sqlx::any::install_default_drivers();
  55. let pool = sqlx::any::AnyPoolOptions::new()
  56. .max_connections(1)
  57. .connect("sqlite::memory:")
  58. .await?;
  59. let store = SqlStore::new(pool);
  60. store.migrate().await?;
  61. let ledger = Arc::new(Ledger::new(store));
  62. // On startup, finish any commit a crash interrupted (idempotent roll-forward).
  63. // A clean store has nothing pending, so this returns 0.
  64. ledger.recover().await?;
  65. Ok(ledger)
  66. }