diff --git a/.claude/context/architecture.md b/.claude/context/architecture.md new file mode 100644 index 00000000..0b3baa17 --- /dev/null +++ b/.claude/context/architecture.md @@ -0,0 +1,43 @@ +# Architecture + +## Diamond proxy + +`contracts/Diamond.sol` plus the standard `DiamondCutFacet` / `DiamondLoupeFacet` / `OwnershipFacet` / `DiamondInit`, pulled in through `hardhat-dependency-compiler` from `@mudgen/diamond-1`. + +- Protocol logic: `contracts/facets/*Facet.sol` +- External API declarations: `contracts/interfaces/` +- `contracts/IexecInterfaceToken.sol` aggregates them into the single interface downstream tools compile against +- Shared helpers: `contracts/abstract/` (`FacetBase`, `IexecPocoCommon`, `SignatureVerifier`, …) +- Storage lives in one struct accessed through `contracts/libs/PocoStorageLib.sol`, shared by every facet: **never reorder or remove an existing variable, only append**. `npm run check-storage-layout` is the CI gate. +- Adding or removing a facet means editing two hand-maintained lists: `utils/proxy-tools.ts#getAllLocalFacetFunctions` (selector-to-name map used by upgrades) and the facet groups in `scripts/tools/sol-to-uml.mjs`. + +Three solc versions: `0.8.21` with `viaIR` for PoCo contracts, `0.6.12` for the `@amxx/factory` dependency, `0.4.24` for RLC. A `docgen` task override in `hardhat.config.ts` temporarily hides 0.4 build-info files because docgen cannot parse them. + +## Deployment + +`deploy/0_deploy.ts` is the single source of truth. + +Boost facets (`IexecPocoBoostFacet`, `IexecPocoBoostAccessorsFacet`) are deliberately **not** deployed on Arbitrum mainnet/Sepolia — see the `isArbitrumMainnetOrSepolia` branch in `deploy/0_deploy.ts`. + +Changing `SALT` changes every derived address, which breaks integrations that rely on deterministic addresses. + +## Chain config + +- `token: null` makes the deployment deploy a fresh RLC mock; a real address makes it reuse that token. +- Registries are looked up before deployment, so several marketplaces on one chain share them. + +## Orders + +Off-chain EIP-712 orders (app / dataset / workerpool / request) are matched on-chain by `IexecPoco1Facet` (`matchOrders` plus sponsored variants) or, in the Boost flow, by `IexecPocoBoostFacet`. Structs and hashing live in the linked library `contracts/libs/IexecLibOrders_v5.sol`. The TypeScript side is `utils/createOrders.ts` (builders) and `utils/odb-tools.ts` (signing). + +## Task lifecycle + +`IexecPoco2Facet` implements initialize → contribute → reveal → finalize, with reopen and claim paths. Escrow and staking are in `IexecEscrowTokenFacet`: deposited RLC is tracked as an internal, non-transferable ERC-20-like balance. Enums and helpers mirroring on-chain state are in `utils/poco-tools.ts` (`TaskStatusEnum`, `ContributionStatusEnum`, `PocoMode`, `getDealId`, `getTaskId`, enclave/authorization signing, `getIexecAccounts`). + +## Registries + +`contracts/registries/` holds ERC-721 registries for apps, datasets and workerpools. Entries are minimal proxies (`RegistryEntry`, `InitializableUpgradeabilityProxy`) at create2-predictable addresses. + +## Token-only + +Native-asset mode and Bellecour (chain 134) support were removed across PRs #341-#344: no native escrow facet, no `IexecInterfaceNative`, no `asset` field in the chain config, and no `setName` ENS stubs on the registries. Only the token escrow path exists. diff --git a/.claude/context/commands.md b/.claude/context/commands.md new file mode 100644 index 00000000..d817d65a --- /dev/null +++ b/.claude/context/commands.md @@ -0,0 +1,21 @@ +# Commands and CI + +`package.json#scripts` is the command list. + +## Generated, never hand-edit + +| Output | Regenerated by | +| ------------------------ | ----------------------------- | +| `abis/**` | every compile (`clear: true`) | +| `typechain/` | every compile | +| `docs/solidity/index.md` | `npm run doc`, from NatSpec | +| `docs/uml/*.svg` | `npm run uml` | + +Edit the NatSpec or the generator config instead. + +## CI + +- `.github/workflows/main.yml` runs, in order: `format:check`, `doc:check`, `build`, `check-storage-layout`, `deploy`, `coverage`, then Slither on `contracts/tools/testing/slither/`. +- Any NatSpec change must be followed by `npm run doc`, or `doc:check` fails. +- `doc:check` diffs the whole `docs/` directory, so a regenerated UML SVG left uncommitted also fails it. +- `npm run doc` starts with `hardhat clean`, so it wipes and rebuilds `artifacts/` and `typechain/`. diff --git a/.claude/context/conventions.md b/.claude/context/conventions.md new file mode 100644 index 00000000..a404debd --- /dev/null +++ b/.claude/context/conventions.md @@ -0,0 +1,39 @@ +# Conventions + +## Every file + +- Solidity and TypeScript files open with the header pair: + + ``` + // SPDX-FileCopyrightText: IEXEC BLOCKCHAIN TECH + // SPDX-License-Identifier: Apache-2.0 + ``` + +- `npm run format` (Prettier, with `prettier-plugin-solidity` and `prettier-plugin-organize-import`) is the formatter. CI runs `format:check`. +- Solidity imports are named (`import {Foo} from "./Foo.sol";`), not bare. The Solidity plugin does not sort them, so keep the existing grouping by hand. + +## Published surface + +`package.json#files` publishes `abis/`, `contracts/`, `deployments/` and `artifacts/contracts`. Consumers are the iExec SDK and the subgraph, so **any ABI, artifact path or artifact name change is a public API change**. A breaking one needs a `feat!:` or `refactor!:` PR title and a note for those two consumers. + +Event signatures are part of that surface twice over: changing one moves its `topic0` and silently breaks the subgraph. + +## Storage + +Every facet shares one struct behind `contracts/libs/PocoStorageLib.sol`. Never reorder or remove an existing variable, only append. `npm run check-storage-layout` is the gate. + +## Generated, never hand-edit + +`abis/**`, `typechain/`, `docs/solidity/index.md`, `docs/uml/*.svg`. Edit the NatSpec or the generator config, then regenerate. + +## Hand-maintained lists + +Two lists are not generated and must be edited when a facet is added, removed or renamed: + +- `utils/proxy-tools.ts#getAllLocalFacetFunctions` +- the facet groups in `scripts/tools/sol-to-uml.mjs` + +## Git + +- Trunk-based, squash merges only. The PR title becomes the commit message, so it must follow Conventional Commits. +- Historical records are not rewritten: `CHANGELOG.md`, the upgrade reports under `scripts/upgrades/*.md` and the `deployments/` artifacts describe what was actually released and deployed, including names that have since changed. diff --git a/.claude/context/testing.md b/.claude/context/testing.md new file mode 100644 index 00000000..37d8a5a4 --- /dev/null +++ b/.claude/context/testing.md @@ -0,0 +1,19 @@ +# Tests + +## Layout + +- `test/0xx_fullchain*.test.ts` — end-to-end deal/task flows: classic, Boost, BoT, multi-orders, reopen. +- `test/byContract/**` — per-facet suites, one directory per facet family. +- `test/utils/` — shared helpers, described below. + +## Helpers + +- `test/utils/hardhat-fixture-deployer.ts` — runs the real `deploy/0_deploy.ts` inside a `loadFixture` snapshot. Every suite starts from it, so tests exercise production deployment code rather than a test-only setup. +- `test/utils/IexecWrapper.ts` — high-level actions. +- `test/utils/fixture-helpers.ts` — account funding and ownership transfers, used by fork-mode runs. +- `utils/poco-tools.ts` — `getIexecAccounts`, deal/task id derivation, result digest/hash builders, enclave and authorization message signing. +- `utils/createOrders.ts` / `utils/odb-tools.ts` — order builders and EIP-712 signing. + +## Timeouts and fork mode + +Mocha timeout is 300s in `hardhat.config.ts` (40s in `.mocharc.json`, which only applies to direct mocha runs). Fork tests copy `deployments/arbitrumSepolia` in via a `test` task override in `hardhat.config.ts` and clean it up afterwards; drive them with `npm run test:arbitrumSepolia` (`ARBITRUM_SEPOLIA_FORK=true`). diff --git a/.claude/context/upgrades.md b/.claude/context/upgrades.md new file mode 100644 index 00000000..74b09367 --- /dev/null +++ b/.claude/context/upgrades.md @@ -0,0 +1,9 @@ +# Facet upgrades + +Full human-facing procedure: `scripts/upgrades/README.md`. + +## Traps + +- `getAllLocalFacetFunctions` in the same file is hand-maintained: a facet added or deleted without editing it leaves selectors unresolved during the upgrade. +- `npm run check-storage-layout` compares layouts found in `artifacts/build-info`; storage stays append-only across versions. +- After a mainnet upgrade, refresh the facet list on the block explorer ("Is this a proxy?") so the proxy reads correctly. diff --git a/.gitignore b/.gitignore index c0d9e792..2a9b383c 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ deployments/dev-* # Flattened Solidity file used to generate diagrams. flatten.sol + +# Agent worktrees. +.claude/worktrees diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..d441116f --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,13 @@ +# CLAUDE.md + +Solidity implementation of iExec's Proof of Contribution (PoCo) protocol: Hardhat 2 + TypeScript, deployed behind an ERC-2535 Diamond proxy, shipped as the `@iexec/poco` npm package. Live on Arbitrum One (42161) and Arbitrum Sepolia (421614). + +## Read when relevant + +| When you are… | Read | +| ------------------------------------------------------------------------------------------ | --------------------------------- | +| creating or editing any file, committing, or opening a PR | `.claude/context/conventions.md` | +| changing contracts, storage, facets, deployment, chain config, orders or registries | `.claude/context/architecture.md` | +| running a command beyond `package.json#scripts`, or reasoning about CI and generated files | `.claude/context/commands.md` | +| writing or debugging tests, or using the test helpers | `.claude/context/testing.md` | +| scripting or executing a facet upgrade | `.claude/context/upgrades.md` |