@parity/product-sdk-contracts 0.5.1 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -2
- package/dist/{chunk-YZ3YBERU.js → chunk-2UN4YA25.js} +2 -2
- package/dist/chunk-2UN4YA25.js.map +1 -0
- package/dist/codegen.d.ts +1 -1
- package/dist/codegen.js +1 -1
- package/dist/codegen.js.map +1 -1
- package/dist/index.d.ts +34 -184
- package/dist/index.js +106 -19
- package/dist/index.js.map +1 -1
- package/dist/pvm.d.ts +1 -1
- package/dist/pvm.js +1 -1
- package/dist/types-DzYW54TT.d.ts +435 -0
- package/package.json +4 -4
- package/dist/chunk-YZ3YBERU.js.map +0 -1
- package/dist/types-BdHp-xWt.d.ts +0 -196
package/README.md
CHANGED
|
@@ -92,7 +92,7 @@ Order, highest wins:
|
|
|
92
92
|
1. Explicit `{ signer }` / `{ origin }` in the call options
|
|
93
93
|
2. `signerManager`'s currently selected account
|
|
94
94
|
3. Static `defaultSigner` / `defaultOrigin`
|
|
95
|
-
4. (Queries only)
|
|
95
|
+
4. (Queries only) pallet-revive account fallback for the dry-run
|
|
96
96
|
|
|
97
97
|
Throws `ContractSignerMissingError` from `.tx()` if no signer is available. `.query()` and `.prepare()` never need a signer.
|
|
98
98
|
|
|
@@ -113,6 +113,31 @@ Without this, every fresh-account `.tx()` fails the pre-flight dry-run with `Acc
|
|
|
113
113
|
|
|
114
114
|
Every `.tx()` runs a `ReviveApi.call` dry-run first to size `weight_limit` / `storage_deposit_limit` and to fail fast on revert, OOG, or `AccountNotMapped` before any signing happens. Throws `ContractDryRunFailedError` (with the chain's `dispatchError`) when the dry-run reports failure — caller pays no gas on a tx the chain already rejected. Pass both `gasLimit` and `storageDepositLimit` overrides on `TxOptions` to skip the dry-run entirely.
|
|
115
115
|
|
|
116
|
+
## Query block selection
|
|
117
|
+
|
|
118
|
+
`.query()` and the `.tx()` / `.prepare()` sizing dry-runs target best-block by default, matching `submitAndWatch`'s default resolution. This keeps reads consistent with the state a freshly-submitted transaction observes.
|
|
119
|
+
|
|
120
|
+
Override per call via `QueryOptions.at`, `TxOptions.at`, or `PrepareOptions.at` — each accepts `"best"`, `"finalized"`, or a block hash:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
await counter.getCount.query(); // best-block (default)
|
|
124
|
+
await counter.getCount.query({ at: "finalized" }); // canonical, lagged
|
|
125
|
+
await counter.getCount.query({ at: blockHash }); // pin to a historical block
|
|
126
|
+
|
|
127
|
+
await counter.increment.tx({ at: "finalized" }); // size the dry-run against finalized
|
|
128
|
+
await counter.increment.prepare({ at: blockHash }); // pin the batched call's sizing dry-run
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`.tx({ at })` / `.prepare({ at })` is a no-op when both `gasLimit` and `storageDepositLimit` overrides are supplied — the sizing dry-run is skipped entirely in that case.
|
|
132
|
+
|
|
133
|
+
Change the runtime default by passing `{ at }` to the factory:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
const runtime = createContractRuntimeFromClient(client.raw.assetHub, paseo_asset_hub, {
|
|
137
|
+
at: "finalized", // read finalized state by default
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
116
141
|
## Batching with `.prepare()`
|
|
117
142
|
|
|
118
143
|
Use `.prepare()` to build `BatchableCall` handles consumable by `batchSubmitAndWatch` from `@parity/product-sdk-tx`. Combine multiple contract calls — or contract calls mixed with other Asset Hub transactions — into a single atomic `Utility.batch_all` extrinsic.
|
|
@@ -126,7 +151,7 @@ const b = registry.publish.prepare("app-two00", "ipfs://...", 0);
|
|
|
126
151
|
await batchSubmitAndWatch([a, b], client.raw.assetHub, signer);
|
|
127
152
|
```
|
|
128
153
|
|
|
129
|
-
**`.prepare()` doesn't require a signer.** The resolved origin is used
|
|
154
|
+
**`.prepare()` doesn't require a signer.** The resolved origin is only used for the dry-run; the batch submission's signer is the dispatched origin at submission time.
|
|
130
155
|
|
|
131
156
|
`PrepareOptions` accepts: `origin`, `value`, `gasLimit`, `storageDepositLimit`. Signer and submission lifecycle options (`signer`, `waitFor`, etc.) are intentionally absent — those belong to the batch submit, not the individual prepared call.
|
|
132
157
|
|
|
@@ -49,5 +49,5 @@ async function loadPvmContractArtifacts(basePath) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export { loadPvmContractAbi, loadPvmContractArtifacts, loadPvmContractCode, parsePvmContractAbi };
|
|
52
|
-
//# sourceMappingURL=chunk-
|
|
53
|
-
//# sourceMappingURL=chunk-
|
|
52
|
+
//# sourceMappingURL=chunk-2UN4YA25.js.map
|
|
53
|
+
//# sourceMappingURL=chunk-2UN4YA25.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pvm.ts"],"names":[],"mappings":";AAqBO,SAAS,oBAAoB,MAAA,EAA6B;AAC7D,EAAA,IAAI,KAAA,GAAiB,MAAA;AAErB,EAAA,IAAI,iBAAiB,UAAA,EAAY;AAC7B,IAAA,KAAA,GAAQ,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,KAAK,CAAA;AAAA,EAC1C;AACA,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,IAAA,IAAI;AACA,MAAA,KAAA,GAAQ,IAAA,CAAK,MAAM,KAAK,CAAA;AAAA,IAC5B,SAAS,KAAA,EAAO;AACZ,MAAA,MAAM,IAAI,KAAA,CAAM,iCAAA,EAAmC,EAAE,OAAO,CAAA;AAAA,IAChE;AAAA,EACJ;AACA,EAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,MAAM,OAAA,CAAQ,KAAK,CAAA,IAAK,KAAA,IAAS,KAAA,EAAO;AAC/E,IAAA,KAAA,GAAS,KAAA,CAA2B,GAAA;AAAA,EACxC;AACA,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACvB,IAAA,MAAM,IAAI,MAAM,mDAAmD,CAAA;AAAA,EACvE;AACA,EAAA,KAAA,MAAW,SAAS,KAAA,EAAO;AACvB,IAAA,IAAI,CAAC,SAAS,OAAO,KAAA,KAAU,YAAY,OAAQ,KAAA,CAAmB,SAAS,QAAA,EAAU;AACrF,MAAA,MAAM,IAAI,KAAA;AAAA,QACN;AAAA,OACJ;AAAA,IACJ;AACA,IAAA,MAAM,SAAU,KAAA,CAAmB,MAAA;AACnC,IAAA,IAAI,WAAW,MAAA,IAAa,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAChD,MAAA,MAAM,IAAI,MAAM,yDAAyD,CAAA;AAAA,IAC7E;AAAA,EACJ;AACA,EAAA,OAAO,KAAA;AACX;AAOA,eAAsB,mBAAmB,IAAA,EAAmC;AACxE,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,MAAM,OAAO,aAAkB,CAAA;AACpD,EAAA,MAAM,GAAA,GAAM,MAAM,QAAA,CAAS,IAAI,CAAA;AAC/B,EAAA,OAAO,oBAAoB,GAAG,CAAA;AAClC;AAYA,eAAsB,oBAAoB,IAAA,EAAmC;AACzE,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,MAAM,OAAO,aAAkB,CAAA;AACpD,EAAA,MAAM,GAAA,GAAM,MAAM,QAAA,CAAS,IAAI,CAAA;AAC/B,EAAA,OAAO,IAAI,UAAA,CAAW,GAAA,CAAI,QAAQ,GAAA,CAAI,UAAA,EAAY,IAAI,UAAU,CAAA;AACpE;AAYA,eAAsB,yBAAyB,QAAA,EAAiD;AAC5F,EAAA,MAAM,CAAC,GAAA,EAAK,QAAQ,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,IACtC,kBAAA,CAAmB,CAAA,EAAG,QAAQ,CAAA,SAAA,CAAW,CAAA;AAAA,IACzC,mBAAA,CAAoB,CAAA,EAAG,QAAQ,CAAA,QAAA,CAAU;AAAA,GAC5C,CAAA;AACD,EAAA,OAAO,EAAE,KAAK,QAAA,EAAS;AAC3B","file":"chunk-2UN4YA25.js","sourcesContent":["// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\nimport type { AbiEntry } from \"./types.js\";\n\n/** ABI + PolkaVM bytecode pair emitted by `cargo pvm-contract build`. */\nexport interface PvmContractArtifacts {\n abi: AbiEntry[];\n bytecode: Uint8Array;\n}\n\n/**\n * Parse an in-memory cargo-pvm-contract ABI artifact.\n *\n * Accepts the shapes the toolchain may produce or that products may pass:\n * - parsed JSON array — `AbiEntry[]`\n * - parsed JSON object with an `abi` property — `{ abi: AbiEntry[] }`\n * - JSON string of either of the above\n * - `Uint8Array` containing UTF-8 JSON of either of the above\n *\n * @throws if the input cannot be coerced to a non-empty `AbiEntry[]`.\n */\nexport function parsePvmContractAbi(source: unknown): AbiEntry[] {\n let value: unknown = source;\n\n if (value instanceof Uint8Array) {\n value = new TextDecoder().decode(value);\n }\n if (typeof value === \"string\") {\n try {\n value = JSON.parse(value);\n } catch (cause) {\n throw new Error(\"Invalid PVM ABI: not valid JSON\", { cause });\n }\n }\n if (value && typeof value === \"object\" && !Array.isArray(value) && \"abi\" in value) {\n value = (value as { abi: unknown }).abi;\n }\n if (!Array.isArray(value)) {\n throw new Error(\"Invalid PVM ABI: expected an array of ABI entries\");\n }\n for (const entry of value) {\n if (!entry || typeof entry !== \"object\" || typeof (entry as AbiEntry).type !== \"string\") {\n throw new Error(\n \"Invalid PVM ABI: every entry must have a string `type` (function/event/constructor/...)\",\n );\n }\n const inputs = (entry as AbiEntry).inputs;\n if (inputs !== undefined && !Array.isArray(inputs)) {\n throw new Error(\"Invalid PVM ABI: `inputs` must be an array when present\");\n }\n }\n return value as AbiEntry[];\n}\n\n/**\n * Read a cargo-pvm-contract ABI file from disk and parse it.\n *\n * Node-only. For browser/in-memory inputs use {@link parsePvmContractAbi}.\n */\nexport async function loadPvmContractAbi(path: string): Promise<AbiEntry[]> {\n const { readFile } = await import(\"node:fs/promises\");\n const buf = await readFile(path);\n return parsePvmContractAbi(buf);\n}\n\n/**\n * Read the `.polkavm` bytecode artifact produced by `cargo pvm-contract build`.\n *\n * Returned bytes are ready to hand to `Revive.instantiate_with_code` (or to\n * any future deploy helper layered on top of it). Use this when you already\n * have an ABI in hand (e.g. inline or fetched separately) and only need the\n * PolkaVM blob — otherwise prefer {@link loadPvmContractArtifacts}.\n *\n * Node-only.\n */\nexport async function loadPvmContractCode(path: string): Promise<Uint8Array> {\n const { readFile } = await import(\"node:fs/promises\");\n const buf = await readFile(path);\n return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n}\n\n/**\n * Read both the `.abi.json` and `.polkavm` artifacts produced by\n * `cargo pvm-contract build` for a given base path.\n *\n * `basePath` is the path prefix shared by both files — typically\n * `target/<name>.release`. The function reads `${basePath}.abi.json` and\n * `${basePath}.polkavm`.\n *\n * Node-only.\n */\nexport async function loadPvmContractArtifacts(basePath: string): Promise<PvmContractArtifacts> {\n const [abi, bytecode] = await Promise.all([\n loadPvmContractAbi(`${basePath}.abi.json`),\n loadPvmContractCode(`${basePath}.polkavm`),\n ]);\n return { abi, bytecode };\n}\n\nif (import.meta.vitest) {\n const { test, expect, describe, beforeAll, afterAll } = import.meta.vitest;\n\n const sampleAbi: AbiEntry[] = [\n { type: \"constructor\", inputs: [], stateMutability: \"nonpayable\" },\n {\n type: \"function\",\n name: \"increment\",\n inputs: [],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"get\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint32\" }],\n stateMutability: \"view\",\n },\n ];\n\n describe(\"parsePvmContractAbi\", () => {\n test(\"accepts a parsed AbiEntry[] array directly\", () => {\n expect(parsePvmContractAbi(sampleAbi)).toEqual(sampleAbi);\n });\n\n test(\"accepts a wrapped { abi } object\", () => {\n expect(parsePvmContractAbi({ abi: sampleAbi })).toEqual(sampleAbi);\n });\n\n test(\"accepts a JSON string of an array\", () => {\n expect(parsePvmContractAbi(JSON.stringify(sampleAbi))).toEqual(sampleAbi);\n });\n\n test(\"accepts a JSON string of a wrapped object\", () => {\n expect(parsePvmContractAbi(JSON.stringify({ abi: sampleAbi }))).toEqual(sampleAbi);\n });\n\n test(\"accepts a UTF-8 Uint8Array\", () => {\n const bytes = new TextEncoder().encode(JSON.stringify(sampleAbi));\n expect(parsePvmContractAbi(bytes)).toEqual(sampleAbi);\n });\n\n test(\"throws on invalid JSON string\", () => {\n expect(() => parsePvmContractAbi(\"{not json\")).toThrow(/not valid JSON/);\n });\n\n test(\"throws when input is not an array\", () => {\n expect(() => parsePvmContractAbi(42)).toThrow(/expected an array/);\n expect(() => parsePvmContractAbi({ foo: \"bar\" })).toThrow(/expected an array/);\n });\n\n test(\"throws when an entry is missing `type`\", () => {\n expect(() => parsePvmContractAbi([{ name: \"noType\" }])).toThrow(/string `type`/);\n });\n\n test(\"throws when `inputs` is not an array\", () => {\n expect(() =>\n parsePvmContractAbi([{ type: \"function\", inputs: \"not an array\" }]),\n ).toThrow(/`inputs` must be an array/);\n });\n\n test(\"treats null as invalid\", () => {\n expect(() => parsePvmContractAbi(null)).toThrow();\n });\n });\n\n describe(\"loadPvmContractAbi / loadPvmContractArtifacts\", () => {\n // Cover the Node-only filesystem helpers via a real tmpdir round-trip.\n // The cargo-pvm-contract toolchain emits files at\n // target/<name>.release.abi.json\n // target/<name>.release.polkavm\n // — we recreate that layout here.\n let dir = \"\";\n let base = \"\";\n let lonely = \"\";\n let badAbi = \"\";\n // Minimal PolkaVM magic (`PVM\\0`) is enough to exercise the path —\n // we don't validate bytecode contents in the loader.\n const fakeBytecode = new Uint8Array([0x50, 0x56, 0x4d, 0x00, 0x01, 0x02, 0x03]);\n\n beforeAll(async () => {\n const { mkdtempSync, writeFileSync } = await import(\"node:fs\");\n const { tmpdir } = await import(\"node:os\");\n const { join } = await import(\"node:path\");\n dir = mkdtempSync(join(tmpdir(), \"pvm-loader-test-\"));\n base = join(dir, \"counter.release\");\n lonely = join(dir, \"lonely.release\");\n badAbi = join(dir, \"bad.release\");\n writeFileSync(`${base}.abi.json`, JSON.stringify(sampleAbi));\n writeFileSync(`${base}.polkavm`, fakeBytecode);\n writeFileSync(`${lonely}.abi.json`, JSON.stringify(sampleAbi));\n writeFileSync(`${badAbi}.abi.json`, \"{not valid json\");\n });\n\n afterAll(async () => {\n const { rmSync } = await import(\"node:fs\");\n try {\n rmSync(dir, { recursive: true, force: true });\n } catch {\n /* ignore */\n }\n });\n\n test(\"loadPvmContractAbi parses a JSON file from disk\", async () => {\n const abi = await loadPvmContractAbi(`${base}.abi.json`);\n expect(abi).toEqual(sampleAbi);\n });\n\n test(\"loadPvmContractArtifacts reads abi + bytecode pair\", async () => {\n const out = await loadPvmContractArtifacts(base);\n expect(out.abi).toEqual(sampleAbi);\n expect(out.bytecode).toBeInstanceOf(Uint8Array);\n expect(Array.from(out.bytecode)).toEqual(Array.from(fakeBytecode));\n });\n\n test(\"loadPvmContractCode reads only the .polkavm blob\", async () => {\n const code = await loadPvmContractCode(`${base}.polkavm`);\n expect(code).toBeInstanceOf(Uint8Array);\n expect(Array.from(code)).toEqual(Array.from(fakeBytecode));\n });\n\n test(\"loadPvmContractAbi rejects a missing file\", async () => {\n await expect(loadPvmContractAbi(`${base}.does-not-exist`)).rejects.toThrow();\n });\n\n test(\"loadPvmContractArtifacts rejects when bytecode is missing\", async () => {\n // Only `${lonely}.abi.json` exists — `.polkavm` is absent.\n await expect(loadPvmContractArtifacts(lonely)).rejects.toThrow();\n });\n\n test(\"loadPvmContractAbi propagates parse errors with helpful message\", async () => {\n await expect(loadPvmContractAbi(`${badAbi}.abi.json`)).rejects.toThrow(\n /not valid JSON/,\n );\n });\n });\n}\n"]}
|
package/dist/codegen.d.ts
CHANGED
package/dist/codegen.js
CHANGED
package/dist/codegen.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/codegen.ts"],"names":[],"mappings":"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","file":"codegen.js","sourcesContent":["import type { AbiEntry, AbiParam } from \"./types.js\";\nimport { loadPvmContractAbi } from \"./pvm.js\";\n\n/** A contract input to {@link generateContractTypes}: either an inline ABI or a `cargo-pvm-contract` artefact path. */\nexport type ContractTypeInput =\n | { library: string; abi: AbiEntry[] }\n | { library: string; abiPath: string };\n\n/**\n * Resolve a heterogeneous list of {@link ContractTypeInput} entries into the\n * `{ library, abi }` shape consumed by {@link generateContractTypes}. Reads any\n * `abiPath` entries off disk via {@link loadPvmContractAbi} (Node only).\n *\n * @example\n * ```ts\n * const resolved = await resolveContractTypeInputs([\n * { library: \"@example/counter\", abiPath: \"./target/counter.release.abi.json\" },\n * { library: \"@example/inline\", abi: counterAbi },\n * ]);\n * const src = generateContractTypes(resolved);\n * ```\n */\nexport async function resolveContractTypeInputs(\n inputs: readonly ContractTypeInput[],\n): Promise<{ library: string; abi: AbiEntry[] }[]> {\n return Promise.all(\n inputs.map(async (input) => {\n if (\"abi\" in input) return { library: input.library, abi: input.abi };\n return { library: input.library, abi: await loadPvmContractAbi(input.abiPath) };\n }),\n );\n}\n\n/** Map a Solidity ABI type to its TypeScript equivalent. */\nfunction mapSolidityType(param: AbiParam): string {\n const t = param.type;\n\n // Dynamic arrays — e.g. uint256[]\n if (t.endsWith(\"[]\")) {\n const inner = { ...param, type: t.slice(0, -2) };\n return `${mapSolidityType(inner)}[]`;\n }\n\n // Fixed-size arrays — e.g. uint256[3]\n const fixedArrayMatch = t.match(/^(.+)\\[(\\d+)\\]$/);\n if (fixedArrayMatch) {\n const inner = { ...param, type: fixedArrayMatch[1] };\n return `${mapSolidityType(inner)}[]`;\n }\n\n // Tuple\n if (t === \"tuple\" && param.components) {\n const fields = param.components.map((c) => `${c.name}: ${mapSolidityType(c)}`);\n return `{ ${fields.join(\"; \")} }`;\n }\n\n // Unsigned integers — uint8/16/32 fit in JS number\n if (/^uint(8|16|32)$/.test(t)) return \"number\";\n if (/^uint\\d*$/.test(t)) return \"bigint\";\n\n // Signed integers\n if (/^int(8|16|32)$/.test(t)) return \"number\";\n if (/^int\\d*$/.test(t)) return \"bigint\";\n\n // Address\n if (t === \"address\") return \"HexString\";\n\n // Bytes — viem's ABI codec accepts hex strings (`0x…`) for both\n // variable-length `bytes` and fixed-length `bytesN`. We surface\n // `SizedHex<N>` for the latter so consumers see the byte width at\n // compile time, even though the runtime check is just on the prefix.\n if (t === \"bytes\") return \"HexString\";\n const bytesMatch = t.match(/^bytes(\\d+)$/);\n if (bytesMatch) return `SizedHex<${bytesMatch[1]}>`;\n\n // Primitives\n if (t === \"bool\") return \"boolean\";\n if (t === \"string\") return \"string\";\n\n return \"unknown\";\n}\n\nfunction generateMethodArgsType(inputs: AbiParam[]): string {\n if (inputs.length === 0) return \"[]\";\n const parts = inputs.map((p) => `${p.name}: ${mapSolidityType(p)}`);\n return `[${parts.join(\", \")}]`;\n}\n\nfunction generateMethodResponseType(outputs: AbiParam[] | undefined): string {\n if (!outputs || outputs.length === 0) return \"undefined\";\n if (outputs.length === 1) return mapSolidityType(outputs[0]);\n const fields = outputs.map((o, i) => {\n const name = o.name || `_${i}`;\n return `${name}: ${mapSolidityType(o)}`;\n });\n return `{ ${fields.join(\"; \")} }`;\n}\n\n/**\n * Generate a TypeScript module augmentation that extends the\n * {@link Contracts} interface with typed method signatures for each\n * installed contract.\n *\n * The output is written to `.cdm/contracts.d.ts` (or equivalent) and\n * augments `\"@parity/product-sdk-contracts\"` so that\n * `ContractManager.getContract()` returns fully-typed handles.\n *\n * Accepts `{ library, abi }` directly. To pull ABIs from\n * `cargo-pvm-contract` build artefacts on disk, use\n * {@link resolveContractTypeInputs} first.\n *\n * @example\n * ```ts\n * // Inline ABIs\n * const src = generateContractTypes([\n * { library: \"@example/counter\", abi },\n * ]);\n * writeFileSync(\".cdm/contracts.d.ts\", src);\n *\n * // From cargo-pvm-contract artefacts\n * const resolved = await resolveContractTypeInputs([\n * { library: \"@example/counter\", abiPath: \"./target/counter.release.abi.json\" },\n * ]);\n * writeFileSync(\".cdm/contracts.d.ts\", generateContractTypes(resolved));\n * ```\n */\nexport function generateContractTypes(contracts: { library: string; abi: AbiEntry[] }[]): string {\n const lines: string[] = [\n \"// Auto-generated by cdm install — do not edit\",\n 'import type { HexString, SizedHex } from \"polkadot-api\";',\n \"\",\n 'declare module \"@parity/product-sdk-contracts\" {',\n \" interface Contracts {\",\n ];\n\n for (const contract of contracts) {\n const methods = contract.abi.filter((e) => e.type === \"function\" && e.name);\n lines.push(` \"${contract.library}\": {`);\n lines.push(\" methods: {\");\n for (const method of methods) {\n const args = generateMethodArgsType(method.inputs);\n const response = generateMethodResponseType(method.outputs);\n lines.push(\n ` ${method.name!}: { args: ${args}; response: ${response} };`,\n );\n }\n lines.push(\" };\");\n lines.push(\" };\");\n }\n\n lines.push(\" }\");\n lines.push(\"}\");\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\nif (import.meta.vitest) {\n const { test, expect, describe } = import.meta.vitest;\n\n describe(\"mapSolidityType\", () => {\n const cases: [AbiParam, string][] = [\n [{ name: \"x\", type: \"uint8\" }, \"number\"],\n [{ name: \"x\", type: \"uint16\" }, \"number\"],\n [{ name: \"x\", type: \"uint32\" }, \"number\"],\n [{ name: \"x\", type: \"uint64\" }, \"bigint\"],\n [{ name: \"x\", type: \"uint128\" }, \"bigint\"],\n [{ name: \"x\", type: \"uint256\" }, \"bigint\"],\n [{ name: \"x\", type: \"int8\" }, \"number\"],\n [{ name: \"x\", type: \"int32\" }, \"number\"],\n [{ name: \"x\", type: \"int64\" }, \"bigint\"],\n [{ name: \"x\", type: \"int256\" }, \"bigint\"],\n [{ name: \"x\", type: \"address\" }, \"HexString\"],\n [{ name: \"x\", type: \"bool\" }, \"boolean\"],\n [{ name: \"x\", type: \"string\" }, \"string\"],\n [{ name: \"x\", type: \"bytes\" }, \"HexString\"],\n [{ name: \"x\", type: \"bytes32\" }, \"SizedHex<32>\"],\n [{ name: \"x\", type: \"bytes4\" }, \"SizedHex<4>\"],\n [{ name: \"x\", type: \"uint256[]\" }, \"bigint[]\"],\n [{ name: \"x\", type: \"address[]\" }, \"HexString[]\"],\n [{ name: \"x\", type: \"uint256[3]\" }, \"bigint[]\"],\n [{ name: \"x\", type: \"somethingWeird\" }, \"unknown\"],\n ];\n\n for (const [param, expected] of cases) {\n test(`${param.type} → ${expected}`, () => {\n expect(mapSolidityType(param)).toBe(expected);\n });\n }\n\n test(\"tuple with components\", () => {\n const param: AbiParam = {\n name: \"info\",\n type: \"tuple\",\n components: [\n { name: \"addr\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n };\n expect(mapSolidityType(param)).toBe(\"{ addr: HexString; amount: bigint }\");\n });\n\n test(\"nested array of tuples\", () => {\n const param: AbiParam = {\n name: \"items\",\n type: \"tuple[]\",\n components: [\n { name: \"id\", type: \"uint32\" },\n { name: \"name\", type: \"string\" },\n ],\n };\n expect(mapSolidityType(param)).toBe(\"{ id: number; name: string }[]\");\n });\n });\n\n describe(\"generateMethodArgsType\", () => {\n test(\"empty inputs\", () => {\n expect(generateMethodArgsType([])).toBe(\"[]\");\n });\n\n test(\"single input\", () => {\n expect(generateMethodArgsType([{ name: \"to\", type: \"address\" }])).toBe(\n \"[to: HexString]\",\n );\n });\n\n test(\"multiple inputs\", () => {\n const result = generateMethodArgsType([\n { name: \"to\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ]);\n expect(result).toBe(\"[to: HexString, amount: bigint]\");\n });\n });\n\n describe(\"generateMethodResponseType\", () => {\n test(\"no outputs\", () => {\n expect(generateMethodResponseType(undefined)).toBe(\"undefined\");\n expect(generateMethodResponseType([])).toBe(\"undefined\");\n });\n\n test(\"single output\", () => {\n expect(generateMethodResponseType([{ name: \"\", type: \"uint32\" }])).toBe(\"number\");\n });\n\n test(\"multiple outputs\", () => {\n const result = generateMethodResponseType([\n { name: \"balance\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint32\" },\n ]);\n expect(result).toBe(\"{ balance: bigint; nonce: number }\");\n });\n\n test(\"unnamed outputs get positional names\", () => {\n const result = generateMethodResponseType([\n { name: \"\", type: \"bool\" },\n { name: \"\", type: \"uint256\" },\n ]);\n expect(result).toBe(\"{ _0: boolean; _1: bigint }\");\n });\n });\n\n describe(\"generateContractTypes\", () => {\n test(\"generates valid module augmentation\", () => {\n const result = generateContractTypes([\n {\n library: \"@example/counter\",\n abi: [\n {\n type: \"constructor\",\n inputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"getCount\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"increment\",\n inputs: [],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n ],\n },\n ]);\n\n expect(result).toContain('declare module \"@parity/product-sdk-contracts\"');\n expect(result).toContain(\"interface Contracts\");\n expect(result).toContain('\"@example/counter\"');\n expect(result).toContain(\"getCount: { args: []; response: number };\");\n expect(result).toContain(\"increment: { args: []; response: undefined };\");\n // Should not include constructor\n expect(result).not.toContain(\"constructor\");\n });\n\n test(\"handles multiple contracts\", () => {\n const result = generateContractTypes([\n {\n library: \"@a/one\",\n abi: [\n {\n type: \"function\",\n name: \"foo\",\n inputs: [{ name: \"x\", type: \"uint256\" }],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n ],\n },\n {\n library: \"@b/two\",\n abi: [\n {\n type: \"function\",\n name: \"bar\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" }],\n },\n ],\n },\n ]);\n\n expect(result).toContain('\"@a/one\"');\n expect(result).toContain('\"@b/two\"');\n expect(result).toContain(\"foo: { args: [x: bigint]; response: boolean };\");\n expect(result).toContain(\"bar: { args: []; response: HexString };\");\n });\n\n test(\"empty contracts list\", () => {\n const result = generateContractTypes([]);\n expect(result).toContain(\"interface Contracts {\");\n expect(result).toContain(\"}\");\n });\n\n test(\"includes polkadot-api type imports\", () => {\n const result = generateContractTypes([]);\n expect(result).toContain(\"import type { HexString, SizedHex }\");\n expect(result).toContain('from \"polkadot-api\"');\n });\n });\n\n describe(\"resolveContractTypeInputs\", () => {\n test(\"passes inline { library, abi } through unchanged\", async () => {\n const abi: AbiEntry[] = [\n {\n type: \"function\",\n name: \"foo\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n ];\n const out = await resolveContractTypeInputs([{ library: \"@x/foo\", abi }]);\n expect(out).toEqual([{ library: \"@x/foo\", abi }]);\n });\n\n test(\"loads ABI from { abiPath } on disk\", async () => {\n const fs = await import(\"node:fs/promises\");\n const path = await import(\"node:path\");\n const os = await import(\"node:os\");\n const tmp = await fs.mkdtemp(path.join(os.tmpdir(), \"codegen-\"));\n const abi: AbiEntry[] = [\n {\n type: \"function\",\n name: \"ping\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n ];\n const file = path.join(tmp, \"ping.release.abi.json\");\n await fs.writeFile(file, JSON.stringify(abi), \"utf8\");\n try {\n const out = await resolveContractTypeInputs([\n { library: \"@x/ping\", abiPath: file },\n ]);\n expect(out).toEqual([{ library: \"@x/ping\", abi }]);\n\n // And it composes with generateContractTypes end-to-end:\n const src = generateContractTypes(out);\n expect(src).toContain('\"@x/ping\"');\n expect(src).toContain(\"ping: { args: []; response: boolean };\");\n } finally {\n await fs.rm(tmp, { recursive: true, force: true });\n }\n });\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/codegen.ts"],"names":[],"mappings":"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","file":"codegen.js","sourcesContent":["// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\nimport type { AbiEntry, AbiParam } from \"./types.js\";\nimport { loadPvmContractAbi } from \"./pvm.js\";\n\n/** A contract input to {@link generateContractTypes}: either an inline ABI or a `cargo-pvm-contract` artefact path. */\nexport type ContractTypeInput =\n | { library: string; abi: AbiEntry[] }\n | { library: string; abiPath: string };\n\n/**\n * Resolve a heterogeneous list of {@link ContractTypeInput} entries into the\n * `{ library, abi }` shape consumed by {@link generateContractTypes}. Reads any\n * `abiPath` entries off disk via {@link loadPvmContractAbi} (Node only).\n *\n * @example\n * ```ts\n * const resolved = await resolveContractTypeInputs([\n * { library: \"@example/counter\", abiPath: \"./target/counter.release.abi.json\" },\n * { library: \"@example/inline\", abi: counterAbi },\n * ]);\n * const src = generateContractTypes(resolved);\n * ```\n */\nexport async function resolveContractTypeInputs(\n inputs: readonly ContractTypeInput[],\n): Promise<{ library: string; abi: AbiEntry[] }[]> {\n return Promise.all(\n inputs.map(async (input) => {\n if (\"abi\" in input) return { library: input.library, abi: input.abi };\n return { library: input.library, abi: await loadPvmContractAbi(input.abiPath) };\n }),\n );\n}\n\n/** Map a Solidity ABI type to its TypeScript equivalent. */\nfunction mapSolidityType(param: AbiParam): string {\n const t = param.type;\n\n // Dynamic arrays — e.g. uint256[]\n if (t.endsWith(\"[]\")) {\n const inner = { ...param, type: t.slice(0, -2) };\n return `${mapSolidityType(inner)}[]`;\n }\n\n // Fixed-size arrays — e.g. uint256[3]\n const fixedArrayMatch = t.match(/^(.+)\\[(\\d+)\\]$/);\n if (fixedArrayMatch) {\n const inner = { ...param, type: fixedArrayMatch[1] };\n return `${mapSolidityType(inner)}[]`;\n }\n\n // Tuple\n if (t === \"tuple\" && param.components) {\n const fields = param.components.map((c) => `${c.name}: ${mapSolidityType(c)}`);\n return `{ ${fields.join(\"; \")} }`;\n }\n\n // Unsigned integers — uint8/16/32 fit in JS number\n if (/^uint(8|16|32)$/.test(t)) return \"number\";\n if (/^uint\\d*$/.test(t)) return \"bigint\";\n\n // Signed integers\n if (/^int(8|16|32)$/.test(t)) return \"number\";\n if (/^int\\d*$/.test(t)) return \"bigint\";\n\n // Address\n if (t === \"address\") return \"HexString\";\n\n // Bytes — viem's ABI codec accepts hex strings (`0x…`) for both\n // variable-length `bytes` and fixed-length `bytesN`. We surface\n // `SizedHex<N>` for the latter so consumers see the byte width at\n // compile time, even though the runtime check is just on the prefix.\n if (t === \"bytes\") return \"HexString\";\n const bytesMatch = t.match(/^bytes(\\d+)$/);\n if (bytesMatch) return `SizedHex<${bytesMatch[1]}>`;\n\n // Primitives\n if (t === \"bool\") return \"boolean\";\n if (t === \"string\") return \"string\";\n\n return \"unknown\";\n}\n\nfunction generateMethodArgsType(inputs: AbiParam[]): string {\n if (inputs.length === 0) return \"[]\";\n const parts = inputs.map((p) => `${p.name}: ${mapSolidityType(p)}`);\n return `[${parts.join(\", \")}]`;\n}\n\nfunction generateMethodResponseType(outputs: AbiParam[] | undefined): string {\n if (!outputs || outputs.length === 0) return \"undefined\";\n if (outputs.length === 1) return mapSolidityType(outputs[0]);\n const fields = outputs.map((o, i) => {\n const name = o.name || `_${i}`;\n return `${name}: ${mapSolidityType(o)}`;\n });\n return `{ ${fields.join(\"; \")} }`;\n}\n\n/**\n * Generate a TypeScript module augmentation that extends the\n * {@link Contracts} interface with typed method signatures for each\n * installed contract.\n *\n * The output is written to `.cdm/contracts.d.ts` (or equivalent) and\n * augments `\"@parity/product-sdk-contracts\"` so that\n * `ContractManager.getContract()` returns fully-typed handles.\n *\n * Accepts `{ library, abi }` directly. To pull ABIs from\n * `cargo-pvm-contract` build artefacts on disk, use\n * {@link resolveContractTypeInputs} first.\n *\n * @example\n * ```ts\n * // Inline ABIs\n * const src = generateContractTypes([\n * { library: \"@example/counter\", abi },\n * ]);\n * writeFileSync(\".cdm/contracts.d.ts\", src);\n *\n * // From cargo-pvm-contract artefacts\n * const resolved = await resolveContractTypeInputs([\n * { library: \"@example/counter\", abiPath: \"./target/counter.release.abi.json\" },\n * ]);\n * writeFileSync(\".cdm/contracts.d.ts\", generateContractTypes(resolved));\n * ```\n */\nexport function generateContractTypes(contracts: { library: string; abi: AbiEntry[] }[]): string {\n const lines: string[] = [\n \"// Auto-generated by cdm install — do not edit\",\n 'import type { HexString, SizedHex } from \"polkadot-api\";',\n \"\",\n 'declare module \"@parity/product-sdk-contracts\" {',\n \" interface Contracts {\",\n ];\n\n for (const contract of contracts) {\n const methods = contract.abi.filter((e) => e.type === \"function\" && e.name);\n lines.push(` \"${contract.library}\": {`);\n lines.push(\" methods: {\");\n for (const method of methods) {\n const args = generateMethodArgsType(method.inputs);\n const response = generateMethodResponseType(method.outputs);\n lines.push(\n ` ${method.name!}: { args: ${args}; response: ${response} };`,\n );\n }\n lines.push(\" };\");\n lines.push(\" };\");\n }\n\n lines.push(\" }\");\n lines.push(\"}\");\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\nif (import.meta.vitest) {\n const { test, expect, describe } = import.meta.vitest;\n\n describe(\"mapSolidityType\", () => {\n const cases: [AbiParam, string][] = [\n [{ name: \"x\", type: \"uint8\" }, \"number\"],\n [{ name: \"x\", type: \"uint16\" }, \"number\"],\n [{ name: \"x\", type: \"uint32\" }, \"number\"],\n [{ name: \"x\", type: \"uint64\" }, \"bigint\"],\n [{ name: \"x\", type: \"uint128\" }, \"bigint\"],\n [{ name: \"x\", type: \"uint256\" }, \"bigint\"],\n [{ name: \"x\", type: \"int8\" }, \"number\"],\n [{ name: \"x\", type: \"int32\" }, \"number\"],\n [{ name: \"x\", type: \"int64\" }, \"bigint\"],\n [{ name: \"x\", type: \"int256\" }, \"bigint\"],\n [{ name: \"x\", type: \"address\" }, \"HexString\"],\n [{ name: \"x\", type: \"bool\" }, \"boolean\"],\n [{ name: \"x\", type: \"string\" }, \"string\"],\n [{ name: \"x\", type: \"bytes\" }, \"HexString\"],\n [{ name: \"x\", type: \"bytes32\" }, \"SizedHex<32>\"],\n [{ name: \"x\", type: \"bytes4\" }, \"SizedHex<4>\"],\n [{ name: \"x\", type: \"uint256[]\" }, \"bigint[]\"],\n [{ name: \"x\", type: \"address[]\" }, \"HexString[]\"],\n [{ name: \"x\", type: \"uint256[3]\" }, \"bigint[]\"],\n [{ name: \"x\", type: \"somethingWeird\" }, \"unknown\"],\n ];\n\n for (const [param, expected] of cases) {\n test(`${param.type} → ${expected}`, () => {\n expect(mapSolidityType(param)).toBe(expected);\n });\n }\n\n test(\"tuple with components\", () => {\n const param: AbiParam = {\n name: \"info\",\n type: \"tuple\",\n components: [\n { name: \"addr\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n };\n expect(mapSolidityType(param)).toBe(\"{ addr: HexString; amount: bigint }\");\n });\n\n test(\"nested array of tuples\", () => {\n const param: AbiParam = {\n name: \"items\",\n type: \"tuple[]\",\n components: [\n { name: \"id\", type: \"uint32\" },\n { name: \"name\", type: \"string\" },\n ],\n };\n expect(mapSolidityType(param)).toBe(\"{ id: number; name: string }[]\");\n });\n });\n\n describe(\"generateMethodArgsType\", () => {\n test(\"empty inputs\", () => {\n expect(generateMethodArgsType([])).toBe(\"[]\");\n });\n\n test(\"single input\", () => {\n expect(generateMethodArgsType([{ name: \"to\", type: \"address\" }])).toBe(\n \"[to: HexString]\",\n );\n });\n\n test(\"multiple inputs\", () => {\n const result = generateMethodArgsType([\n { name: \"to\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ]);\n expect(result).toBe(\"[to: HexString, amount: bigint]\");\n });\n });\n\n describe(\"generateMethodResponseType\", () => {\n test(\"no outputs\", () => {\n expect(generateMethodResponseType(undefined)).toBe(\"undefined\");\n expect(generateMethodResponseType([])).toBe(\"undefined\");\n });\n\n test(\"single output\", () => {\n expect(generateMethodResponseType([{ name: \"\", type: \"uint32\" }])).toBe(\"number\");\n });\n\n test(\"multiple outputs\", () => {\n const result = generateMethodResponseType([\n { name: \"balance\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint32\" },\n ]);\n expect(result).toBe(\"{ balance: bigint; nonce: number }\");\n });\n\n test(\"unnamed outputs get positional names\", () => {\n const result = generateMethodResponseType([\n { name: \"\", type: \"bool\" },\n { name: \"\", type: \"uint256\" },\n ]);\n expect(result).toBe(\"{ _0: boolean; _1: bigint }\");\n });\n });\n\n describe(\"generateContractTypes\", () => {\n test(\"generates valid module augmentation\", () => {\n const result = generateContractTypes([\n {\n library: \"@example/counter\",\n abi: [\n {\n type: \"constructor\",\n inputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"getCount\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"increment\",\n inputs: [],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n ],\n },\n ]);\n\n expect(result).toContain('declare module \"@parity/product-sdk-contracts\"');\n expect(result).toContain(\"interface Contracts\");\n expect(result).toContain('\"@example/counter\"');\n expect(result).toContain(\"getCount: { args: []; response: number };\");\n expect(result).toContain(\"increment: { args: []; response: undefined };\");\n // Should not include constructor\n expect(result).not.toContain(\"constructor\");\n });\n\n test(\"handles multiple contracts\", () => {\n const result = generateContractTypes([\n {\n library: \"@a/one\",\n abi: [\n {\n type: \"function\",\n name: \"foo\",\n inputs: [{ name: \"x\", type: \"uint256\" }],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n ],\n },\n {\n library: \"@b/two\",\n abi: [\n {\n type: \"function\",\n name: \"bar\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" }],\n },\n ],\n },\n ]);\n\n expect(result).toContain('\"@a/one\"');\n expect(result).toContain('\"@b/two\"');\n expect(result).toContain(\"foo: { args: [x: bigint]; response: boolean };\");\n expect(result).toContain(\"bar: { args: []; response: HexString };\");\n });\n\n test(\"empty contracts list\", () => {\n const result = generateContractTypes([]);\n expect(result).toContain(\"interface Contracts {\");\n expect(result).toContain(\"}\");\n });\n\n test(\"includes polkadot-api type imports\", () => {\n const result = generateContractTypes([]);\n expect(result).toContain(\"import type { HexString, SizedHex }\");\n expect(result).toContain('from \"polkadot-api\"');\n });\n });\n\n describe(\"resolveContractTypeInputs\", () => {\n test(\"passes inline { library, abi } through unchanged\", async () => {\n const abi: AbiEntry[] = [\n {\n type: \"function\",\n name: \"foo\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n ];\n const out = await resolveContractTypeInputs([{ library: \"@x/foo\", abi }]);\n expect(out).toEqual([{ library: \"@x/foo\", abi }]);\n });\n\n test(\"loads ABI from { abiPath } on disk\", async () => {\n const fs = await import(\"node:fs/promises\");\n const path = await import(\"node:path\");\n const os = await import(\"node:os\");\n const tmp = await fs.mkdtemp(path.join(os.tmpdir(), \"codegen-\"));\n const abi: AbiEntry[] = [\n {\n type: \"function\",\n name: \"ping\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n ];\n const file = path.join(tmp, \"ping.release.abi.json\");\n await fs.writeFile(file, JSON.stringify(abi), \"utf8\");\n try {\n const out = await resolveContractTypeInputs([\n { library: \"@x/ping\", abiPath: file },\n ]);\n expect(out).toEqual([{ library: \"@x/ping\", abi }]);\n\n // And it composes with generateContractTypes end-to-end:\n const src = generateContractTypes(out);\n expect(src).toContain('\"@x/ping\"');\n expect(src).toContain(\"ping: { args: []; response: boolean };\");\n } finally {\n await fs.rm(tmp, { recursive: true, force: true });\n }\n });\n });\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,187 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { PolkadotClient, HexString } from 'polkadot-api';
|
|
2
|
+
import { C as CdmJson, a as ContractRuntime, b as ContractManagerOptions, c as ContractDefaults, d as ContractRuntimeOptions, e as Contracts, f as Contract, g as ContractDef, A as AbiEntry, h as ContractOptions } from './types-DzYW54TT.js';
|
|
3
|
+
export { i as AbiParam, j as CdmJsonContract, k as CdmJsonTarget, l as ContractDryRunAt, P as PrepareOptions, Q as QueryOptions, m as QueryResult, R as ReviveDryRunCall, n as ReviveDryRunCallOptions, o as ReviveDryRunResult, p as ReviveTypedApi, T as TxOptions, q as createContractRuntime, r as createContractRuntimeFromClient, s as ensureContractAccountMapped } from './types-DzYW54TT.js';
|
|
3
4
|
export { BatchableCall, TxResult } from '@parity/product-sdk-tx';
|
|
4
|
-
import { C as CdmJson, a as ContractManagerOptions, b as ContractDefaults, c as Contracts, d as Contract, e as ContractDef, A as AbiEntry, f as ContractOptions } from './types-BdHp-xWt.js';
|
|
5
|
-
export { g as AbiParam, h as CdmJsonContract, i as CdmJsonTarget, P as PrepareOptions, Q as QueryOptions, j as QueryResult, T as TxOptions } from './types-BdHp-xWt.js';
|
|
6
5
|
import '@parity/product-sdk-signer';
|
|
7
6
|
|
|
8
|
-
/**
|
|
9
|
-
* Result of a `Revive.call` extrinsic — present on the typed API as
|
|
10
|
-
* `api.tx.Revive.call(args)`. Returned object is a PAPI submittable that
|
|
11
|
-
* `submitAndWatch` consumes natively.
|
|
12
|
-
*
|
|
13
|
-
* `dest` is an H160 hex string and `data` is a raw `Uint8Array`: this matches
|
|
14
|
-
* what `polkadot-api` ≥2.0 codecs accept and produce. The class-based
|
|
15
|
-
* `Binary` / `FixedSizeBinary` wrappers from `@polkadot-api/substrate-bindings`
|
|
16
|
-
* 0.12 are *not* accepted by PAPI 2.x's compatibility check.
|
|
17
|
-
*/
|
|
18
|
-
type ReviveCallTx = (args: {
|
|
19
|
-
dest: HexString;
|
|
20
|
-
value: bigint;
|
|
21
|
-
weight_limit: Weight;
|
|
22
|
-
storage_deposit_limit: bigint;
|
|
23
|
-
data: Uint8Array;
|
|
24
|
-
}) => SubmittableTransaction;
|
|
25
|
-
/**
|
|
26
|
-
* Dry-run result returned by `ReviveApi.call`. Mirrors the shape exposed by
|
|
27
|
-
* descriptors (`paseo-asset-hub`, `polkadot-asset-hub`, `kusama-asset-hub`).
|
|
28
|
-
*
|
|
29
|
-
* `data` is a raw `Uint8Array` because PAPI ≥2.0 dropped the `Binary` class
|
|
30
|
-
* wrapper for `Vec<u8>` codecs.
|
|
31
|
-
*/
|
|
32
|
-
interface ReviveDryRunResult {
|
|
33
|
-
weight_consumed: Weight;
|
|
34
|
-
weight_required: Weight;
|
|
35
|
-
storage_deposit: {
|
|
36
|
-
type: "Refund" | "Charge";
|
|
37
|
-
value: bigint;
|
|
38
|
-
};
|
|
39
|
-
max_storage_deposit: {
|
|
40
|
-
type: "Refund" | "Charge";
|
|
41
|
-
value: bigint;
|
|
42
|
-
};
|
|
43
|
-
gas_consumed: bigint;
|
|
44
|
-
/**
|
|
45
|
-
* `success: true` carries `{ flags, data }`; `success: false` carries the
|
|
46
|
-
* dispatch error as the chain encoded it.
|
|
47
|
-
*/
|
|
48
|
-
result: {
|
|
49
|
-
success: true;
|
|
50
|
-
value: {
|
|
51
|
-
flags: number;
|
|
52
|
-
data: Uint8Array;
|
|
53
|
-
};
|
|
54
|
-
} | {
|
|
55
|
-
success: false;
|
|
56
|
-
value: unknown;
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
/** Structural shape consumed by `ContractManager` / `createContract`. */
|
|
60
|
-
interface ReviveTypedApi {
|
|
61
|
-
tx: {
|
|
62
|
-
Revive: {
|
|
63
|
-
call: ReviveCallTx;
|
|
64
|
-
map_account(): SubmittableTransaction;
|
|
65
|
-
};
|
|
66
|
-
};
|
|
67
|
-
query: {
|
|
68
|
-
Revive: {
|
|
69
|
-
OriginalAccount: {
|
|
70
|
-
getValue(address: HexString): Promise<SS58String | undefined>;
|
|
71
|
-
};
|
|
72
|
-
};
|
|
73
|
-
};
|
|
74
|
-
apis: {
|
|
75
|
-
ReviveApi: {
|
|
76
|
-
call(origin: SS58String, dest: HexString, value: bigint, gas_limit: Weight | undefined, storage_deposit_limit: bigint | undefined, input_data: Uint8Array): Promise<ReviveDryRunResult>;
|
|
77
|
-
};
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Signature of a `ReviveApi.call` dry-run, used by the wrapped contract layer
|
|
82
|
-
* to estimate weight + storage deposit and surface revert / OOG /
|
|
83
|
-
* `AccountNotMapped` failures before a tx is signed.
|
|
84
|
-
*
|
|
85
|
-
* Identical to `ReviveTypedApi.apis.ReviveApi.call`, but extracted so the
|
|
86
|
-
* runtime can route this single hot call through PAPI's *unsafe* API
|
|
87
|
-
* (skipping compatibility-token checks) on production runtimes whose
|
|
88
|
-
* descriptors lag a chain upgrade — every other surface still uses the
|
|
89
|
-
* compat-checked typed API.
|
|
90
|
-
*/
|
|
91
|
-
type ReviveDryRunCall = (origin: SS58String, dest: HexString, value: bigint, gas_limit: Weight | undefined, storage_deposit_limit: bigint | undefined, input_data: Uint8Array) => Promise<ReviveDryRunResult>;
|
|
92
|
-
/**
|
|
93
|
-
* Runtime handle that drives queries and transactions against a
|
|
94
|
-
* pallet-revive-capable chain.
|
|
95
|
-
*
|
|
96
|
-
* @example
|
|
97
|
-
* ```ts
|
|
98
|
-
* import { createChainClient } from "@parity/product-sdk-chain-client";
|
|
99
|
-
* import { paseo_asset_hub } from "@parity/product-sdk-descriptors/paseo-asset-hub";
|
|
100
|
-
* import { createContractRuntimeFromClient } from "@parity/product-sdk-contracts";
|
|
101
|
-
*
|
|
102
|
-
* const client = await createChainClient({
|
|
103
|
-
* chains: { assetHub: paseo_asset_hub },
|
|
104
|
-
* rpcs: { assetHub: ["wss://paseo-asset-hub-next-rpc.polkadot.io"] },
|
|
105
|
-
* });
|
|
106
|
-
* const runtime = createContractRuntimeFromClient(client.raw.assetHub, paseo_asset_hub);
|
|
107
|
-
* ```
|
|
108
|
-
*/
|
|
109
|
-
interface ContractRuntime {
|
|
110
|
-
readonly api: ReviveTypedApi;
|
|
111
|
-
/**
|
|
112
|
-
* Dry-run entry point. Production factories route this through the
|
|
113
|
-
* *unsafe* API to avoid compatibility-token failures when the descriptor
|
|
114
|
-
* trails a runtime upgrade. The {@link createContractRuntime} test factory
|
|
115
|
-
* delegates to `api.apis.ReviveApi.call`.
|
|
116
|
-
*/
|
|
117
|
-
readonly dryRunCall: ReviveDryRunCall;
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Wrap a typed PAPI API as a `ContractRuntime`. Intended for tests and
|
|
121
|
-
* advanced setups where the caller already holds a typed API. Routes the
|
|
122
|
-
* dry-run through the typed (compatibility-token-checked) `ReviveApi.call`
|
|
123
|
-
* — fine for mocks but susceptible to `Incompatible runtime entry` errors
|
|
124
|
-
* on a live chain whose descriptor lags. Prefer
|
|
125
|
-
* {@link createContractRuntimeFromClient} for production use.
|
|
126
|
-
*/
|
|
127
|
-
declare function createContractRuntime(api: ReviveTypedApi): ContractRuntime;
|
|
128
|
-
/**
|
|
129
|
-
* Build a `ContractRuntime` from a raw `PolkadotClient` plus its descriptor.
|
|
130
|
-
*
|
|
131
|
-
* The typed API powers `tx.Revive.call`, `tx.Revive.map_account`, and
|
|
132
|
-
* `query.Revive.OriginalAccount` (extrinsics + storage are tolerant of
|
|
133
|
-
* descriptor drift). The runtime-API dry-run, which is *not* tolerant of
|
|
134
|
-
* descriptor drift on PAPI's compat-token path, is routed through
|
|
135
|
-
* `client.getUnsafeApi()` — bypassing the compat check while preserving
|
|
136
|
-
* argument and return shapes.
|
|
137
|
-
*
|
|
138
|
-
* Use this on every production code path that calls a contract's `.tx()` or
|
|
139
|
-
* `.query()` against a live chain.
|
|
140
|
-
*
|
|
141
|
-
* @example
|
|
142
|
-
* ```ts
|
|
143
|
-
* import { paseo_asset_hub } from "@parity/product-sdk-descriptors/paseo-asset-hub";
|
|
144
|
-
* import { createContractRuntimeFromClient } from "@parity/product-sdk-contracts";
|
|
145
|
-
*
|
|
146
|
-
* const runtime = createContractRuntimeFromClient(rawClient, paseo_asset_hub);
|
|
147
|
-
* ```
|
|
148
|
-
*/
|
|
149
|
-
declare function createContractRuntimeFromClient<TDescriptor>(client: PolkadotClient, descriptor: TDescriptor): ContractRuntime;
|
|
150
|
-
/**
|
|
151
|
-
* Ensure the SS58 account is mapped to its derived H160 on `pallet-revive`.
|
|
152
|
-
*
|
|
153
|
-
* `pallet-revive` requires every signing account to have a registered
|
|
154
|
-
* `OriginalAccount` mapping before the runtime accepts its `Revive.call`
|
|
155
|
-
* extrinsics. The mapping is one-time and cheap. This helper:
|
|
156
|
-
*
|
|
157
|
-
* 1. Reads `Revive.OriginalAccount` for the H160 derived from `address`.
|
|
158
|
-
* 2. Returns `null` if already mapped (idempotent fast-path).
|
|
159
|
-
* 3. Otherwise submits `Revive.map_account()` and waits for inclusion.
|
|
160
|
-
*
|
|
161
|
-
* Call this once per signing account at app startup — after that, every
|
|
162
|
-
* subsequent `contract.<method>.tx({ signer })` against the same chain will
|
|
163
|
-
* succeed without further mapping work.
|
|
164
|
-
*
|
|
165
|
-
* @param runtime - The contract runtime (typically `createContractRuntime(...)`).
|
|
166
|
-
* @param address - The SS58 address of the account to map.
|
|
167
|
-
* @param signer - A signer matching `address`.
|
|
168
|
-
* @param options - Optional timeout / status callback (forwarded to the underlying tx).
|
|
169
|
-
* @returns The `TxResult` from the mapping extrinsic, or `null` if already mapped.
|
|
170
|
-
*
|
|
171
|
-
* @example
|
|
172
|
-
* ```ts
|
|
173
|
-
* import { createContractRuntime, ensureContractAccountMapped } from "@parity/product-sdk-contracts";
|
|
174
|
-
*
|
|
175
|
-
* const runtime = createContractRuntime(client.getTypedApi(paseo_asset_hub));
|
|
176
|
-
* await ensureContractAccountMapped(runtime, signerManager.getState().selectedAccount!.address, signer);
|
|
177
|
-
* // now safe to call contract.<method>.tx({ signer })
|
|
178
|
-
* ```
|
|
179
|
-
*/
|
|
180
|
-
declare function ensureContractAccountMapped(runtime: ContractRuntime, address: SS58String, signer: PolkadotSigner, options?: {
|
|
181
|
-
timeoutMs?: number;
|
|
182
|
-
onStatus?: (s: string) => void;
|
|
183
|
-
}): Promise<TxResult | null>;
|
|
184
|
-
|
|
185
7
|
/**
|
|
186
8
|
* Manages typed contract interactions backed by a `cdm.json` manifest.
|
|
187
9
|
*
|
|
@@ -231,7 +53,7 @@ declare class ContractManager {
|
|
|
231
53
|
* @param descriptor - The chain descriptor used to derive the typed API.
|
|
232
54
|
* @param options - Optional configuration (signerManager, defaults).
|
|
233
55
|
*/
|
|
234
|
-
static fromClient<TDescriptor>(cdmJson: CdmJson, client: PolkadotClient, descriptor: TDescriptor, options?: ContractManagerOptions): ContractManager;
|
|
56
|
+
static fromClient<TDescriptor>(cdmJson: CdmJson, client: PolkadotClient, descriptor: TDescriptor, options?: ContractManagerOptions & ContractRuntimeOptions): ContractManager;
|
|
235
57
|
private getContractData;
|
|
236
58
|
/**
|
|
237
59
|
* Get a typed contract handle.
|
|
@@ -282,7 +104,7 @@ declare function createContract(runtime: ContractRuntime, address: HexString, ab
|
|
|
282
104
|
* const { value } = await counter.getCount.query();
|
|
283
105
|
* ```
|
|
284
106
|
*/
|
|
285
|
-
declare function createContractFromClient<TDescriptor>(client: PolkadotClient, descriptor: TDescriptor, address: HexString, abi: AbiEntry[], options?: ContractOptions): Contract<ContractDef>;
|
|
107
|
+
declare function createContractFromClient<TDescriptor>(client: PolkadotClient, descriptor: TDescriptor, address: HexString, abi: AbiEntry[], options?: ContractOptions & ContractRuntimeOptions): Contract<ContractDef>;
|
|
286
108
|
|
|
287
109
|
/** Base class for all contract errors. Use `instanceof ContractError` to catch any contract-related error. */
|
|
288
110
|
declare class ContractError extends Error {
|
|
@@ -312,5 +134,33 @@ declare class ContractDryRunFailedError extends ContractError {
|
|
|
312
134
|
readonly dispatchError: unknown;
|
|
313
135
|
constructor(methodName: string, dispatchError: unknown);
|
|
314
136
|
}
|
|
137
|
+
/** viem-decoded standard or ABI-defined contract error. */
|
|
138
|
+
interface DecodedContractRevert {
|
|
139
|
+
errorName: string;
|
|
140
|
+
args: readonly unknown[] | undefined;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Tagged-enum value surfaced on `QueryResult.value` when a contract reverts
|
|
144
|
+
* via the REVERT flag. The discriminant is intentionally distinct from
|
|
145
|
+
* `pallet-revive`'s bare `{ type: "ContractReverted" }` dispatch-error variant,
|
|
146
|
+
* which is the other path that can populate `QueryResult.value` on failure.
|
|
147
|
+
*/
|
|
148
|
+
interface ContractRevertInfo {
|
|
149
|
+
type: "ContractRevertedWithPayload";
|
|
150
|
+
data: HexString;
|
|
151
|
+
reason?: string;
|
|
152
|
+
decoded?: DecodedContractRevert;
|
|
153
|
+
}
|
|
154
|
+
/** A contract call returned with the `REVERT` flag set on a dispatched-OK call. */
|
|
155
|
+
declare class ContractRevertedError extends ContractError {
|
|
156
|
+
readonly methodName: string;
|
|
157
|
+
readonly data: HexString;
|
|
158
|
+
readonly reason?: string;
|
|
159
|
+
readonly decoded?: DecodedContractRevert;
|
|
160
|
+
constructor(methodName: string, data: HexString, info?: {
|
|
161
|
+
reason?: string;
|
|
162
|
+
decoded?: DecodedContractRevert;
|
|
163
|
+
});
|
|
164
|
+
}
|
|
315
165
|
|
|
316
|
-
export { AbiEntry, CdmJson, Contract, ContractDef, ContractDefaults, ContractDryRunFailedError, ContractError, ContractManager, ContractManagerOptions, ContractNotFoundError, ContractOptions, type
|
|
166
|
+
export { AbiEntry, CdmJson, Contract, ContractDef, ContractDefaults, ContractDryRunFailedError, ContractError, ContractManager, ContractManagerOptions, ContractNotFoundError, ContractOptions, type ContractRevertInfo, ContractRevertedError, ContractRuntime, ContractRuntimeOptions, ContractSignerMissingError, Contracts, type DecodedContractRevert, createContract, createContractFromClient };
|