The four things a second copy of the book has to be able to do.
Identity, register, snapshot, allocation. No transport, no keys, no network: feed it data you fetched yourself and check the result against your own.
Every amount is BigInt. Multipliers are 18-decimal fixed point and a dividend is 566080 parts in a billion. Float arithmetic loses that by the third rebase, so nothing here accepts a float where precision matters.
npm install @stockledger/core| Module | What it settles |
|---|---|
identity |
Which contract a ticker actually means, decided by bytecode |
register |
Replay of corporate actions, with the entries a replayer cannot trust flagged |
snapshot |
Who held the exposure at the effective time, looking through pools where possible |
allocation |
What each holder is owed, rounded so the parts sum to the whole |
A ticker is not an identifier. On chain 4663, 1127 contracts answer to AAPL and
346 contracts copy the Robinhood naming scheme. The bytecode is the only test
that holds.
const { identity } = require('@stockledger/core');
identity.classify(bytecode);
// { verdict: 'genuine', size: 283, embedsImplementation: true }
identity.resolveTicker('AAPL', candidates);
// '0xaf3d76f1834a1d425780943c99ea8a608f8a93f9'
// throws when the answer is not unique - ambiguity is a fact, not a value to guessconst { register, toWad, fromWad } = require('@stockledger/core');
const entries = register.build(logs);
const r = register.resolve(entries);
fromWad(r.absolute); // '4.000000000' the last `to` value <- correct
fromWad(r.composed); // '16.000000000' every step multiplied <- wrong here
r.agree; // falseThree flags, all present on chain today:
| Flag | Meaning |
|---|---|
duplicate |
The identical payload emitted twice in different blocks |
reversal |
A value set and put back inside the same session |
outsized |
A step far larger than a dividend: a split, or a correction |
The register never picks a winner. It records both readings and reports the disagreement, because a book that silently resolves a conflict is not a second copy of anything.
const { snapshot } = require('@stockledger/core');
const s = snapshot.take(balances, multiplierBeforeStep, { pools });
snapshot.reconcile(s, totalSupply); // { ok: true, diff: 0n }Pools are why this is not a groupBy. The pool holds the token, the depositor
holds the claim, and the chain records only the first. Where the pool's share
accounting is readable the snapshot looks through it; where it is not, the pool
is listed in s.opaque instead of being split on a guess.
const { allocation } = require('@stockledger/core');
allocation.allocate(snapshot, 10_000n * 10n ** 6n); // issuer pays USDC
allocation.allocateAccrual(snapshot, from, to); // issuer bumps the multiplierLargest-remainder rounding, so distributed + dust === amount always. A payout
list that does not sum to the amount is a reconciliation problem you inherit.
identity.js bytecode -> genuine | impostor | no-code
|
register.js logs -> entries + flags -> { absolute, composed, agree }
|
snapshot.js balances + pools @ effectiveAt -> rows that reconcile to supply
|
allocation.js snapshot + amount -> payout rows, largest remainder
npm test # 29 assertions, node:test, no runner to install
node examples/replay.js # the real CrowdStrike duplicate, read both ways
node examples/distribute.js # snapshot through a pool, then a USDC payoutMIT. See LICENSE.
Part of Stock Ledger - the register of record for tokenized equities.