paritytech / paritytech/contract-dependency-manager

Solidity version pinning: generate pinned() wrappers in the .cdm/solidity imports

Open
#79 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
4
Forks
3
Avg merge
4d 13h
Merged PRs (30d)
3

Description

Problem

Since #76, Solidity consumers get the stable per-name proxy address baked into their generated imports (.cdm/solidity/<scope>/<pkg>.sol), but calls through the typed ref() interface are plain calldata — the proxy routes them to the latest implementation. The version pinned at cdm install time affects only the generated interface's shape, not execution.

No toolchain blocker — this is pure codegen

Solidity's low-level .call/.staticcall accept arbitrary bytes, and the import files are generated by solidity-imports.ts (fully owned here). The generator can bake the CDM wire prefix as constants and emit one pinned wrapper per ABI method:

// generated — users never write this
bytes4  private constant CDM_MAGIC = 0xa2264d53;             // keccak256("cdm.proxy.call.v1")[..4]
uint128 private constant CDM_KEY   = <major<<64|minor<<32|patch>; // pinned at install time

function increment() internal {
    (bool ok, bytes memory ret) = ADDRESS.call(
        abi.encodePacked(CDM_MAGIC, CDM_KEY, abi.encodeCall(IExampleCounter.increment, ()))
    );
    if (!ok) _bubble(ret); // revert with the proxy/impl's exact revert data
}

User surface becomes a choice of two one-liners:

ExampleCounter.ref().increment();      // follow latest (today's behavior)
ExampleCounter.pinned().increment();   // execute exactly the installed version

Details

  • Views/pure → staticcall; returns abi.decoded in the generated wrapper.
  • Reverts bubble the raw returndata so proxy errors (UnsupportedVersion(uint128,uint128), ContractFrozen(), …) surface with their real selectors.
  • The pinned() shape (library of free functions vs a struct-wrapped handle mirroring ref()) is the main design choice — whatever reads best next to the existing ref()/cdm() surface.
  • Constants derive from the same pinned version the generator already receives; cdm i regenerates on version change as it does today.

References

  • #76 — wire format and on-chain routing (e2e-proven in proxy.e2e.test.ts); src/lib/contracts/src/solidity-imports.ts — the generator this lands in. TypeScript and Rust pinning are tracked separately.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/lib/contracts/src/solidity-imports.ts and compare the existing ref()/cdm() generated surface with the pinned() design options described in the issue. Use the wire format and routing behavior from #76 and proxy.e2e.test.ts as references. Done means generated imports expose pinned wrappers that route to the installed version, decode view/pure returns, use staticcall where appropriate, and preserve raw revert data.

Written by the indexing model from the issue text.

Assessment

Tech stack
solidity, typescript
Domain
blockchain
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.