Skip to content

Commit faaffe4

Browse files
Merge pull request #409 from paritytech/chore/summit-descriptor-support
Prepare direct clients for Summit descriptors
2 parents d08abeb + d27cebd commit faaffe4

14 files changed

Lines changed: 245 additions & 45 deletions

.changeset/summit-w3s.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"playground-cli": patch
3+
---
4+
5+
Prepare direct chain clients for Summit descriptors when the active environment is switched.

DEPLOY.MD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ Expected: a `0x…` address. If it prints `(empty)`, the CDM `DEPLOY_DOC.md` isn
3636

3737
**b.** Flip the network switch in `src/config.ts`:
3838

39+
Update `ACTIVE_TESTNET_ENV`: `"paseo-next-v2"` -> `"summit"`.
40+
3941
```ts
4042
export const ACTIVE_TESTNET_ENV: Env = "summit"; // was "paseo-next-v2"
4143
```

src/commands/contract.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ import {
4444
resolveQueryOrigin,
4545
} from "@parity/cdm-env";
4646
import { createContractFromClient } from "@parity/product-sdk-contracts";
47-
import { paseo_asset_hub } from "@parity/product-sdk-descriptors/paseo-asset-hub";
48-
import { paseo_bulletin } from "@parity/product-sdk-descriptors/paseo-bulletin";
4947
import { DEFAULT_MNEMONIC as PAD_DEFAULT_MNEMONIC } from "@parity/polkadot-app-deploy";
5048
import { Command, Option } from "commander";
5149
import { createClient, type HexString, type SS58String } from "polkadot-api";
@@ -61,6 +59,7 @@ import {
6159
wrapSignerWithEvents,
6260
type SigningEvent,
6361
} from "../utils/deploy/signingProxy.js";
62+
import { getAssetHubDescriptor, getBulletinDescriptor } from "../utils/descriptors.js";
6463
import { onProcessShutdown } from "../utils/process-guard.js";
6564
import { resolveSigner, type ResolvedSigner, type SignerOptions } from "../utils/signer.js";
6665
import { runContractDeployWithUI } from "./contractDeployUi.js";
@@ -366,6 +365,9 @@ function asCdmAssetHubDescriptor(d: unknown): PipelineChainClient["descriptors"]
366365
async function createContractChainClient(
367366
target: ContractDeployTarget,
368367
): Promise<ContractChainClient> {
368+
const cfg = getChainConfig();
369+
const assetHubDescriptor = getAssetHubDescriptor(cfg.env);
370+
const bulletinDescriptor = getBulletinDescriptor(cfg.env);
369371
const raw = {
370372
assetHub: createClient(getWsProvider([target.assethubUrl])),
371373
bulletin: createClient(
@@ -388,12 +390,12 @@ async function createContractChainClient(
388390
}
389391

390392
return {
391-
assetHub: asCdmAssetHubApi(raw.assetHub.getTypedApi(paseo_asset_hub)),
392-
bulletin: raw.bulletin.getTypedApi(paseo_bulletin),
393+
assetHub: asCdmAssetHubApi(raw.assetHub.getTypedApi(assetHubDescriptor)),
394+
bulletin: raw.bulletin.getTypedApi(bulletinDescriptor),
393395
raw,
394396
descriptors: {
395-
assetHub: asCdmAssetHubDescriptor(paseo_asset_hub),
396-
bulletin: paseo_bulletin,
397+
assetHub: asCdmAssetHubDescriptor(assetHubDescriptor),
398+
bulletin: bulletinDescriptor,
397399
},
398400
destroy,
399401
};

src/config.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,12 @@ import { CONFIGS, DEFAULT_ENV, getPgasAssetId, type ChainConfig, type Env } from
4242
const { doc } = await loadEnvironments();
4343

4444
describe("getPgasAssetId", () => {
45-
it("returns the paseo-next-v2 PGAS asset id by default", () => {
46-
expect(getPgasAssetId("paseo-next-v2")).toBe(2_000_000_000);
45+
it("returns the active PGAS asset id by default", () => {
46+
expect(getPgasAssetId()).toBe(2_000_000_000);
4747
});
4848

4949
it("returns a number for every wired env", () => {
50+
expect(typeof getPgasAssetId("paseo-next-v2")).toBe("number");
5051
expect(typeof getPgasAssetId("summit")).toBe("number");
5152
});
5253
});

src/utils/account/drip.test.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
*/
2424

2525
import { describe, it, expect, vi, beforeEach } from "vitest";
26+
import { getTokenSymbol } from "../../config.js";
2627

2728
const mockSubmitAndWatch = vi
2829
.fn<(tx: unknown, signer: unknown, options?: unknown) => Promise<unknown>>()
@@ -46,6 +47,7 @@ const DEV_FUNDER = "5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV";
4647
const ONE_PAS = 10_000_000_000n;
4748
const SOURCE_BUFFER = ONE_PAS;
4849
const FUNDER_REQUIRED = DRIP_AMOUNT + SOURCE_BUFFER;
50+
const TOKEN_SYMBOL = getTokenSymbol();
4951
// Plenty of headroom so the preflight balance check passes in tests that
5052
// expect the transfer to fire.
5153
const FUNDER_HEALTHY = FUNDER_REQUIRED * 100n;
@@ -181,14 +183,14 @@ describe("dripToProductAccount", () => {
181183

182184
describe("formatPas", () => {
183185
it("renders whole amounts without a fraction", () => {
184-
expect(formatPas(0n)).toBe("0 PAS");
185-
expect(formatPas(ONE_PAS)).toBe("1 PAS");
186-
expect(formatPas(DRIP_CAP)).toBe("10 PAS");
186+
expect(formatPas(0n)).toBe(`0 ${TOKEN_SYMBOL}`);
187+
expect(formatPas(ONE_PAS)).toBe(`1 ${TOKEN_SYMBOL}`);
188+
expect(formatPas(DRIP_CAP)).toBe(`10 ${TOKEN_SYMBOL}`);
187189
});
188190

189191
it("trims trailing zeros and caps at 4 fractional digits", () => {
190-
expect(formatPas(ONE_PAS + ONE_PAS / 2n)).toBe("1.5 PAS");
191-
// 0.123456 PAS (1_234_560_000 planck at 10 decimals) -> truncated to 4 dp
192-
expect(formatPas(1_234_560_000n)).toBe("0.1234 PAS");
192+
expect(formatPas(ONE_PAS + ONE_PAS / 2n)).toBe(`1.5 ${TOKEN_SYMBOL}`);
193+
// 0.123456 token units (1_234_560_000 planck at 10 decimals) -> truncated to 4 dp
194+
expect(formatPas(1_234_560_000n)).toBe(`0.1234 ${TOKEN_SYMBOL}`);
193195
});
194196
});

src/utils/connection.test.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// limitations under the License.
1515

1616
import { describe, it, expect, vi, beforeEach } from "vitest";
17-
import { getNetworkLabel } from "../config.js";
17+
import { DEFAULT_ENV, getNetworkLabel } from "../config.js";
1818

1919
const mockCreateClient = vi.fn();
2020
const mockGetWsProvider = vi.fn();
@@ -41,10 +41,31 @@ vi.mock("@parity/product-sdk-descriptors/paseo-individuality", () => ({
4141
paseo_individuality: { genesis: "0xpeople" },
4242
}));
4343

44+
vi.mock("@parity/product-sdk-descriptors/summit-asset-hub", () => ({
45+
summit_asset_hub: { genesis: "0xsummit-asset" },
46+
}));
47+
48+
vi.mock("@parity/product-sdk-descriptors/summit-bulletin", () => ({
49+
summit_bulletin: { genesis: "0xsummit-bulletin" },
50+
}));
51+
52+
vi.mock("@parity/product-sdk-descriptors/summit-individuality", () => ({
53+
summit_individuality: { genesis: "0xsummit-people" },
54+
}));
55+
4456
// Re-import after each test to reset the singleton
4557
let getConnection: typeof import("./connection.js").getConnection;
4658
let destroyConnection: typeof import("./connection.js").destroyConnection;
4759

60+
const expectedActiveDescriptors =
61+
DEFAULT_ENV === "summit"
62+
? [
63+
{ genesis: "0xsummit-asset" },
64+
{ genesis: "0xsummit-bulletin" },
65+
{ genesis: "0xsummit-people" },
66+
]
67+
: [{ genesis: "0xasset" }, { genesis: "0xbulletin" }, { genesis: "0xpeople" }];
68+
4869
beforeEach(async () => {
4970
vi.resetModules();
5071
mockCreateClient.mockReset();
@@ -62,10 +83,13 @@ beforeEach(async () => {
6283
});
6384

6485
describe("getConnection", () => {
65-
it("creates direct clients for the three Paseo chains", async () => {
86+
it("creates direct clients with descriptors for the active chains", async () => {
6687
await getConnection();
6788
expect(mockCreateClient).toHaveBeenCalledTimes(3);
6889
expect(mockGetTypedApi).toHaveBeenCalledTimes(3);
90+
expect(mockGetTypedApi.mock.calls.map(([descriptor]) => descriptor)).toEqual(
91+
expectedActiveDescriptors,
92+
);
6993
});
7094

7195
it("returns the same client on subsequent calls (singleton)", async () => {

src/utils/connection.ts

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,24 @@ import {
2020
type TypedApi,
2121
} from "polkadot-api";
2222
import { getWsProvider } from "polkadot-api/ws";
23-
import { paseo_bulletin as bulletin } from "@parity/product-sdk-descriptors/paseo-bulletin";
24-
import { paseo_individuality as individuality } from "@parity/product-sdk-descriptors/paseo-individuality";
25-
import { paseo_asset_hub } from "@parity/product-sdk-descriptors/paseo-asset-hub";
2623
import { getChainConfig, getNetworkLabel } from "../config.js";
24+
import {
25+
getAssetHubDescriptor,
26+
getBulletinDescriptor,
27+
getIndividualityDescriptor,
28+
type AssetHubDescriptor,
29+
type BulletinDescriptor,
30+
type IndividualityDescriptor,
31+
} from "./descriptors.js";
2732

28-
// The chain DESCRIPTORS are intentionally the `paseo_*` ones for EVERY env,
29-
// including summit — only the RPC URLs are env-driven (via getChainConfig). This
30-
// mirrors `@parity/cdm-env`, whose `DEPLOY_CHAIN_DESCRIPTORS`/`ASSET_HUB_DESCRIPTORS`
31-
// also map `w3s` (summit) → `paseo_asset_hub`/`paseo_bulletin`; the deploy engine
32-
// `@parity/polkadot-app-deploy` is descriptor-free (live `getUnsafeApi()`). PAPI
33-
// typed calls decode by structural type IDs, so this holds as long as summit's
34-
// runtime shapes match paseo's (they do today — same testnet family). Dedicated
35-
// `summit-*` descriptors DO exist in `@parity/product-sdk-descriptors` as an escape
36-
// hatch if the runtimes ever diverge; switching to them before they're needed would
37-
// DIVERGE from the engine. See CLAUDE.md → "Adding a network / Summit".
33+
// The public type name remains `PaseoClient` for compatibility with the rest of
34+
// the codebase, but runtime descriptor selection follows the active env. When
35+
// DEFAULT_ENV is summit, direct PAPI reads use product-sdk's summit descriptors.
3836

3937
type PaseoChains = {
40-
assetHub: typeof paseo_asset_hub;
41-
bulletin: typeof bulletin;
42-
individuality: typeof individuality;
38+
assetHub: AssetHubDescriptor;
39+
bulletin: BulletinDescriptor;
40+
individuality: IndividualityDescriptor;
4341
};
4442

4543
export type PaseoClient = {
@@ -65,6 +63,11 @@ function typedApi<T extends ChainDefinition>(raw: PolkadotClient, descriptor: T)
6563

6664
async function connectPaseo(): Promise<PaseoClient> {
6765
const cfg = getChainConfig();
66+
const descriptors = {
67+
assetHub: getAssetHubDescriptor(cfg.env),
68+
bulletin: getBulletinDescriptor(cfg.env),
69+
individuality: getIndividualityDescriptor(cfg.env),
70+
};
6871
const raw = {
6972
assetHub: createRawClient([cfg.assetHubRpc]),
7073
bulletin: createRawClient([cfg.bulletinRpc, ...cfg.bulletinRpcFallbacks]),
@@ -73,9 +76,9 @@ async function connectPaseo(): Promise<PaseoClient> {
7376

7477
let destroyed = false;
7578
return {
76-
assetHub: typedApi(raw.assetHub, paseo_asset_hub),
77-
bulletin: typedApi(raw.bulletin, bulletin),
78-
individuality: typedApi(raw.individuality, individuality),
79+
assetHub: typedApi(raw.assetHub, descriptors.assetHub),
80+
bulletin: typedApi(raw.bulletin, descriptors.bulletin),
81+
individuality: typedApi(raw.individuality, descriptors.individuality),
7982
raw,
8083
destroy() {
8184
if (destroyed) return;

src/utils/deploy/bulletinAuthContext.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
// limitations under the License.
1515

1616
import { beforeEach, describe, expect, it, vi } from "vitest";
17+
import { DEFAULT_ENV } from "../../config.js";
1718

1819
const { createClientMock, getWsProviderMock, destroyMock, getTypedApiMock } = vi.hoisted(() => ({
1920
createClientMock: vi.fn(),
@@ -25,9 +26,15 @@ const { createClientMock, getWsProviderMock, destroyMock, getTypedApiMock } = vi
2526
vi.mock("polkadot-api", () => ({ createClient: createClientMock }));
2627
vi.mock("polkadot-api/ws", () => ({ getWsProvider: getWsProviderMock }));
2728
vi.mock("@parity/product-sdk-descriptors/paseo-bulletin", () => ({ paseo_bulletin: {} }));
29+
vi.mock("@parity/product-sdk-descriptors/summit-bulletin", () => ({
30+
summit_bulletin: { genesis: "0xsummit-bulletin" },
31+
}));
2832

2933
import { createBulletinAuthContext } from "./bulletinAuthContext.js";
3034

35+
const expectedActiveBulletinDescriptor =
36+
DEFAULT_ENV === "summit" ? { genesis: "0xsummit-bulletin" } : {};
37+
3138
beforeEach(() => {
3239
createClientMock.mockReset();
3340
getWsProviderMock.mockReset();
@@ -43,6 +50,7 @@ describe("createBulletinAuthContext", () => {
4350

4451
expect(ctx).not.toBeNull();
4552
expect(ctx?.bulletinApi).toEqual({ marker: "bulletin-api" });
53+
expect(getTypedApiMock).toHaveBeenCalledWith(expectedActiveBulletinDescriptor);
4654
expect(destroyMock).not.toHaveBeenCalled();
4755
ctx?.destroy();
4856
expect(destroyMock).toHaveBeenCalledTimes(1);

src/utils/deploy/bulletinAuthContext.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131

3232
import { createClient } from "polkadot-api";
3333
import { getWsProvider } from "polkadot-api/ws";
34-
import { paseo_bulletin as bulletin } from "@parity/product-sdk-descriptors/paseo-bulletin";
3534
import type { CloudStorageApi } from "@parity/product-sdk-cloud-storage";
3635
import { asCloudStorageApi } from "../allowances/bulletin.js";
3736
import { getChainConfig, type Env } from "../../config.js";
3837
import { BULLETIN_WS_HEARTBEAT_MS } from "../bulletinWs.js";
38+
import { getBulletinDescriptor } from "../descriptors.js";
3939

4040
export interface BulletinAuthContext {
4141
bulletinApi: CloudStorageApi;
@@ -59,7 +59,7 @@ export function createBulletinAuthContext(env: Env | undefined): BulletinAuthCon
5959
}),
6060
);
6161
return {
62-
bulletinApi: asCloudStorageApi(client.getTypedApi(bulletin)),
62+
bulletinApi: asCloudStorageApi(client.getTypedApi(getBulletinDescriptor(cfg.env))),
6363
destroy: () => client.destroy(),
6464
};
6565
} catch {

src/utils/deploy/playground.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ import { readFileSync, readdirSync, statSync } from "node:fs";
3636
import { join } from "node:path";
3737
import { createClient } from "polkadot-api";
3838
import { getWsProvider } from "polkadot-api/ws";
39-
import { paseo_bulletin as bulletin } from "@parity/product-sdk-descriptors/paseo-bulletin";
4039
import { calculateCid } from "@parity/product-sdk-cloud-storage";
4140
import { submitAndWatch, withRetry } from "@parity/product-sdk-tx";
4241
import { getRegistryContract } from "../registry.js";
4342
import { getConnection } from "../connection.js";
4443
import { getChainConfig, type Env } from "../../config.js";
44+
import { getBulletinDescriptor } from "../descriptors.js";
4545
import { captureWarning, withSpan, errorMessage } from "../../telemetry.js";
4646
import {
4747
asCloudStorageApi,
@@ -353,7 +353,7 @@ export async function publishToPlayground(
353353
}),
354354
);
355355
try {
356-
const bulletinApi = bulletinClient.getTypedApi(bulletin);
356+
const bulletinApi = bulletinClient.getTypedApi(getBulletinDescriptor(cfg.env));
357357
const cid = (await calculateCid(metadataBytes)).toString();
358358
const storeTx = bulletinApi.tx.TransactionStorage.store({ data: metadataBytes });
359359
let storageSigner = await getBulletinAllowanceSigner({

0 commit comments

Comments
 (0)