/** * @pwngh/economy-lab * * Copyright (c) Preston Neal * * This source code is licensed under the MIT license found in the * LICENSE.md file in the root directory of this source tree. * * @license MIT */ /** * The sole source of account ids: user wallets (`usr_...:spendable|earned|promo`), the platform's * SYSTEM accounts, and the shard routing that splits hot platform accounts across rows. Also owns * account classification (custodial vs house) and the per-operation lock sets. */ import type { Currency } from './money.js'; import type { Operation } from './contract.js'; /** * The kinds of account a single user can have. This is a category, not a currency. The * currency of any money movement comes from the amount's own `Currency`. * * @see {@link https://economy-lab-docs.pages.dev/economy/concepts/accounts-and-double-entry/ * Accounts & double-entry} for how these accounts and their normal sides balance. */ export type AccountKind = 'spendable' | 'earned' | 'promo' | 'escrow'; /** * A branded account identifier string, so a plain string can't be used as an account. The only * sources are the functions in this file and the `SYSTEM` accounts below, so every id is * well-formed by construction. */ export type AccountRef = string & { readonly __brand: 'AccountRef'; }; /** * A user's spendable account: money they topped up and can spend. Backed by real USD held * in trust. */ export declare function spendable(userId: string): AccountRef; /** * A session escrow account: the prefund lane's crash-safe attribution. The account key is the * (user, session) pair, so recovery derives the unspent remainder from durable postings plus * the journal — no session-memory truth anywhere. Funded from `spendable` at session first * touch, drained by the session settlement, remainder refunded to `spendable` at close (see * src/instance.ts prefund). */ export declare function sessionEscrow(userId: string, sessionId: string): AccountRef; /** * Parses a session-escrow id back into its (user, session) pair, or null for any other account — * what the orphan-escrow sweep uses to find each remainder's owner. */ export declare function escrowPartsOf(ref: AccountRef): { userId: string; sessionId: string; } | null; /** * A user's earned account: revenue owed to them as a seller, which the platform must pay out. * Cashing out goes through `requestPayout`, which moves earned money into the payout reserve; * earned balances class as `excluded` in the backing check, so only the custodial spendable * side raises the required trust cash. */ export declare function earned(userId: string): AccountRef; /** * A user's promo account: a marketing grant that expires. Its offsetting entry sits in * `SYSTEM.PROMO_FLOAT`, and promo balances class as `excluded` in the backing check — granted * credits are the platform's marketing spend, not user money held in trust. */ export declare function promo(userId: string): AccountRef; /** * The platform's own ("house") accounts; every id starts with `platform:`. A debit-normal account * goes up when debited, a credit-normal one when credited. */ export declare const SYSTEM: { readonly TRUST_CASH: AccountRef; readonly REVENUE: AccountRef; readonly STORED_VALUE: AccountRef; readonly PAYOUT_RESERVE: AccountRef; readonly RECEIVABLE: AccountRef; readonly PROMO_FLOAT: AccountRef; readonly USD_CLEARING: AccountRef; readonly REVENUE_USD: AccountRef; readonly OPENING_EQUITY: AccountRef; readonly NETTING_CLEARING: AccountRef; readonly SETTLEMENT_ACCRUAL: AccountRef; }; /** * Strips a shard suffix: `platform:revenue#3` -> `platform:revenue`. The identity functions below * normalize through this, so a shard behaves exactly like its parent. */ export declare function baseOf(ref: AccountRef): AccountRef; /** The id of shard `k`: the bare id for 0, `base#k` otherwise. */ export declare function shardRef(base: AccountRef, shard: number): AccountRef; /** All shard ids of `base`, bare id first. Readers sum these to get the logical balance. */ export declare function shardsOf(base: AccountRef, shards: number): AccountRef[]; /** Whether `ref` is the bare id of an account that shards, so a reader must sum its rows. */ export declare function isShardedBase(ref: AccountRef): boolean; /** * Picks a posting's shard: hash the key, mod the count. Outside the sharded set, or shards < 2, * the bare id passes through. Ops key on their idempotency key (same shard on retry); * PAYOUT_RESERVE keys on the user id, so a settle or reverse — which only knows the saga — drains * the shard the request credited (the overdraft guard keeps every reserve row non-negative). */ export declare function platformShard(ref: AccountRef, key: string, shards: number): AccountRef; /** * Applies {@link platformShard} to every leg. Handlers wrap their finished legs, so legs built by * injected ports (the fee policy credits REVENUE) route without the port knowing about shards. */ export declare function routePlatformLegs(legs: T[], key: string, shards: number): T[]; /** * Whether `ref` is a user wallet account rather than a platform ("house") account — the single * user-vs-house test. Escrow code relies on it to refuse moving held money straight into a user's * balance, which would mint immediately-spendable money that skips settlement and the payout * waiting period. */ export declare function isWalletAccount(ref: AccountRef): boolean; /** * The user id a wallet account belongs to: the part before its `:kind` suffix. For * `usr_alice:spendable` this is `usr_alice`; for a malformed `:spendable` (empty user id) it's the * empty string, which the submit pipeline rejects. Only meaningful for the wallet accounts * {@link isWalletAccount} identifies. For a session escrow account this returns the * `:` prefix, not a user id; use `escrowPartsOf` for those. */ export declare function ownerOf(ref: AccountRef): string; /** Everything is denominated in CREDIT except the USD accounts (see SYSTEM_TRAITS). */ export declare function currency(ref: AccountRef): Currency; /** * Sorts every account into `custodial`, `excluded`, `house-asset`, or `house-liability`. Only * `custodial` (users' spendable) counts toward the trust total. * * @see {@link https://economy-lab-docs.pages.dev/economy/concepts/accounts-and-double-entry/ * Accounts & double-entry} for what each bucket holds and why only custodial raises the required * cash. */ export declare function classify(ref: AccountRef): 'custodial' | 'excluded' | 'house-asset' | 'house-liability'; /** * Whether the account grows on a debit (true) rather than a credit (false). The ledger uses this * to sign a posted line; the no-negative-balance check uses it to read each balance right-way-up. */ export declare function isDebitNormal(ref: AccountRef): boolean; /** * The accounts an operation might touch, locked before posting. A superset on purpose: extra locks * are harmless, too few would let operations interleave. * * `refund` and `reverse` return only the system accounts they always touch; the handler loads the * original transaction and adds its accounts before posting. */ export declare function accountsOf(operation: Operation, shards?: number, accrual?: boolean): AccountRef[]; /** * Pulls the wallet kind out of an id like `usr_123:spendable`. Returns null if there's no `:kind` * suffix or it isn't a known kind — the one parser for the shape, shared with the store adapters' * isKnownAccount checks. */ export declare function walletKindOf(ref: AccountRef): AccountKind | null;