Skip to content

refactor!: retire the Token suffix - #348

Draft
zguesmi wants to merge 1 commit into
pr/b-unify-transferfrom
pr/c-drop-token-suffix
Draft

refactor!: retire the Token suffix#348
zguesmi wants to merge 1 commit into
pr/b-unify-transferfrom
pr/c-drop-token-suffix

Conversation

@zguesmi

@zguesmi zguesmi commented Aug 31, 2026

Copy link
Copy Markdown
Member

Stacked on #347.

Native-asset mode is gone (#343), so the Token suffix no longer distinguishes anything.

Before After
contracts/facets/IexecEscrowTokenFacet.sol -> IexecEscrowTokenFacet contracts/facets/IexecEscrowFacet.sol -> IexecEscrowFacet
contracts/interfaces/IexecEscrowToken.sol -> IexecEscrowToken contracts/interfaces/IexecEscrow.sol -> IexecEscrow
contracts/IexecInterfaceToken.sol -> IexecInterfaceToken contracts/IexecInterface.sol -> IexecInterface (retires the TODO)
contracts/abstract/IexecEscrow.sol -> IexecEscrow contracts/abstract/IexecEscrowBase.sol -> IexecEscrowBase

IexecTokenSpender keeps its name: it describes ERC-20 receiveApproval semantics, not a native/token distinction.

The name collision

contracts/abstract/IexecEscrow.sol already declared an abstract contract named IexecEscrow, so one of the two had to move. The abstract was renamed to IexecEscrowBase and the interface took the clean name.

Why that way round:

  1. Interfaces are the published surface. They ship in abis/contracts/interfaces/ and are what the SDK and integrators compile against. The abstract is an internal implementation detail that never appears in a consumer's import.
  2. The repository already uses the Base suffix for exactly this role: FacetBase is the shared abstract every facet inherits. IexecEscrowBase reads the same way.
  3. It matches the new facet name: IexecEscrowFacet is ... IexecEscrowBase is self-explanatory, where IexecEscrowFacet is ... IexecEscrow would have read as "the facet inherits the interface it implements" and hidden which of the two IexecEscrow declarations was meant.

Two IexecEscrow declarations in different directories are not shipped: there is exactly one, the interface.

Consequences

Function selectors are unaffected. A contract's name is not part of a selector, so nothing about the deployed protocol surface changes. The ABI contents are byte-identical to the old paths, verified by diffing against the pre-rename snapshot:

abis/contracts/facets/IexecEscrowTokenFacet.json == abis/contracts/facets/IexecEscrowFacet.json   (identical)
abis/contracts/IexecInterfaceToken.json          == abis/contracts/IexecInterface.json            (identical)

Published ABI paths change (breaking for anyone importing them by path):

Removed Added
abis/contracts/facets/IexecEscrowTokenFacet.json abis/contracts/facets/IexecEscrowFacet.json
abis/contracts/IexecInterfaceToken.json abis/contracts/IexecInterface.json
abis/contracts/interfaces/IexecEscrowToken.json abis/contracts/interfaces/IexecEscrow.json
abis/contracts/abstract/IexecEscrow.json abis/contracts/abstract/IexecEscrowBase.json

(plus the mirrored human-readable-abis/ entries)

Deployment artifacts. deployments/{arbitrum,arbitrumSepolia}/IexecEscrowTokenFacet.json is deliberately left in place — it records what is deployed right now. hardhat-deploy keys artifacts by contract name, so the next upgrade writes IexecEscrowFacet.json alongside the old file; removeDanglingFacetDeploymentArtifacts in utils/proxy-tools.ts deletes the stale one once the new facet is on-chain.

Hand-maintained lists updated, since neither is generated:

  • the selector map getAllLocalFacetFunctions in utils/proxy-tools.ts
  • the facet groups in scripts/tools/sol-to-uml.mjs (['IexecEscrowFacet', 'IexecEscrowBase'])

Historical records left alone. The upgrade reports under scripts/upgrades/*.md and CHANGELOG.md keep the old names — they are the record of what was actually deployed. scripts/upgrades/v6.2.0.ts needed the one change that makes it compile (the typechain factory identifier); its recorded name: 'IexecEscrowTokenFacet' strings and addresses are untouched, with a comment saying why. That file already carries a name: 'IexecERC20Facet' entry for a facet that no longer exists, so this matches how the script is treated.

Two test files were renamed with the contracts they cover, and one more to keep the names unambiguous:

Before After
test/byContract/IexecEscrow/IexecEscrowToken.test.ts test/byContract/IexecEscrow/IexecEscrow.test.ts
test/byContract/IexecEscrow/IexecEscrowToken-receiveApproval.test.ts test/byContract/IexecEscrow/IexecEscrow-receiveApproval.test.ts
test/byContract/IexecPocoBoost/IexecEscrow.test.ts test/byContract/IexecPocoBoost/IexecEscrowBase.test.ts

The last one exercises the abstract through IexecEscrowTestContract; without the rename the repository would have had two IexecEscrow.test.ts files meaning different things.

Downstream notice needed

The iExec SDK and the subgraph need advance notice. The SDK references the aggregate by path (contracts/IexecInterfaceToken.sol) — that path and the interface name both change. The subgraph is unaffected at the event level (no topic0 moves, no ABI content changes) but will need the new artifact path if it consumes abis/ by filename.

Not changed

The IexecEscrow: prefix on the _transfer revert reasons stays. Those strings are observable behavior; a rename must not move them. They now name the interface rather than the abstract, which is documented in IexecEscrowBase.

Verification

Gate Result
npm run build compiled 119 Solidity files successfully
npm run check-storage-layout pass, exit 0, no output
npm run doc regenerated, docs/solidity/index.md committed
npm run sol-to-uml regenerated with the new names, SVGs committed
npx tsc --noEmit the 6 known pre-existing errors, no new ones
npm test 514 passing, 6 pending, 0 failing (same as base)
npm run format:check All matched files use Prettier code style

npm run format was needed after the rename: five test files had import lines that reflowed once the identifiers got shorter.

Native-asset mode is gone, so the `Token` suffix no longer distinguishes
anything.

-   `IexecEscrowTokenFacet` becomes `IexecEscrowFacet`
-   the interface `IexecEscrowToken` becomes `IexecEscrow`
-   `IexecInterfaceToken` becomes `IexecInterface`

The abstract contract that was named `IexecEscrow` becomes `IexecEscrowBase`,
so the clean name goes to the interface. Interfaces are the published surface
consumers compile against, and the repository already uses the `Base` suffix
for shared abstracts (`FacetBase`).

`IexecTokenSpender` keeps its name: it describes ERC-20 `receiveApproval`
semantics, not a native/token distinction.

The `IexecEscrow:` prefix of the `_transfer` revert reasons is left alone.
Those strings are observable behavior; renaming a contract must not change
them.

BREAKING CHANGE: published ABI paths and artifact names change.

-   `abis/contracts/facets/IexecEscrowTokenFacet.json` becomes
    `abis/contracts/facets/IexecEscrowFacet.json`
-   `abis/contracts/IexecInterfaceToken.json` becomes
    `abis/contracts/IexecInterface.json`
-   `abis/contracts/interfaces/IexecEscrowToken.json` becomes
    `abis/contracts/interfaces/IexecEscrow.json`
-   `abis/contracts/abstract/IexecEscrow.json` becomes
    `abis/contracts/abstract/IexecEscrowBase.json`

Function selectors are unaffected: a contract name is not part of a selector,
so there is no protocol break. The ABI contents are byte-identical to the
previous paths.

The iExec SDK and the subgraph need advance notice, since the SDK references
`contracts/IexecInterfaceToken.sol` by path.

`deployments/{arbitrum,arbitrumSepolia}/IexecEscrowTokenFacet.json` is left in
place: it records what is deployed. `hardhat-deploy` keys artifacts by contract
name, so the next upgrade writes `IexecEscrowFacet.json` next to it and
`removeDanglingFacetDeploymentArtifacts` deletes the stale one.

The hand-maintained lists were updated: `getAllLocalFacetFunctions` in
`utils/proxy-tools.ts` and the facet groups in `scripts/tools/sol-to-uml.mjs`.
The historical upgrade reports under `scripts/upgrades/` keep the old names.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.53%. Comparing base (f932325) to head (161ddda).

Additional details and impacted files
@@                 Coverage Diff                  @@
##           pr/b-unify-transfer     #348   +/-   ##
====================================================
  Coverage                99.53%   99.53%           
====================================================
  Files                       31       31           
  Lines                     1083     1083           
  Branches                   220      220           
====================================================
  Hits                      1078     1078           
  Misses                       5        5           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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