Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
126 commits
Select commit Hold shift + click to select a range
c6a19d2
chore(vendor): rebuild the host from the Seity layer (host-rust-core#…
replghost Sep 25, 2026
0b53082
feat(profile): show product-referenced Seity profiles in a host drawer
replghost Sep 25, 2026
e54484b
feat(profile): open Seity contacts references -- registry slot, seale…
corey-hathaway Sep 26, 2026
e7299f4
fix(profile): read the Seity registry through the protocol worker
corey-hathaway Sep 26, 2026
1d7b4f6
chore(vendor): rebuild the host from the Seity contacts layer (host-r…
corey-hathaway Sep 26, 2026
180278e
chore(vendor): point the host lock at host-rust-core#1009
corey-hathaway Sep 26, 2026
c0bb2a5
chore(vendor): rebuild the host with Profile on wire trait 22 (host-r…
replghost Sep 26, 2026
6ee0c96
style: format the Seity contacts layer with prettier
replghost Sep 26, 2026
7dad5e6
test(profile): let the contacts drawer settle on real time
replghost Sep 26, 2026
193fa4e
Merge remote-tracking branch 'origin/feat/chat-v2-host-runtime' into …
replghost Sep 27, 2026
88183f0
Merge remote-tracking branch 'origin/feat/chat-v2-host-runtime' into …
replghost Sep 27, 2026
fcac68a
Merge feat/chat-v2-host-runtime (#255) into feat/chat-seity-profile: …
replghost Sep 27, 2026
a010d88
Merge remote-tracking branch 'origin/feat/chat-v2-host-runtime' into …
replghost Sep 27, 2026
ce68fe8
Merge remote-tracking branch 'origin/feat/chat-v2-host-runtime' into …
replghost Sep 27, 2026
b7e29e2
Merge feat/chat-v2-host-runtime (TrUAPI 0.21) into feat/chat-seity-pr…
replghost Sep 27, 2026
a9a0ebe
Merge feat/chat-v2-host-runtime (SSO Chat messages at 200-205) into f…
replghost Sep 28, 2026
c6e2b07
Merge feat/chat-v2-host-runtime (test wallet single-tab owner) into f…
replghost Sep 28, 2026
7f5e266
Merge feat/chat-v2-host-runtime (#255) into feat/chat-seity-profile: …
replghost Sep 28, 2026
6070cc6
fix(profile): read Seity slots on the gateway backend; keep the mood …
replghost Sep 28, 2026
3bb04c8
Merge feat/chat-v2-host-runtime (take the wallet back on a click into…
replghost Sep 28, 2026
5cb04f5
chore(vendor): rebuild the host with profile disclosure consent (host…
replghost Sep 28, 2026
ae091b3
feat(profile): ask before sharing the profile with chat contacts
replghost Sep 28, 2026
cba7bf2
ci(secret-scan): allowlist the Seity contacts test vector
replghost Sep 28, 2026
f988ceb
chore(vendor): rebuild the host with placed contact avatars (host-rus…
replghost Sep 28, 2026
55cff84
feat(profile): draw placed contact avatars over the product frame
replghost Sep 28, 2026
a4f369a
chore(vendor): rebuild the host with the Chat state migration (host-r…
replghost Sep 28, 2026
ec9e40a
chore(vendor): rebuild the host with Profile on wire trait 69 (host-r…
replghost Sep 28, 2026
dce9148
chore(vendor): rebuild the host with the profile relay triggers (host…
replghost Sep 28, 2026
7e351e8
feat(profile): hide host-drawn avatars while they move
replghost Sep 28, 2026
3f243a3
Merge updated Chat base
replghost Sep 28, 2026
1749d6e
chore(vendor): rebuild the host with re-disclose resend and sharedAt …
replghost Sep 28, 2026
2b0441b
fix(profile): refetch a contact's profile when their share is renewed
replghost Sep 28, 2026
0ea70f6
Merge feat/chat-v2-host-runtime (Safari per-app test wallet notice) i…
replghost Sep 28, 2026
9c19460
chore(vendor): rebuild the host with contact attribution (host-rust-c…
replghost Sep 28, 2026
58ccf79
feat(profile): say which contact shared a presented profile
replghost Sep 29, 2026
4a1b5b4
chore(vendor): rebuild the host with the contact's username (host-rus…
replghost Sep 29, 2026
e86b590
feat(profile): name the sharing contact by username, never by address
replghost Sep 29, 2026
cd6c96a
Merge feat/chat-v2-host-runtime into feat/chat-seity-profile
replghost Sep 29, 2026
ab032ba
chore(vendor): point the host lock at host-rust-core#1001 d3df641d
replghost Sep 29, 2026
b169341
Merge revert of the light-client E2E switch into feat/chat-seity-profile
replghost Sep 29, 2026
20410d9
Merge refreshed Chat runtime into Seity profile
replghost Sep 29, 2026
75d58e4
Merge commit 'be57cf69ae0bd8c2ade42e36a8b1e1581e122c46' into HEAD
replghost Sep 29, 2026
57f7bc4
ci: recognize the public resolver mapping-slot vector
replghost Sep 29, 2026
583d89e
chore(vendor): rebuild the host from host-rust-core#1001 at 67782146
replghost Sep 29, 2026
815c40d
ci: retain deployed product smoke diagnostics
replghost Sep 29, 2026
940a343
fix(host): settle protocol startup and exercise demand-driven Chat
replghost Sep 29, 2026
fda4ccf
fix(profile): describe audience-wide profile sharing consent
replghost Sep 30, 2026
b6b02a0
Merge Chat contacts picker into Seity profile layer
replghost Sep 30, 2026
8c93b6b
fix(profile): store wallet-wide personal profile grants as bearer sec…
replghost Sep 30, 2026
f01d251
style(profile): format confirmation tests
replghost Sep 30, 2026
a9f9110
chore(vendor): merge Chat refresh and pin Profile runtime f0316580
replghost Sep 30, 2026
a3e7106
Merge Chat smoke opt-in into Seity profile layer
replghost Sep 30, 2026
f588a9a
Merge Chat refresh smoke setup into Profile integration
replghost Sep 30, 2026
5717c71
Preserve concurrent Profile smoke integration
replghost Sep 30, 2026
cc88453
Merge verified real-settings smoke reconciliation from Chat
replghost Sep 30, 2026
efa15ff
Merge PolkaVM apps default-on fix from Chat
replghost Sep 30, 2026
aad0d8a
Merge commit 'feec9de3' into HEAD
replghost Sep 30, 2026
6bfd9eb
Merge commit '77cb602fa795003d010b4f8b059ae350638c6a98' into HEAD
replghost Sep 30, 2026
5ff99bf
Merge commit '11df15832a821b9ce67afc23364bbed6c31df97e' into HEAD
replghost Sep 30, 2026
3c72828
Merge commit '101b2b6ba2dd7d6cbd1cc39e9fec563dccbf2442' into HEAD
replghost Sep 30, 2026
852ff70
Merge refreshed Chat provider stack into Seity Profile
replghost Sep 30, 2026
871b3d1
Merge clarified SDK provenance guidance from Chat
replghost Sep 30, 2026
1ca253a
Merge source-pinned E2E toolchain setup from Chat
replghost Sep 30, 2026
3b7b95e
Merge provider-compatible Previewnet trust roots from Chat
replghost Sep 30, 2026
7f1db9c
Merge current main and native Chat into Seity Profile
replghost Oct 1, 2026
8f2ea88
Merge commit '474e770cee9c5f1a730b527fc0ab38d25e2b25a5' into HEAD
replghost Oct 1, 2026
27e46e5
Qualify Solid profile lifetimes and settle lazy landing rendering
replghost Oct 1, 2026
81c986e
fix(rpc): preserve idle subscriptions and propagate transport loss
replghost Oct 1, 2026
df38076
Merge commit '6047abfe98b9746454d125ea451dcd9fb49f70c2' into HEAD
replghost Oct 1, 2026
59eeff5
Merge commit 'feb65b8e7b612aca164226cebb501d249b8656b3' into HEAD
replghost Oct 1, 2026
4865556
Merge commit '81c986e2a352aca00837ac8474a1e69931c3a1de' into HEAD
replghost Oct 1, 2026
a26b493
Merge commit '0cddc13e4680f096867207a970df412af512f378' into HEAD
replghost Oct 1, 2026
38b5dda
Merge commit 'baa34f24018cc504114a6e5b5ee19512ca6698f0' into HEAD
replghost Oct 1, 2026
beb5ad7
Merge commit '4f011d01041cfacd33f0bb2f2f6e078b3a62bb4f' into HEAD
replghost Oct 1, 2026
abb08d9
Merge commit '19253c28214900ce1a41a727e32f29672d0f90fb' into HEAD
replghost Oct 1, 2026
a093cb4
Merge commit 'a76966ec11dda8f7c2321d6254e412d0dd4d33c1' into HEAD
replghost Oct 1, 2026
89b7a46
Merge commit '1d1000fc16c396666f3e8857310652826a8e3157' into HEAD
replghost Oct 1, 2026
927a3b3
Merge commit '4130d62c77ca9d95961ec6659416749376fd6318' into HEAD
replghost Oct 1, 2026
e8310f3
Merge commit 'e103de7f5cbf623121e9684c47a0940dd7f55147' into HEAD
replghost Oct 1, 2026
1abbada
chore: refresh canonical native-main Seity SDK artifacts
replghost Oct 1, 2026
11f46dd
Merge commit 'bef37bfa3ecf406b1b7f225f2e9e7060b92a5275' into HEAD
replghost Oct 1, 2026
c703312
Merge commit 'ef8e703b668a3545b9171c4594d531a69b0e130c' into HEAD
replghost Oct 1, 2026
39fb06b
merge: inherit qualified resolver and worker recovery
replghost Oct 2, 2026
b526e4a
fix: apply canonical stopped-chain recovery to Seity gateway reads
replghost Oct 2, 2026
19f6592
merge: inherit shared-worker generation recovery
replghost Oct 2, 2026
26de976
merge: inherit proven recovery guidance
replghost Oct 2, 2026
50f2144
merge: inherit real-RPC recovery regression cutover
replghost Oct 2, 2026
b03e836
merge: inherit isolated bitswap fixture setup
replghost Oct 2, 2026
d3dc8a4
Merge corrected upstream and refresh canonical seity artifacts
replghost Oct 2, 2026
bdb7e06
Merge commit '6ef2aa616b6e771c236a37f36743212472ad0b38' into HEAD
replghost Oct 2, 2026
e77662e
Merge refreshed Chat into browser Seity profiles
replghost Oct 2, 2026
8ce9b84
Merge refreshed Chat and matching native Seity packages
replghost Oct 2, 2026
b33a630
feat(contacts): add audience picker and host-owned contact labels
replghost Oct 2, 2026
b81cd07
style(contacts): format browser feature changes
replghost Oct 2, 2026
8aa3839
build(contacts): vendor matching Seity host and client
replghost Oct 2, 2026
700d77d
fix(contacts): follow current host lint contracts
replghost Oct 2, 2026
40994a9
Merge refreshed browser Chat into Seity
replghost Oct 2, 2026
e662f0c
Merge refreshed Chat and matched Seity native artifacts
replghost Oct 2, 2026
b457d8e
Merge Chat cache regression compatibility into Seity
replghost Oct 2, 2026
f773c82
Merge final Chat source formatting into Seity
replghost Oct 2, 2026
39568ae
Merge Chat persisted cache correction into Seity
replghost Oct 2, 2026
7fd3352
Merge Chat archive fixture correction into Seity
replghost Oct 2, 2026
28eb0c2
Merge incoming Contacts source into refreshed Seity layer
replghost Oct 2, 2026
78e2cf1
Vendor clean Contacts packages from refreshed Seity native source
replghost Oct 2, 2026
ab4f79a
fix(profile): open an empty drawer for unshared contacts
replghost Oct 2, 2026
8b76a45
merge: forward Chat locale support into Seity
replghost Oct 2, 2026
7d71930
style(contacts): format picker checkbox selector
replghost Oct 2, 2026
8dc914a
merge: forward Chat locale and rebuild matching Seity SDK
replghost Oct 2, 2026
d601dd3
style(profile): format empty-drawer implementation
replghost Oct 2, 2026
bf2a7da
merge: forward corrected locale tests into Seity
replghost Oct 2, 2026
0909407
fix(profile): explicitly snapshot per-presentation loading state
replghost Oct 2, 2026
7000f15
merge: preserve concurrent Contacts formatting repair
replghost Oct 2, 2026
3af5375
merge: forward final locale conventions into Seity
replghost Oct 2, 2026
121683e
merge: forward bridge SDK mock repair into Seity
replghost Oct 2, 2026
6b89d6c
build(vendor): record the generated client digest
replghost Oct 3, 2026
201ad3e
Merge refreshed Chat layer into Seity
replghost Oct 3, 2026
99b905b
Merge approved Duke pointer-lock smoke correction into browser #287
replghost Oct 3, 2026
2da9b69
fix(profile): resolve drawer names from the verified contact directory
replghost Oct 3, 2026
7293d40
Merge approved browser #255 update into Seity #287
replghost Oct 4, 2026
d8e05a6
Merge approved #255 qualification input correction into #287
replghost Oct 4, 2026
2a98e64
Merge approved #255 deployed-handshake qualification into #287
replghost Oct 4, 2026
428e547
Merge approved #255 loading qualification repair into #287
replghost Oct 4, 2026
3848d20
Merge approved #255 runtime 0.3.2-rc.2 file-input update into #287
replghost Oct 5, 2026
aaf2415
Merge feat/chat-v2-host-runtime (runtime 0.3.2-rc.3) into feat/chat-s…
replghost Oct 5, 2026
b06838e
Merge approved #255 runtime rc.3 pin note formatting into #287
replghost Oct 5, 2026
4e9518c
Merge approved #255 PWA update recovery fix into #287
replghost Oct 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,17 @@ private storage and attachment custody stay with the one page core.

Picker rows show verified contact names, with a generic label for unnamed contacts; raw account IDs are not displayed.

The multi-select picker opens with the current audience checked, preserves selections while searching, and applies them
only with **Use selection**. Confirming no checked contacts removes everyone; **Cancel**, Escape, and the backdrop leave
the audience unchanged. The original single-contact picker remains available.

Contact names and account identities remain host-private. Products receive opaque contact handles and can reserve
clipped label boxes on their surface; the host draws verified contact usernames, or account identifiers when no username
is available, above the product frame. These labels do not require a shared profile or photo, and are independent of
Profile avatar placement. Same-wallet contact-directory changes clear stale names and refresh the latest placement
without waiting for the product to redraw. Product restart, navigation, wallet/session replacement, an empty placement,
and frame teardown cancel pending refreshes and remove labels.

Use the existing **List**, **Timeline**, and **Resolution** tabs for activity and diagnostics. Wallet does not duplicate
their event viewer or capture controls.

Expand Down Expand Up @@ -700,6 +711,29 @@ funds or import a real wallet. Debug builds can still access real networks and s

Keep `VITE_APP_DEBUG` unset or false in production builds.

### Seity profiles

Profile sharing uses the native core's separate **Profile Disclosure** consent. It does not authorize identity
disclosure, transaction signing, spending, or statement submission. Dismissing a disclosure prompt leaves it undecided;
an explicit denial is persisted by the core.

The host resolves Seity contact references through the active network's registry and decrypts Bulletin content outside
the product frame. Profile references are bearer capabilities: their storage follows the existing encrypted native
wallet custody and wallet/network namespaces. A network without a configured registry has no contact profile to display.

Profiles and contact-avatar layers are Solid host surfaces attached to the product's connection to the shared page core.
Closing or retiring the connection aborts pending loads, removes its drawer and avatars, and releases decrypted image
URLs. Profile content is self-described; verified Chat attribution confirms who shared a reference, not who an image
depicts.

Opening a contact without a received, live profile reference still opens the host drawer. It shows the host-verified
contact name and **No information shared with you yet**, without an error style or an indefinite spinner. It does not
claim the contact has never shared: information may not have reached this host yet. Availability stays private from the
requesting product, whose completion reply is the same for shared and empty profiles. When a product-specific Chat name
is unavailable, the drawer resolves it from the same wallet- and People-network-bound verified directory used by contact
labels. This lookup never delays opening the drawer or returns the name to the requesting product. Missing or
unavailable directory names retain generic attribution.

## Sandbox API Checker

dApps rendered in dotli's sandboxed iframe should communicate exclusively through the container bridge (postMessage),
Expand Down
19 changes: 19 additions & 0 deletions apps/protocol/src/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
ManifestResult,
RootManifest,
ResolveOptions,
SeitySlot,
} from '@dotli/resolver';
import { isExecutableKind } from '@dotli/shared';
import {
Expand Down Expand Up @@ -52,6 +53,7 @@ export interface EngineOptions {
* `@dotli/resolver` entry points so they can be wired by reference. */
resolveDotName?: (label: string, opts?: ResolveOptions) => Promise<string | null>;
resolveOwner?: (label: string, opts?: ResolveOptions) => Promise<string | null>;
resolveSeitySlot?: (lookupKey: `0x${string}`, opts?: ResolveOptions) => Promise<SeitySlot | null>;
/**
* Product-manifest readers.
*
Expand Down Expand Up @@ -157,6 +159,23 @@ export function createEngine(options: EngineOptions): ProtocolEngine {
return;
}

case 'resolveSeitySlot': {
if (!options.resolveSeitySlot) {
throw new Error(PROTOCOL_APP_ERRORS.RESOLVE_SEITY_SLOT_UNSUPPORTED);
}
const payload = request.payload as ProtocolRequestMap['resolveSeitySlot'];
assertStr(payload.lookupKey, 'lookupKey');
const slot = await options.resolveSeitySlot(payload.lookupKey as `0x${string}`, syncOptions);
respond({
namespace: 'dotli:protocol',
kind: 'response',
id: request.id,
ok: true,
result: slot === null ? null : { ...slot, version: slot.version.toString() },
});
return;
}

case 'resolveOwner': {
if (!options.resolveOwner) {
throw new Error(PROTOCOL_APP_ERRORS.RESOLVE_OWNER_UNSUPPORTED);
Expand Down
1 change: 1 addition & 0 deletions apps/protocol/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const PROTOCOL_APP_ERRORS = {
INVALID_SHARED_AUTH_VALUE: 'Invalid shared auth value',
RESOLVE_DOT_NAME_UNSUPPORTED: 'resolveDotName is not served by this protocol mode',
RESOLVE_OWNER_UNSUPPORTED: 'resolveOwner is not served by this protocol mode',
RESOLVE_SEITY_SLOT_UNSUPPORTED: 'resolveSeitySlot is not served by this protocol mode',
RESOLVE_EXECUTABLE_MANIFEST_UNSUPPORTED: 'resolveExecutableManifest is not served by this protocol mode',
RESOLVE_ROOT_MANIFEST_UNSUPPORTED: 'resolveRootManifest is not served by this protocol mode',
CHAIN_BROKER_FAILED: 'Failed to create chain broker',
Expand Down
2 changes: 2 additions & 0 deletions apps/protocol/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,7 @@ async function initDirectMode(): Promise<void> {
resolveExecutableManifest,
resolveOwner,
resolveRootManifest,
resolveSeitySlot,
setResolverAssetHubProvider,
setResolverPeopleProvider,
waitForPeopleFinalized,
Expand Down Expand Up @@ -1014,6 +1015,7 @@ async function initDirectMode(): Promise<void> {
},
resolveDotName,
resolveOwner,
resolveSeitySlot,
resolveExecutableManifest,
resolveRootManifest,
});
Expand Down
15 changes: 15 additions & 0 deletions apps/protocol/src/protocol-shared-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
resolveExecutableManifest,
resolveOwner,
resolveRootManifest,
resolveSeitySlot,
setResolverAssetHubProvider,
setResolverPeopleProvider,
waitForAssetHubFinalized,
Expand Down Expand Up @@ -368,6 +369,20 @@ async function handleRequest(port: MessagePort, request: ProtocolRequestEnvelope
return;
}

case 'resolveSeitySlot': {
const payload = request.payload as ProtocolRequestMap['resolveSeitySlot'];
assertString(payload.lookupKey, 'lookupKey');
const slot = await resolveSeitySlot(payload.lookupKey as `0x${string}`, syncOptions);
sendToPort(port, {
namespace: 'dotli:protocol',
kind: 'response',
id: request.id,
ok: true,
result: slot === null ? null : { ...slot, version: slot.version.toString() },
});
return;
}

case 'resolveOwner': {
const payload = request.payload as ProtocolRequestMap['resolveOwner'];
assertString(payload.label, 'label');
Expand Down
10 changes: 10 additions & 0 deletions docs/resolution-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@

![Shared Smoldot](assets/smoldot-shared.svg)

### Seity profile resolution

Seity profile reads use `resolveSeitySlot` through the canonical iframe engine
(`apps/protocol/src/engine.ts`) or the SharedWorker request handler. Both preserve
the resolver sync deadline and serialize the slot's bigint version as a decimal
string. Gateway mode instead calls `resolveSeitySlotViaRpc` directly. All three
paths use the same pinned `withContract` registry reader; an unconfigured registry
returns `null`. Profile resolution shares the canonical chain-pool lifecycle and
stopped-chain recovery rather than maintaining a separate engine or RPC retry loop.

## Appendix

Table I - Cold-start latency distribution. End-to-end domain resolution across 20 runs (2026-04-24). The *actor* column matches the components in the Architecture Overview above.
Expand Down
4 changes: 4 additions & 0 deletions packages/config/src/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ export interface ServicesConfig {
readonly decimals: number;
};
readonly dotns: DotnsContracts;
/** Seity's slot registry on Asset Hub; absent where Seity is not deployed. */
readonly seity?: { readonly REGISTRY: string };
}

const BUILTIN_NETWORK_SERVICES: Record<NetworkName, ServicesConfig> = {
Expand Down Expand Up @@ -105,6 +107,8 @@ const BUILTIN_NETWORK_SERVICES: Record<NetworkName, ServicesConfig> = {
STORAGE_SLOTS: { REGISTRY_RECORDS: 0, CONTENTHASH: 0, TEXT_RECORDS: 1 },
TLD: 'paseo',
},
// paritytech/seity registry/deployments/paseo-next-v2/deployment.json
seity: { REGISTRY: '0x90ddece099d26f66d13bb46b9db49dbb2083cb15' },
},
[NetworkName.PREVIEWNET]: {
label: 'Previewnet',
Expand Down
2 changes: 1 addition & 1 deletion packages/content/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ export { bitswapGet, listenForSandboxBitswap, onContentProgress } from './bitswa
export { decryptContent, isEncrypted } from './decrypt.js';
export { type FetchResult } from './fetch.js';
export { fetchFromIpfs } from './ipfs.js';
export { computePreimageKey, hashToCid } from './preimage.js';
export { cidToPreimageKey, computePreimageKey, hashToCid } from './preimage.js';
export { assertBlockMatchesCid } from './verify.js';
export { loadFetch, type FetchModule } from './lazy.js';
18 changes: 18 additions & 0 deletions packages/content/src/preimage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,21 @@ export function hashToCid(hashHex: string): CID {
const digest = create(BLAKE2B_256_MULTIHASH_CODE, fromHex(hashHex));
return CID.createV1(RAW_CID_CODEC, digest);
}

/**
* Inverse of `hashToCid`: the Blake2b-256 preimage key a Bulletin CID names.
* Throws for any CID that is not CIDv1 raw with a Blake2b-256 multihash, the
* only shape the preimage API content-addresses.
*/
export function cidToPreimageKey(cid: string): `0x${string}` {
const parsed = CID.parse(cid);
if (
parsed.version !== 1 ||
parsed.code !== RAW_CID_CODEC ||
parsed.multihash.code !== BLAKE2B_256_MULTIHASH_CODE ||
parsed.multihash.digest.length !== 32
) {
throw new Error(`${cid} is not a raw Blake2b-256 CIDv1`);
}
return toHex(parsed.multihash.digest);
}
17 changes: 16 additions & 1 deletion packages/protocol/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,8 @@ async function postRequest<M extends ProtocolRequestMethod>(
frameWindow.postMessage(envelope, getProtocolOrigin());
});
}
type ResolverRequestMethod = 'resolveDotName' | 'resolveOwner' | 'resolveExecutableManifest' | 'resolveRootManifest';
type ResolverRequestMethod =
'resolveDotName' | 'resolveOwner' | 'resolveSeitySlot' | 'resolveExecutableManifest' | 'resolveRootManifest';

function isStoppedResolverResponse(error: unknown): error is Error {
return (
Expand Down Expand Up @@ -700,6 +701,20 @@ export async function resolveOwnerRemote(label: string): Promise<string | null>
return (await postResolverRequest('resolveOwner', { label })) as string | null;
}

/** A Seity registry slot as the protocol returns it; `version` is a decimal string. */
export interface RemoteSeitySlot {
readonly owner: `0x${string}`;
readonly cidDigest: `0x${string}`;
readonly version: string;
}

/** Remote proxy for the Seity registry reader (null when the registry is absent). */
export async function resolveSeitySlotRemote(lookupKey: `0x${string}`): Promise<RemoteSeitySlot | null> {
return (await postResolverRequest('resolveSeitySlot', {
lookupKey,
})) as RemoteSeitySlot | null;
}

/**
* Remote proxy for the executable-manifest reader.
*
Expand Down
2 changes: 2 additions & 0 deletions packages/protocol/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export {
resolveExecutableManifestRemote,
resolveOwnerRemote,
resolveRootManifestRemote,
resolveSeitySlotRemote,
setProtocolSubMode,
subscribeSharedAuthStorage,
subscribeSharedWallet,
Expand All @@ -57,6 +58,7 @@ export {
warmupProtocol,
writeSharedAuthStorage,
writeSharedModeStorage,
type RemoteSeitySlot,
} from './client.js';
export { CORE_CUSTODY_BUSY_ERROR, isCoreCustodyOperation, type CoreCustodyOperation } from './core-custody.js';
export { ProtocolFatalError, ProtocolInitFailedError } from './errors.js';
Expand Down
1 change: 1 addition & 0 deletions packages/protocol/src/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface ProtocolRequestMap {
warmup: Record<string, never>;
resolveDotName: { label: string };
resolveOwner: { label: string };
resolveSeitySlot: { lookupKey: string };
resolveExecutableManifest: {
label: string;
kind: 'app' | 'widget' | 'worker';
Expand Down
1 change: 1 addition & 0 deletions packages/protocol/src/method-timeouts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const METHOD_TIMEOUTS: Partial<Record<ProtocolRequestMethod, number>> = {
chainConnect: 30_000,
resolveDotName: 90_000,
resolveOwner: 90_000,
resolveSeitySlot: 90_000,
resolveExecutableManifest: 30_000,
resolveRootManifest: 30_000,
};
15 changes: 15 additions & 0 deletions packages/resolver/src/abi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,21 @@ export function computeMappingSlot(key: `0x${string}`, slotNumber: number): `0x$
return toHex(new Uint8Array(keccak_256(concatBytes(hexToBytes(key), slotBytes))));
}

/**
* Compute the slot for `mapping(bytes32 => mapping(bytes32 => T))` at slot N,
* which is also how a pvm-contract-sdk `Mapping<([u8; 32], [u8; 32]), T>`
* lays out (pvm-storage chains tuple keys like Solidity nested mappings):
* keccak256(inner ++ keccak256(outer ++ uint256(N)))
*/
export function computeNestedBytes32MappingSlot(
outerKey: `0x${string}`,
innerKey: `0x${string}`,
slotNumber: number,
): `0x${string}` {
const midSlot = computeMappingSlot(outerKey, slotNumber);
return toHex(new Uint8Array(keccak_256(concatBytes(hexToBytes(innerKey), hexToBytes(midSlot)))));
}

/**
* Compute the data slot for long Solidity `bytes` storage.
*
Expand Down
2 changes: 2 additions & 0 deletions packages/resolver/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ export {
resolveExecutableManifest,
resolveOwner,
resolveRootManifest,
resolveSeitySlot,
setResolverAssetHubProvider,
setResolverPeopleProvider,
waitForAssetHubFinalized,
waitForPeopleFinalized,
type ResolveOptions,
} from './resolve.js';
export { type SeitySlot } from './seity-registry.js';
export { createCoreRpcChainProvider, getConnectedRpcEndpoint, isCoreRpcChainSupported } from './rpc-chain.js';
export { type ChainTransportHooks, type ConnectionStatus } from './transport-hooks.js';
export {
Expand Down
14 changes: 14 additions & 0 deletions packages/resolver/src/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type { PhaseCallback, StatusCallback } from './access-raw-storage.js';
import { createRawApi, type Api } from './api.js';
import { readExecutableManifest, readRootManifest } from './manifest.js';
import type { ExecutableKind, ExecutableManifest, ManifestResult, RootManifest } from './manifest.js';
import { readSeitySlot, type SeitySlot } from './seity-registry.js';

export type { StatusCallback, PhaseCallback, ResolvePhase } from './access-raw-storage.js';
export { statusToPhase } from './access-raw-storage.js';
Expand Down Expand Up @@ -359,3 +360,16 @@ async function readOwner(label: string, opts: ResolveOptions): Promise<string |
const dotns = getActiveServicesConfig().dotns;
return readMappingAddress(api, dotns.DOTNS_REGISTRY, node, dotns.STORAGE_SLOTS.REGISTRY_RECORDS);
}

/**
* Read one Seity registry slot on the active network's Asset Hub. Returns
* null when the network has no Seity registry configured.
*/
export async function resolveSeitySlot(lookupKey: `0x${string}`, opts: ResolveOptions = {}): Promise<SeitySlot | null> {
const registry = getActiveServicesConfig().seity?.REGISTRY;
if (registry === undefined) {
return null;
}
const api = await ensureClient(opts);
return readSeitySlot(api, registry, lookupKey);
}
14 changes: 14 additions & 0 deletions packages/resolver/src/rpc-resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { createRawApi, type Api } from './api.js';
import { getConnectedRpcEndpoint } from './rpc-chain.js';
import { readExecutableManifest, readRootManifest } from './manifest.js';
import type { ExecutableKind, ExecutableManifest, ManifestResult, RootManifest } from './manifest.js';
import { readSeitySlot, type SeitySlot } from './seity-registry.js';

export type { StatusCallback } from './access-raw-storage.js';

Expand Down Expand Up @@ -225,6 +226,19 @@ export function resolveOwnerViaRpc(label: string): Promise<string | null> {
});
}

/**
* Read one Seity registry slot over JSON-RPC: the gateway-mode counterpart of
* `resolveSeitySlot`. Null when the network has no Seity registry, matching
* the protocol-worker path.
*/
export async function resolveSeitySlotViaRpc(lookupKey: `0x${string}`): Promise<SeitySlot | null> {
const registry = getActiveServicesConfig().seity?.REGISTRY;
if (registry === undefined) {
return null;
}
return withRpcClient(api => readSeitySlot(api, registry, lookupKey));
}

/**
* Return the Asset Hub RPC endpoint URI the shared chain connection is
* currently on, or `null` while none is open. The URI may not be the first
Expand Down
Loading
Loading