paritytech / paritytech/contract-dependency-manager
TypeScript version pinning: honor the cdm.json pin in ContractManager calls (needs ~20 lines in product-sdk)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 4
- Forks
- 3
- Avg merge
- 4d 13h
- Merged PRs (30d)
- 3
Description
Problem
Since #76, cdm install pins an exact version per dependency — cdm.json carries {version: "1.2.1", address: <stable proxy>, abi} and the ABI is version-exact. But TypeScript consumers still get latest execution: ContractManager encodes calldata from the pinned ABI and sends it plain, and the per-name proxy routes plain calldata to the latest implementation. Result today: "1.2.1's ABI, latest's implementation" — safe only as long as publishers honor semver.
The on-chain side is fully deployed and e2e-proven: prefixing calldata with [MAGIC 0xa2264d53][u128 versionKey] makes the proxy execute exactly that version (UnsupportedVersion() below the owner's minSupported floor). What's missing is only the last-mile wiring in the TS call path.
Where the work lives
~20 lines in product-sdk-contracts, ~0 lines here. ContractManager's buildReviveCall assembles [selector][args] and sends it through exactly two choke points — the ReviveApi.call dry-run and the Revive.call transaction. Prefix injection belongs at those two sites (an optional calldata-prefix threaded through, inert when unset). Doing it CDM-side would mean duplicating product-sdk's call pipeline (weight estimation, revert decoding) in a wrapper.
Better still: ContractManager.fromClient(cdmJson, …) is already CDM-aware — it reads each entry's address from cdm.json. It can read the pinned version from the same entry and derive the 20-byte prefix itself (keccak256("cdm.proxy.call.v1")[..4] ++ major<<64|minor<<32|patch as big-endian u128 — mirrored with tests in @parity/cdm-builder/proxy).
End-user surface
Unchanged — the pin becomes true instead of cosmetic:
const contracts = ContractManager.fromClient(cdmJson, chain.raw.assetHub, paseo_asset_hub);
const counter = contracts.getContract("@yourorg/counter"); // cdm.json pins 1.2.1
await counter.increment.tx(); // executes 1.2.1, not latest
with following-latest becoming the explicit opt-in:
contracts.getContract("@yourorg/counter", { version: "latest" });
Tasks
- product-sdk: optional calldata prefix through
buildReviveCall's dry-run + tx sites (or native cdm.jsonversionawareness deriving it) - product-sdk:
{ version: "latest" }opt-out ongetContract - here: catalog bump once released; docs + a pinned-execution e2e case (the wire helpers and proxy routing are already covered by
proxy.e2e.test.ts)
References
- #76 — wire format (
contract-registry-core::versioning, mirrored insrc/lib/contracts/src/proxy.ts);proxy.e2e.test.tsproves versioned routing +UnsupportedVersiongating on-chain. - Rust consumers have the same gap with a different blocker (upstream
CallBuilderpreamble in cargo-pvm-contract); Solidity's counterpart is tracked separately.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in product-sdk-contracts at ContractManager.buildReviveCall and trace the ReviveApi.call dry-run and Revive.call transaction sites. Compare the version-prefix helpers and tests in @parity/cdm-builder/proxy and proxy.e2e.test.ts. Done means pinned cdm.json versions execute correctly, latest is an explicit opt-out, and the catalog, docs, and pinned-execution e2e case are updated here.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, blockchain
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100