Conversation
Wondertan
force-pushed
the
feat/ledger-client
branch
from
September 30, 2026 14:48
dc60584 to
c91a8f2
Compare
Wondertan
force-pushed
the
feat/ledger-client
branch
from
September 30, 2026 15:32
ea2bdbe to
a40b019
Compare
Wondertan
added this pull request to stack #68
September 30, 2026 20:04
Wondertan
force-pushed
the
feat/ledger-client
branch
from
October 2, 2026 20:12
fb9fa8a to
0bf8963
Compare
Wondertan
removed this pull request from stack #68
October 2, 2026 20:13
Wondertan
added this pull request to stack #107
October 2, 2026 20:13
🚀 Deploying Preview to Cloudflare 🚀Preview URL: https://feat-ledger-client.previews.lib.id, https://feat-ledger-client-libid.grounded-systems.workers.dev (commit b967faa)This URL reflects your latest Preview deploymentPreview Deployments by commit
|
`@libid/ledger/client` serves many ledgers from one client. It runs reads and
writes the layer above describes as one implementation per ledger family, so
the ledger holds no identity or application getters.
- `connect({ ledgers, indexer })` reaches each ledger through its RPC or
through another client. Every method takes the ledger it acts on, and
`client.ledger(chain)` looks one up at runtime.
- `read` pins a query's actions to one ledger state. `tx` and `estimate` build
a command's transaction and its network fee.
- `connect(ledger, wallet)` returns a session whose reads prefer the wallet's
own RPC, ported from handles.link. `send` rechecks the wallet and simulates
first; a `LedgerError` from it means nothing was sent.
- A query may add an `indexer` implementation. One libID indexer serves every
chain it reports and is used while current, otherwise the chain answers. The
default indexer can be replaced or turned off per ledger.
- EVM specifics live in `@libid/ledger/evm`, and ledgers carry their family.
A conformance suite covers every client and session member against a harness
each family must provide, including with an unavailable indexer.
Assisted-by: Claude Opus 5.5
Signed-off-by: Wondertan <hlibwondertan@gmail.com>
`readFailure` exceeded the workspace's oxlint complexity limit. Its checks move into named predicates for refusals, transient failures, unsupported methods and transport errors, with no change in behavior. Assisted-by: Claude Opus 5.5 Signed-off-by: Wondertan <hlibwondertan@gmail.com>
A client now reads each ledger through the wallet connected on it, then the ledger's RPC. Catalog ledgers carry a public RPC and explorer where one exists, used by default, offered to wallets that must add the chain, and overridable per client entry; a ledger without a public RPC needs one configured. A catalog chain is served only with its catalog definition, so its deployments cannot be changed. `Session.read` is gone: client reads use the connected wallet. Assisted-by: Claude Opus 5.5 Signed-off-by: Wondertan <hlibwondertan@gmail.com>
A client entry's `rpc` and `explorer` must be endpoints, like a ledger's public ones, so a misconfigured URL fails when the client is created. Assisted-by: Claude Opus 5.5 Signed-off-by: Wondertan <hlibwondertan@gmail.com>
…p indexer fallback - The catalog is `Ledgers`, whose members are the ledgers themselves (`Ledgers.EdenTestnet`), so no catalog id is a string. - Eden's `identityNames` moves to the live `libid.IdentityNames.3` deployment (0x5b86…7796) named by chain-configurations and indexed by the names indexer; the previous address has no `accountsOf` getters. Its public RPC stays on Gateway.fm, which allows browser origins; the chain-configurations endpoint sends no CORS headers. - On a ledger with an indexer, queries with an indexer implementation are answered by the indexer alone. A stale or unavailable indexer fails the read with `indexer-unavailable` instead of falling back to the chain; a caller's abort stays an abort, and a query's own errors pass through. BREAKING CHANGE: `ledgers['eden-testnet']` is now `Ledgers.EdenTestnet`, and indexer failures no longer fall back to the chain. Assisted-by: Claude Opus 5.5 Signed-off-by: Wondertan <hlibwondertan@gmail.com>
… pin no RPC - `client.connect(wallet)` connects the wallet the user picked for every served ledger of its family, replacing any connected before. `session.send(ledger, tx)` switches the wallet to that ledger's chain first. - The session follows the wallet: `account` tracks account switches, `subscribe` reports them, and `chooseAccount()` opens the wallet's account picker (`wallet_requestPermissions`), or fails as `unsupported`. - libID pins no RPC; Eden's is removed. An RPC is optional: without one, a ledger is read only through a connected wallet on its chain, reads with neither fail with `unreachable`, and a wallet that does not know the chain cannot be offered it. - Ledger errors thrown inside viem transports are unwrapped, so callers see `unreachable` rather than a generic RPC error. BREAKING CHANGE: `connect(ledger, wallet)` is now `connect(wallet)`, and `send(tx)` is now `send(ledger, tx)`. Assisted-by: Claude Opus 5.5 Signed-off-by: Wondertan <hlibwondertan@gmail.com>
libid-contracts 0.15.0 renamed the identity contract to IdentityRegistry and deployed it fresh as `libid.IdentityRegistry` (0x0531…1366), the same on every EVM chain; chain-configurations now lists it on Eden and Sepolia. The catalog's deployment key is `identityRegistry`, Eden moves to the new registry, and Sepolia joins with the testnet notary and its public explorer. Both verifiers' chain hashes, the registry and the notary's trust were checked on-chain, and the names indexer already covers the new registry on both chains. Assisted-by: Claude Opus 5.5 Signed-off-by: Wondertan <hlibwondertan@gmail.com>
Wondertan
force-pushed
the
feat/ledger-client
branch
from
October 2, 2026 20:14
0bf8963 to
b967faa
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stacked on #62. Adds chain access to
@libid/ledgerthat serves many ledgers from one client. Every use case starts multichain, so there is no single-chain client. The client runs reads and writes that the layer above describes as one implementation per ledger family, so the ledger holds no identity or application getters. (Folds in the former #66.)Package
@libid/ledgergains the./clientand./evmentry points, both built into the published package, and a runtime dependency on viem. The root entry point stays dependency-free apart from@noble/hashes.Catalog
Ledgersnames the pinned ledgers (Ledgers.EdenTestnet); its members are the ledgers themselves, so no catalog id is a string.Ledgers.EdenTestnetandLedgers.Sepoliapin thelibid.IdentityRegistrydeployment (0x0531…1366, keyidentityRegistry). This is the same canonical address on both chains, from libid-contracts 0.15.0 and chain-configurations. Both carry the testnet notary and a public explorer. On 2026-10-01 I checked on-chain that each chain's verifier reports the chain hash its catalog entry derives (the test vectors), that the registry answers, and that the testnet notary's signer is trusted. The names indexer covers the registry on both chains.Multichain client
Ledgerit acts on.unreachable. Without an RPC, a wallet that does not know the chain cannot be offered it. Configured endpoints are validated.LedgerClient, such as a custom or differently configured one.walletRequirementslists chains, methods and events per CAIP-2 namespace, ready for WalletConnect's namespaces.family(derived bydefineLedger), so family-dependent types resolve by plain property lookup. Code generic over families type-checks without conditional types.Driver: one ledger's operations. The client routes to them.Family modules
@libid/ledger/evmholds the EVMReader,TxandProvidertypes for query authors, the EVM driver, and the chain-hash and address checksdefineLedgeruses.connect(wallet)connects the wallet the user picked for every served ledger of its family, replacing any connected before. TheSessionfollows the wallet:accounttracks account switches,subscribereports them, andchooseAccount()opens the wallet's account picker (wallet_requestPermissions), or fails asunsupported.session.send(ledger, tx)switches the wallet to the ledger's chain if needed, rechecks the account and simulates before asking the wallet to send. ALedgerErrorfromsend(wallet-changed,not-sent,rejected) means nothing was sent; any other error leaves the outcome unknown.@libid/ledger/clientstays family-agnostic and refers to family types only through oneFamiliesentry per family. The root entry gains only the type-onlyAccountbrand.Indexer
Querykeeps its required chain implementation per family and may add anindexerimplementation for the same result.indexer({ origin, deployment })serves every chain its/v1/statusreports.maxLagblocks (default 20) of the head, as reported and by head gap;LedgerError('indexer-unavailable'); there is no fallback to the chain. A caller's abort stays an abort, and a query's own errors pass through.indexer: falsegives a ledger none, so its queries read the chain.indexer.ts. Application endpoints stay in consuming queries.Adding a family
Adding a second family was simulated. The compiler flagged only three things:
The router, the EVM driver and the conformance suite needed no change.
Verification
pnpm --filter @libid/ledger build,typecheck,test: 104 tests pass.LedgerClientandSessionmember, including several ledgers with independent state, runtime lookup, unserved and duplicate ledgers, per-namespace wallet requirements, and delegation. They run twice: plain, and with an unavailable default indexer.rpc.test.ts, and 8 catalog tests.index.d.tsimports nothing andclient.d.tsnames no viem types.pnpm build,typecheck,test(ledger 104, popup 154, ceremony 996),lint(biome and oxlint's complexity limit),fmt:checkandtest:packagespass onmainatcbe7f35.Not run: against the live testnet indexer or a real wallet;
@libid/identitywill be the first consumer.