Skip to content

feat(protocol-core): add version-discriminated deployment addresses to ChainConfig - #30

Draft
henrypalacios wants to merge 3 commits into
refactor/protocol-core-drop-dead-chainsfrom
feat/protocol-core-deployments-schema
Draft

feat(protocol-core): add version-discriminated deployment addresses to ChainConfig#30
henrypalacios wants to merge 3 commits into
refactor/protocol-core-drop-dead-chainsfrom
feat/protocol-core-deployments-schema

Conversation

@henrypalacios

Copy link
Copy Markdown
Collaborator

Summary

  • Add an optional deployments list to ChainConfig, modelled as a union discriminated by protocol version, plus a getDeployment(chainId, version) lookup whose result narrows to the requested family.
  • Add an optional chain-level multicall address, which is version-agnostic.
  • Add checkDeploymentCoherence, run for every chain inside the existing pre-publish address validation, so each deployment entry targets a version its chain declares, appears once, and holds a real contract address.
  • Populate deployment data for Polygon and Polygon zkEVM.

Why

ChainConfig describes chain identity — chain id, name, native and wrapped native, the protocol versions the chain runs, its stablecoins — but it has never carried contract addresses. There is no canonical home for them in the package, so every consumer keeps its own address map and its own assumptions about which contracts each protocol family deploys. Those maps drift, and nothing in the SDK can tell a caller which factory or quoter belongs to which version on a given chain.

This change puts the addresses next to the chain identity that already exists, and encodes the differences between protocol families in the type system:

  • V2 pairs are fungible ERC20 tokens priced by closed-form constant-product math, so those entries carry no quoter and no position manager.
  • Only the Algebra families derive pool addresses from a pool deployer rather than from the factory.

Modelling deployments as a discriminated union makes those asymmetries compile errors instead of conventions a reader has to know, and getDeployment returns the family it was asked for.

Polygon zkEVM is the case that exercises this fully: it runs Algebra v3 alongside a Uniswap-V3 fork, and those two quoters expose different ABIs. Resolving them by version is what stops a caller reaching for the wrong one.

Size

The diff is large — 495 added lines — and roughly two thirds of it is tests. Source and script changes are 165 lines across 8 files; the remaining 330 lines are test coverage, including type-level assertions now enforced by vitest type-checking.

Changes

File Change
src/chains/types.ts ProtocolDeployment union discriminated by version; optional deployments and multicall on ChainConfig
src/chains/deployments.ts getDeployment(chainId, version) with a narrowing return type
src/chains/deploymentCoherence.ts checkDeploymentCoherence(chain) — pure function returning one message per violation
src/chains/polygon.ts Algebra v3 and v2 deployments, multicall
src/chains/zkevm.ts Algebra v3 and Uniswap-V3-fork deployments, multicall
src/index.ts Public exports for the new types and lookup
scripts/validate-addresses.ts Runs the coherence check per chain inside the existing validation loop
vitest.config.ts Enables type-checking over the test suite
src/__tests__/** Runtime and type-level coverage for the schema, the lookup, each coherence rule, and the new chain data

Every added field is optional, so existing chain configs and every published export keep their current shape. Every address is stored in EIP-55 checksum form.

Test plan

  • pnpm --filter @quickswap-defi/protocol-core test — 323 tests across 22 files pass, no type errors
  • pnpm --filter @quickswap-defi/protocol-core build — CJS, ESM and declaration builds succeed
  • pnpm --filter @quickswap-defi/protocol-core validate:addresses — 62 addresses validated, coherence check clean

@henrypalacios
henrypalacios marked this pull request as draft August 25, 2026 18:00
…lookup

Chain configs describe chain identity but carry no contract addresses, so every
consumer maintains its own address maps and its own assumptions about which
contracts each protocol family deploys.

Add an optional `deployments` list to `ChainConfig`, modelled as a union
discriminated by protocol version, together with `getDeployment(chainId,
version)` whose result narrows to the requested family. Required fields follow
the contracts a family actually deploys: V2 pairs are fungible ERC20 tokens
priced by closed-form constant-product math and therefore have no quoter and no
position manager, while only the Algebra families derive pool addresses from a
pool deployer instead of the factory. Modelling this as a union makes those
asymmetries compile errors rather than conventions.

Add an optional chain-level `multicall` address, which is version-agnostic.

Enable vitest type-checking over `*.test-d.ts` files so the type-level
assertions covering these rules are enforced, and keep that glob disjoint from
the runtime suite so no spec is collected twice.

Document the new surface in the package README.

Every added field is optional, so existing chain configs and every published
export keep their current shape.
Deployment data has to agree with the chain that declares it: every entry
targets a protocol version that chain actually lists, each version appears at
most once, and every address slot — the chain-level multicall included — holds
a real contract address. Those are registry-level rules, so they belong in the
same pass that already guards address format before publish.

Add `checkDeploymentCoherence` and run it for every chain inside the existing
validation loop, reporting through the same error list, the same exit code and
the same path grammar. The publish gate now guarantees that every deployment
entry reaching consumers is coherent with the protocols its chain declares.

Keeping the rules in a pure function leaves the script responsible only for
whole-registry wiring, so each rule is covered directly by unit tests.
… and IMX

Give the deployment schema real data on three chains. Polygon carries the
Algebra v3 and v2 entries; Manta Pacific and Immutable zkEVM each carry a
Uniswap-V3 fork entry. Together they cover both concentrated-liquidity
families, so a lookup returning the family it was asked for is exercised
across chains: the Algebra and Uniswap-V3 fork quoters expose different ABIs,
and resolving them by version is what stops a caller reaching for the wrong
one.

The Uniswap-V3 fork entries carry no pool deployer, since that family derives
pool addresses from the factory. Manta Pacific and Immutable zkEVM share a
factory and a position manager address; both are confirmed against the
deployed contracts.

All three chains also gain their multicall address. Every value is stored in
EIP-55 checksum form.
@henrypalacios
henrypalacios force-pushed the feat/protocol-core-deployments-schema branch from 7a714a1 to 8c76fd1 Compare August 26, 2026 21:51
@henrypalacios
henrypalacios changed the base branch from main to refactor/protocol-core-drop-dead-chains August 27, 2026 18:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant