pub trait LedgerApi: Send + Sync {
// Required methods
fn register_asset<'life0, 'async_trait>(
&'life0 self,
draft: AssetDraft,
) -> Pin<Box<dyn Future<Output = Result<(), ApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait;
fn open_account<'life0, 'async_trait>(
&'life0 self,
draft: AccountDraft,
) -> Pin<Box<dyn Future<Output = Result<(), ApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait;
fn post<'life0, 'async_trait>(
&'life0 self,
draft: TransactionDraft,
) -> Pin<Box<dyn Future<Output = Result<Posted, ApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait;
fn post_batch<'life0, 'async_trait>(
&'life0 self,
drafts: Vec<TransactionDraft>,
) -> Pin<Box<dyn Future<Output = Vec<Result<Posted, ApiError>>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait;
fn balance<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
book: &'life1 str,
path: &'life2 str,
as_of: Option<DateTime<Utc>>,
) -> Pin<Box<dyn Future<Output = Result<BalanceView, ApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait;
fn account_history<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
book: &'life1 str,
path: &'life2 str,
page: Page,
) -> Pin<Box<dyn Future<Output = Result<Paged<PostingView>, ApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait;
fn transaction<'life0, 'life1, 'async_trait>(
&'life0 self,
tx_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<TransactionView, ApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
fn trial_balance<'life0, 'life1, 'async_trait>(
&'life0 self,
book: &'life1 str,
as_of: Option<DateTime<Utc>>,
) -> Pin<Box<dyn Future<Output = Result<TrialBalance, ApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
fn subscribe<'life0, 'life1, 'async_trait>(
&'life0 self,
book: &'life1 str,
from: i64,
) -> Pin<Box<dyn Future<Output = Result<Pin<Box<dyn Stream<Item = Result<EventEnvelope, ApiError>> + Send>>, ApiError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
}Expand description
The full ledger contract. Each transport adapter is a thin translation
onto it: the server implements it over a Store, the client over HTTP —
code written against this trait runs unchanged against either.
Required Methods§
Sourcefn register_asset<'life0, 'async_trait>(
&'life0 self,
draft: AssetDraft,
) -> Pin<Box<dyn Future<Output = Result<(), ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn register_asset<'life0, 'async_trait>(
&'life0 self,
draft: AssetDraft,
) -> Pin<Box<dyn Future<Output = Result<(), ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Register an asset. Idempotent on id: an identical re-registration
succeeds, the same id with a different definition is AlreadyExists.
Crypto assets require a network; precision is immutable forever.
Sourcefn open_account<'life0, 'async_trait>(
&'life0 self,
draft: AccountDraft,
) -> Pin<Box<dyn Future<Output = Result<(), ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn open_account<'life0, 'async_trait>(
&'life0 self,
draft: AccountDraft,
) -> Pin<Box<dyn Future<Output = Result<(), ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Open an account in a book. Idempotent on book+path with the same rule as assets. Book names starting with ‘_’ are reserved.
Sourcefn post<'life0, 'async_trait>(
&'life0 self,
draft: TransactionDraft,
) -> Pin<Box<dyn Future<Output = Result<Posted, ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn post<'life0, 'async_trait>(
&'life0 self,
draft: TransactionDraft,
) -> Pin<Box<dyn Future<Output = Result<Posted, ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Post a balanced transaction (per-asset debits == credits, all
amounts positive). Idempotent on the caller-supplied idempotency key
(unique per book): a replay returns the original Posted with
deduplicated: true and never double-posts — which is what makes
retrying on failure unconditionally safe.
Sourcefn post_batch<'life0, 'async_trait>(
&'life0 self,
drafts: Vec<TransactionDraft>,
) -> Pin<Box<dyn Future<Output = Vec<Result<Posted, ApiError>>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn post_batch<'life0, 'async_trait>(
&'life0 self,
drafts: Vec<TransactionDraft>,
) -> Pin<Box<dyn Future<Output = Vec<Result<Posted, ApiError>>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Post multiple drafts and return one result per input, preserving
input order (out[i] corresponds to drafts[i]).
Positional contract — every draft is attempted independently.
A failure (validation error, unknown account, unbalanced, …) in one
slot sets that slot’s Err; it has no effect on any other slot.
Idempotency deduplication — two drafts with the same idempotency
key, whether within this batch or against historical commits, both
resolve to the original Posted (with deduplicated: true) exactly
as concurrent single post calls would. This is a property of the
per-book write router, not special batch logic.
Empty input returns an empty Vec immediately.
Implementations must preserve input order in the returned Vec.
Sourcefn balance<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
book: &'life1 str,
path: &'life2 str,
as_of: Option<DateTime<Utc>>,
) -> Pin<Box<dyn Future<Output = Result<BalanceView, ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn balance<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
book: &'life1 str,
path: &'life2 str,
as_of: Option<DateTime<Utc>>,
) -> Pin<Box<dyn Future<Output = Result<BalanceView, ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Effective (normal-side-adjusted) balance, rendered as a decimal
string using the asset’s precision. as_of replays by commit time;
None reads the live projection.
Sourcefn account_history<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
book: &'life1 str,
path: &'life2 str,
page: Page,
) -> Pin<Box<dyn Future<Output = Result<Paged<PostingView>, ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn account_history<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
book: &'life1 str,
path: &'life2 str,
page: Page,
) -> Pin<Box<dyn Future<Output = Result<Paged<PostingView>, ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Postings for one account, seq-ascending. page.after_seq is
exclusive (resume with the last seen seq); limit counts
transactions, so one transaction’s postings never split across
pages. Paged::next is None once exhausted.
Sourcefn transaction<'life0, 'life1, 'async_trait>(
&'life0 self,
tx_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<TransactionView, ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn transaction<'life0, 'life1, 'async_trait>(
&'life0 self,
tx_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<TransactionView, ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
A committed transaction by its id (UUID assigned at post time).
Unknown ids are NotFound.
Sourcefn trial_balance<'life0, 'life1, 'async_trait>(
&'life0 self,
book: &'life1 str,
as_of: Option<DateTime<Utc>>,
) -> Pin<Box<dyn Future<Output = Result<TrialBalance, ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn trial_balance<'life0, 'life1, 'async_trait>(
&'life0 self,
book: &'life1 str,
as_of: Option<DateTime<Utc>>,
) -> Pin<Box<dyn Future<Output = Result<TrialBalance, ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Per-asset debit/credit sums for a book, optionally as of commit time. Every line balances when the ledger does.
Sourcefn subscribe<'life0, 'life1, 'async_trait>(
&'life0 self,
book: &'life1 str,
from: i64,
) -> Pin<Box<dyn Future<Output = Result<Pin<Box<dyn Stream<Item = Result<EventEnvelope, ApiError>> + Send>>, ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn subscribe<'life0, 'life1, 'async_trait>(
&'life0 self,
book: &'life1 str,
from: i64,
) -> Pin<Box<dyn Future<Output = Result<Pin<Box<dyn Stream<Item = Result<EventEnvelope, ApiError>> + Send>>, ApiError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Live event stream for a book, starting at seq from (inclusive:
catch-up first, then tail). Delivery is at-least-once; consumers
resume after a disconnect from their last seen EventEnvelope::seq.
The HTTP client implementation does that resumption automatically.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".