Skip to content

Releases: CMTA/DocumentEngine

v0.4.0

Choose a tag to compare

@rya-sge rya-sge released this 19 Aug 10:30
687c5d7

Targets CMTAT v3.3.0-rc3 — see the compatibility matrix for which CMTAT release each version of this engine is built against.

Versioning note. getDocument changes shape relative to v0.3.0, which the convention above classifies as a MAJOR bump. MINOR is used because the project is still in its 0.x line, where a 1.0.0 would wrongly signal a stable, audited release. Treat this release as breaking for any consumer decoding getDocument.

Changed

  • Dependencies

    • Upgrade CMTAT v2.5.0-rc0 → v3.3.0-rc3 (lib/CMTAT → 658672f190d56d3f61663a7d6d51962b8980df70). Development passed through v3.3.0-rc1 and v3.3.0-rc2. rc1 is not compatible with the code as shipped here, because it declares neither the ERC-1643 errors nor the flat getDocument return (see below); rc2 and rc3 are interchangeable for this engine — between them, the whole document surface (draft-IERC1643.sol, IDocumentEngine.sol, DocumentEngineModule.sol, DocumentERC1643Module.sol) changed only its pragma, ^0.8.20 → ^0.8.24. Both are therefore listed as the supported range, verified by building and running the full suite against each (74/74 on both). Nothing below rc2 works: v3.0.0/v3.1.0/v3.2.0 return a Document struct and declare no interface errors, and they predate CMTAT's token-side DocumentEngineModule entirely.
    • Upgrade OpenZeppelin Contracts (and Contracts Upgradeable) v5.0.2 → v5.7.0. v5.7.0 deprecates EnumerableSet.at() in favour of pos() (the old name clashes with a keyword scheduled for Solidity); at() remains as a forwarding alias, and this engine has no call sites either way. The only exposure is inherited — AccessControlEnumerable.getRoleMember switched to pos() internally, with no change to its signature, selector or behaviour. Verified: DocumentEngine's runtime code is byte-identical across v5.6.1 and v5.7.0 (8436 bytes; only the CBOR metadata trailer moves, because the source text of AccessControlEnumerable.sol changed), and DocumentEngineOwnable's bytecode is unchanged including metadata.
    • Add CMTA/RuleEngine v3.0.0-rc5 as a submodule (binding-pattern reference; see Why not reuse RuleEngine's compliance module? — its ERC3643ComplianceExtendedModule is not reused)
    • foundry.lock now records every submodule by tag; all five entries had gone stale since v0.3.0.
  • Toolchain: bump Solidity 0.8.26 → 0.8.34 and evm_version cancun → prague to match CMTAT v3 (CMTAT uses require(cond, CustomError()), which needs solc ≥ 0.8.27)

  • Code-quality review (doc/audits/tools/v0.4.0/claude/CLAUDE_ANALYSIS.md) — 14 findings, none a vulnerability. Six implemented:

    • Gas, _removeDocumentName: the _documentNames[subject] mapping slot was re-hashed on every loop iteration; cached as a storage pointer. Measured −2200 gas on a 20-entry full scan.
    • Gas, _removeDocument: the whole Document (URI included) was copied to memory to be read three times; now read through a storage pointer. A further −645 gas. Combined, removal is −2845 gas (−3.3 %) worst case. The emit must stay ahead of the delete — verified by mutating the order and confirming testRemoveDocumentEmitsForSubjectEvent fails. Side effect: Slither's incorrect-equality (Medium) and timestamp (Low) stopped firing on the unchanged doc.lastModified == 0, taking it from 4 results to 2. Not a fix — both were already false positives and the detector merely loses the taint through a storage pointer.
    • hasRole NatSpec: documented that a role is unrevokable from the default admin — revokeRole succeeds, emits RoleRevoked and drops getRoleMemberCount, yet the admin keeps the access. Not a privilege issue (an admin can re-grant itself anything) but the call misreports. Pinned by the new testRevokingRoleFromDefaultAdminDoesNotRemoveAccess.
    • DocumentEngineInvariant: the error-location comment misattributed NotBoundToken(address) to ITokenBinding; it is declared by TokenBindingModule.
    • Documentation pointers removed from contract comments. Three comments referenced doc/ERCSpecification…; documentation moves but deployed source does not, and this repo had already renamed that file once (ERC-1643-proposition.md → erc-draft_multi_document_management.md), leaving a dangling README link behind. Someone reading verified source on an explorer has the comment and not the file. All three pointers are gone and each comment is now shorter, not longer — the IERC1643MultiDocument header dropped from 10 lines to 9 by replacing an enumeration that gestured at the draft's rationale with the one operative fact: subject need not be a token.
    • All 12 internal functions are now virtual (_setDocument, _removeDocument, _removeDocumentName, _getDocument, _setTokenBinding, _checkTokenBound, and the ERC-2771 context trio in both deployments), resolving an inconsistency where TokenBindingModule exposed its public surface for override while DocumentEngineBase exposed nothing but its two abstract hooks. A deployment can now override the document write/read paths and the binding check, matching what CMTAT's equivalent module allows. Runtime cost is zero: the executable bytecode of both deployments is byte-identical before and after (7457 / 6111 bytes, metadata trailer excluded). Guarded by OverridingDocumentEngine + testInternalHooksAreVirtualAndOverridesAreReached — removing virtual from any of the three overridden hooks fails the build (Error (4334): Trying to override non-virtual function).

    Notable non-changes, recorded so they are not re-raised: unchecked { ++i } buys 0 gas on solc 0.8.34 (measured); string calldata on the admin setDocument is 49 gas worse than memory (measured); and the duplicated ERC-2771 context overrides cannot be extracted into a shared module — C3 linearization forces each deployment to re-state them, proven by compiler error.

  • Style pass across src/ and script/ — behaviour-preserving. Brought the sources in line with the Solidity style guide: functions reordered by visibility group (external → public → internal, view/pure last within each), so the _authorize* hooks and the ERC-2771 context overrides now follow the public API instead of preceding it; every brace-less global import replaced by a named one (which required adding the previously implicit Context and AccessControl imports, since a named import no longer re-exports a dependency's own imports); and NatSpec completed with a @param per argument and a @return per return value. No signature, visibility, body or storage layout changed — verified by an unchanged per-contract function set, a clean forge build, and 72/72 tests passing.

  • Source pragma raised ^0.8.20 → ^0.8.24 across src/, script/ and test/. This is a correction, not a new restriction: ^0.8.20 had become an over-promise, advertising a range the sources could not actually compile in. OpenZeppelin's AccessControlEnumerable.sol and EnumerableSet.sol are ^0.8.24, and CMTAT v3.3.0-rc3 moved draft-IERC1643.sol to ^0.8.24 as well, so every contract in src/ now transitively requires it — forge build --use 0.8.23 fails to resolve a compiler. 0.8.24 is the real src/ floor; the full project including the CMTAT-importing tests needs 0.8.27, because require(cond, CustomError()) is restricted to the via-ir pipeline before then. Deployed bytecode is unaffected — the pinned compiler is still 0.8.34.

  • IERC1643 (CMTAT v3) breaking changes

    • getDocument keeps returning (string uri, bytes32 documentHash, uint256 lastModified) — the flat ERC-1643 ABI — on both overloads, getDocument(bytes32) and getDocument(address subject, bytes32). CMTAT v3.3.0-rc1 briefly replaced this with a Document struct and v3.3.0-rc2 reverted it; this engine follows rc2/rc3, so relative to v0.3.0 the external shape is unchanged.

      The distinction is worth recording because it is invisible to interface detection: return types are not part of a function signature, so both shapes share the same selectors and the same type(IERC1643).interfaceId (0xecfecec8). A consumer built from the specification ABI decodes a struct return as garbage without reverting — uri becomes binary junk, documentHash becomes 0x…60, and lastModified becomes the real hash as a uint256. getDocument is now covered by testGetDocumentReturnsFlatErc1643Abi, which inspects the returndata directly since ERC-165 structurally cannot.

    • The Document struct and the DocumentUpdated/DocumentRemoved events are now provided by IERC1643; the duplicate local declarations were removed from DocumentEngineInvariant. The struct is retained internally for storage only.

    • ERC1643InvalidName() / ERC1643MissingDocument() are likewise declared by IERC1643 as of CMTAT v3.3.0-rc2 and are not re-declared here. The multi-subject draft requires a contract implementing both interfaces to obtain each error exactly once ("MUST NOT declare them twice"), and re-declaring is a compile error. Selectors, and hence revert data, are unchanged. The same principle was applied to every other error: MultiDocumentInvalidSubject() moved to IERC1643MultiDocument and TokenBindingInvalidToken() is declared on ITokenBinding, so an ABI generated from an interface carries its errors. DocumentEngineInvariant now holds only InvalidInputLength and AdminWithAddressZeroNotAllowed, which no interface defines.

    • Im...

Read more

v0.3.0

Choose a tag to compare

@rya-sge rya-sge released this 09 Sep 13:07
befff83
  • Add ERC-2771 support

The release does not include the .git folder, which does not allow installing dependencies.
The easiest solution is to clone the project and perform a git checkout on the version tag

git clone https://github.com/CMTA/DocumentEngine
git checkout v0.3.0
forge install
forge build

v0.2.0

Choose a tag to compare

@rya-sge rya-sge released this 03 Sep 13:40
28f31a4
  • Add the constant VERSION
  • Add batch functionsto manage documents for one target contract
  • Improve documentation

The release does not include the .git folder, which does not allow installing dependencies.
The easiest solution is to clone the project and perform a git checkout on the version tag

git clone https://github.com/CMTA/DocumentEngine
git checkout v0.2.0
forge install
forge build

v0.1.0

Choose a tag to compare

@rya-sge rya-sge released this 29 Aug 12:13
4ab48f3

First release !

git clone https://github.com/CMTA/DocumentEngine
git checkout v0.1.0
forge install
forge build