Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 5 additions & 5 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"smoldot": "3.3.2"
},
"overrides": {
"@parity/truapi": "0.7.0",
"@parity/truapi": "0.8.0",
"fast-uri": "3.1.5",
"smoldot": "3.3.2",
"esbuild": "^0.28.1",
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
"@dotli/storage": "workspace:*",
"@dotli/truapi-debug": "workspace:*",
"@noble/hashes": "^2.2.0",
"@parity/truapi": "0.7.0",
"@parity/truapi-host": "0.4.0",
"@parity/truapi": "0.8.0",
"@parity/truapi-host": "0.5.0",
"@polkadot-api/json-rpc-provider": "^0.2.0",
"@scure/base": "^2.2.0",
"neverthrow": "^8.2.0",
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/debug-wire-describe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ const CHAIN_LINKAGE: readonly ChainLinkage[] = [
{ wireTableKey: "CHAIN_GET_SPEC_GENESIS_HASH", stem: "SpecGenesisHash" },
{ wireTableKey: "CHAIN_GET_SPEC_CHAIN_NAME", stem: "SpecChainName" },
{ wireTableKey: "CHAIN_GET_SPEC_PROPERTIES", stem: "SpecProperties" },
{ wireTableKey: "CHAIN_GET_CHAIN_INFO", stem: "Info" },
{
wireTableKey: "CHAIN_BROADCAST_TRANSACTION",
stem: "TransactionBroadcast",
Expand Down
14 changes: 11 additions & 3 deletions packages/ui/src/host-callbacks/SessionStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ export function toSessionUiState(info: SessionUiInfo): TruapiSessionUiState {
const primaryUsername = info.fullUsername ?? info.liteUsername;
return {
connected: true,
publicKey: bytesToHex(info.publicKey),
publicKey: info.publicKey,
...(info.identityAccountId !== undefined
? { identityAccountId: bytesToHex(info.identityAccountId) }
? { identityAccountId: info.identityAccountId }
: {}),
...(info.liteUsername !== undefined
? { liteUsername: info.liteUsername }
Expand Down Expand Up @@ -244,6 +244,10 @@ function coreLocalStorageKey(key: CoreStorageKey): string {
return `${CORE_LOCAL_STORAGE_PREFIX}auto-signing:${hexNoPrefix(
encodeCoreStorageKey(key),
)}`;
// Wallet-bound capabilities for the active pairing: one slot, unlike the
// legacy per-product `AutoSigningKey` above.
case "AutoSigningKeys":
return `${CORE_LOCAL_STORAGE_PREFIX}auto-signing-keys`;
case "LastProcessedPairingStatement":
return `${CORE_LOCAL_STORAGE_PREFIX}last-processed-pairing-statement`;
case "AuthSession":
Expand All @@ -252,7 +256,11 @@ function coreLocalStorageKey(key: CoreStorageKey): string {
}

function storesSecretMaterial(key: CoreStorageKey): boolean {
return key.tag === "AllowanceKeys" || key.tag === "AutoSigningKey";
return (
key.tag === "AllowanceKeys" ||
key.tag === "AutoSigningKey" ||
key.tag === "AutoSigningKeys"
);
}

async function encodeCoreStorageValue(
Expand Down
47 changes: 47 additions & 0 deletions packages/ui/src/host-callbacks/SupportedChains.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// dot.li — TrUAPI supported-chains callback (RFC 0026)
//
// Maps the protocol's closed chain-role enum onto the active environment's
// config slots. The core answers `chain.getChainInfo` from this one set,
// resolving a requested identifier and mapping a miss to `NotSupported`.
//
// The set is filtered through the same per-backend predicate as
// `featureSupported`, so the two advertisements can never disagree: in
// RPC-gateway mode Bulletin is intentionally absent (its content is served
// via IPFS gateways; the core-owned Bulletin connection seam in `Chain.ts`
// is not a product-facing advertisement).

import type { Features } from "@parity/truapi-host";
import type { ChainIdentifier } from "@parity/truapi";
import { toHexString } from "@parity/truapi/scale";
import { getBackend } from "@dotli/config/mode";
import { getActiveServicesConfig, getNetwork } from "@dotli/config/network";
import { isChainSupported as isSmoldotChainSupported } from "@dotli/resolver/chains";
import { isRpcChainSupported } from "@dotli/resolver/rpc-chain";

export function createSupportedChains(): Features["supportedChains"] {
return () => {
const cfg = getActiveServicesConfig();
const slots: { identifier: ChainIdentifier; genesis: string }[] = [
{ identifier: "Relay", genesis: cfg.relay.genesis },
{ identifier: "AssetHub", genesis: cfg.assethub.genesis },
{ identifier: "People", genesis: cfg.people.genesis },
{ identifier: "Bulletin", genesis: cfg.bulletin.genesis },
];
const isSupported =
getBackend() === "rpc-gateway"
? isRpcChainSupported
: isSmoldotChainSupported;
// The environment id ("paseo-next-v2"), not a bare ecosystem ("paseo"):
// the field is informational and two environments of one ecosystem must
// stay distinguishable in product logs.
return Promise.resolve({
network: getNetwork(),
chains: slots
.filter(({ genesis }) => isSupported(genesis))
.map(({ identifier, genesis }) => ({
identifier,
genesisHash: toHexString(genesis),
})),
});
};
}
2 changes: 1 addition & 1 deletion packages/ui/src/host-callbacks/UserConfirmation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ function formatRawPayload(payload: RawPayload): string {
}

function formatDerivationIndex(index: DerivationIndex): string {
return index.tag === "Left" ? String(index.value) : index.value;
return index.tag === "Index" ? String(index.value) : index.value;
}

function formatProductAccount(account: ProductAccountId): string {
Expand Down
6 changes: 5 additions & 1 deletion packages/ui/src/host-callbacks/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { createPreimageAdapters } from "./Preimage";
import { createChainConnect } from "./Chain";
import { createFeatureSupported } from "./FeatureSupported";
import { createSupportedChains } from "./SupportedChains";
import { createThemeSubscribe } from "./Theme";
import { createAuthStateChanged } from "./AuthState";
import { createSessionStoreAdapters } from "./SessionStore";
Expand Down Expand Up @@ -62,7 +63,10 @@ export function createHostCallbacks(
blockingModalScope,
promptLimiter,
),
features: { featureSupported: createFeatureSupported() },
features: {
featureSupported: createFeatureSupported(),
supportedChains: createSupportedChains(),
},
productStorage: {
read: createLocalStorageRead(),
write: createLocalStorageWrite(),
Expand Down
3 changes: 2 additions & 1 deletion packages/ui/tests/debug-wire-describe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ describe("chain-family drift guard", () => {
// When
const derived = [...derivedTagRoots, ...controlOnlyTags];

// Then: pins the exact current 15-entry legacy vocabulary as a literal
// Then: pins the exact current 16-entry legacy vocabulary as a literal
// snapshot, so it can't drift silently.
expect(derived).toEqual([
"remote_chain_head_follow",
Expand All @@ -344,6 +344,7 @@ describe("chain-family drift guard", () => {
"remote_chain_spec_genesis_hash",
"remote_chain_spec_chain_name",
"remote_chain_spec_properties",
"remote_chain_info",
"remote_chain_transaction_broadcast",
"remote_chain_transaction_stop",
"remote_chain_head_follow_stop",
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/tests/legacy-host-bridge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ describe("createLegacyNovaChainHeadProvider", () => {
value: {
productAccountId: {
dotNsIdentifier: "localhost:3000.dot",
derivationIndex: { tag: "Left", value: 0 },
derivationIndex: { tag: "Index", value: 0 },
},
},
}),
Expand Down Expand Up @@ -214,7 +214,7 @@ describe("createLegacyNovaChainHeadProvider", () => {
value: {
productAccountId: {
dotNsIdentifier: "other-product.dot",
derivationIndex: { tag: "Left", value: 0 },
derivationIndex: { tag: "Index", value: 0 },
},
},
}),
Expand Down
19 changes: 11 additions & 8 deletions packages/ui/tests/session-store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,25 @@ async function flushMicrotasks(): Promise<void> {
await Promise.resolve();
}

// The core reports these as `Bytes32` (hex), so the UI state carries them
// through unchanged rather than encoding them.
const SESSION_PUBLIC_KEY =
"0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
const SESSION_IDENTITY_ACCOUNT_ID =
"0xa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf";

function connectedSessionUiInfo() {
return {
publicKey: new Uint8Array(Array.from({ length: 32 }, (_, i) => i)),
identityAccountId: new Uint8Array(
Array.from({ length: 32 }, (_, i) => 0xa0 + i),
),
publicKey: SESSION_PUBLIC_KEY,
identityAccountId: SESSION_IDENTITY_ACCOUNT_ID,
liteUsername: "pgherveou.04",
};
}

const CONNECTED_DETAIL = {
connected: true,
publicKey:
"0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
identityAccountId:
"0xa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf",
publicKey: SESSION_PUBLIC_KEY,
identityAccountId: SESSION_IDENTITY_ACCOUNT_ID,
liteUsername: "pgherveou.04",
primaryUsername: "pgherveou.04",
};
Expand Down
10 changes: 5 additions & 5 deletions packages/ui/tests/user-confirmation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ describe("user confirmation modal", () => {
value: {
account: {
dotNsIdentifier: "truapi-playground.dot",
derivationIndex: { tag: "Left", value: 2 },
derivationIndex: { tag: "Index", value: 2 },
},
payload: {
blockHash:
Expand Down Expand Up @@ -228,7 +228,7 @@ describe("user confirmation modal", () => {
request: {
account: {
dotNsIdentifier: "other-product.dot",
derivationIndex: { tag: "Left", value: 4 },
derivationIndex: { tag: "Index", value: 4 },
},
transcriptLabel: "0x706f703a61697264726f70",
items: [
Expand Down Expand Up @@ -271,7 +271,7 @@ describe("user confirmation modal", () => {
value: {
signer: {
dotNsIdentifier: "truapi-playground.dot",
derivationIndex: { tag: "Left", value: 3 },
derivationIndex: { tag: "Index", value: 3 },
},
genesisHash:
"0xbf0488dbe9daa1de1c08c5f743e26fdc2a4ecd74cf87dd1b4b1eeb99ae4ef19f",
Expand Down Expand Up @@ -347,7 +347,7 @@ describe("user confirmation modal", () => {
callingProductId: "truapi-playground.dot",
context: {
productId: "truapix-playground.dot",
suffix: { tag: "Left", value: 0 },
suffix: { tag: "Index", value: 0 },
},
ringLocation: {
chainId:
Expand Down Expand Up @@ -397,7 +397,7 @@ describe("user confirmation modal", () => {
callingProductId: "truapi-playground.dot",
context: {
productId: "truapix-playground.dot",
suffix: { tag: "Left", value: 0 },
suffix: { tag: "Index", value: 0 },
},
ringLocation: {
chainId:
Expand Down
Loading