Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ typechain-types
cache
artifacts

#
FEEDBACK.md
ISSUE.md
./.codex
.codex
9 changes: 9 additions & 0 deletions AGENTS
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
SnapshotEngine is a Solidity/Hardhat codebase for on-chain ERC-20 snapshots.

Main point:
- Schedule, reschedule, and execute snapshot times.
- Record historical account balances and total supply at snapshot boundaries.
- Expose snapshot state for downstream on-chain features like dividends, rewards, and governance.

Note:
- `CMTAT/` is a git submodule and should be treated as external code.
12 changes: 12 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
SnapshotEngine is a Solidity/Hardhat codebase for on-chain ERC-20 snapshots.

Main point:
- Schedule, reschedule, and execute snapshot times.
- Record historical account balances and total supply at snapshot boundaries.
- Expose snapshot state for downstream on-chain features like dividends, rewards, and governance.

Note:
- `CMTAT/` is a git submodule and should be treated as external code.

- Update `CHANGELOG.md` for each new relevant modification.
- After each implemented feature or fix, provide a one-line GitHub commit message for all changes since the last commit.
65 changes: 62 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,88 @@

Please follow <https://changelog.md/> conventions.

## Semantic Version 2.0.0

Given a version number MAJOR.MINOR.PATCH, increment the:

1. MAJOR version when the new version makes:
- Incompatible proxy **storage** change internally or through the upgrade of an external library (OpenZeppelin)
- A significant change in external APIs (public/external functions) or in the internal architecture
2. MINOR version when the new version adds functionality in a backward compatible manner
3. PATCH version when the new version makes backward compatible bug fixes

See [https://semver.org](https://semver.org)

## Type of changes

- `Added` for new features.
- `Changed` for changes in existing functionality.
- `Deprecated` for soon-to-be removed features.
- `Removed` for now removed features.
- `Fixed` for any bug fixes.
- `Security` in case of vulnerabilities.

Reference: [keepachangelog.com/en/1.1.0/](https://keepachangelog.com/en/1.1.0/)

Custom changelog tag: `Dependencies`, `Documentation`, `Testing`

## Checklist

> Before a new release, perform the following tasks

- Code: Update the version name defined in [SnapshotEngine.sol](contracts/SnapshotEngine.sol)
- Code: Update the version name in the `Version` core module, variable VERSION
- Run linter

> npm run-script lint:all:prettier

- Documentation
- Perform a code coverage and update the files in the corresponding directory [./doc/coverage](./doc/coverage)
- Perform an audit with several audit tools (e.g Slither), update the report in the corresponding directory [./doc/audits/](./doc/audits/)
- Perform a code coverage and update the files in the corresponding directory [./doc/general/test/coverage](./doc/general/test/coverage)
- Perform an audit with several audit tools (Aderyn and Slither), update the report in the corresponding directory [./doc/audits/tools](./doc/audits/tools)
- Update surya doc by running the 3 scripts in [./doc/script](./doc/script)

- Update changelog

## 0.4.0

- Dependencies
- Align integration for `CMTAT v3.2.0`.
- Update `CMTATBaseRuleEngine` import path (`1_CMTATBaseRuleEngine.sol` -> `2_CMTATBaseRuleEngine.sol`).
- Update version interface usage from `IERC3643Base` to `IERC3643Version`.
- Update OpenZeppelin dependencies to `@openzeppelin/contracts` and `@openzeppelin/contracts-upgradeable` `5.6.1`.
- Replace full `IERC20` dependency in SnapshotEngine modules with a minimal `IERC20SnapshotCompatible` interface (`balanceOf`, `totalSupply`).

- Documentation
- Clarify and document the `0.3.0` known issue and `0.4.0` resolution for `getNextSnapshots()` arithmetic underflow when no future snapshots remain.
- Document strict snapshot query semantics with exact-time APIs:
- `snapshotExists(time)`
- `snapshotBalanceOfExact(time, tokenHolder)` (reverts if `time` is not scheduled)
- `snapshotTotalSupplyExact(time)` (reverts if `time` is not scheduled)
- Document snapshot materialization observability:
- `SnapshotMaterialized(time, blockNumber)` emitted when `_setCurrentSnapshot()` advances.
- `poke()` can be used by authorized accounts to materialize due snapshots without requiring token transfers.
- Add a second deployment variant using OpenZeppelin `Ownable2Step` (`SnapshotEngineOwnable2Step`) and refactor shared deployment logic into `SnapshotEngineBase` to minimize duplication.
- Add `CMTATStandaloneSnapshot` (standalone/non-proxy deployment) and refactor shared CMTAT+snapshot behavior into `CMTATSnapshotBase` to minimize duplication with `CMTATUpgradeableSnapshot`.
- Update README integration guidance to document the minimal token interface required by SnapshotEngine (`IERC20SnapshotCompatible`).

- Testing
- Add tests for exact snapshot queries (scheduled vs non-scheduled timestamps and parity with legacy queries on scheduled timestamps).
- Add tests for snapshot materialization event emission.
- Add tests for `poke()` access control and idempotent behavior.
- Add test coverage for `SnapshotUnschedule(time)` emission in `unscheduleSnapshotNotOptimized`.
- Add a dedicated `SnapshotEngineOwnable2Step` test suite and share common snapshot behavior tests across AccessControl and Ownable variants.
- Add a dedicated `CMTATStandaloneSnapshot` test suite reusing the same shared snapshot behavior suites.
- Refactor admin-authorization assertions into a shared helper to avoid duplicated expectations across test modules.
- Refactor snapshot suite registration and CMTAT init params into shared test helpers to reduce duplication across test entrypoints.

## 0.3.0 - 2025-08-27

Commit: `b5750a0a6f75e73ab00ace6a2cf3e482b1a64352`

- Add deployment version with snapshot for CMTAT
- Better code separation
- Create new module ` SnapshotUpdateModule`
- Known issue for this release:
- `getNextSnapshots()` may revert (panic `0x11`) in edge cases once the most-recent-past-snapshot optimization branch is enabled/fixed, due to an underflow in future-snapshot array size computation.

## 0.2.0 - 2025-08-25

Expand Down
12 changes: 12 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
SnapshotEngine is a Solidity/Hardhat codebase for on-chain ERC-20 snapshots.

Main point:
- Schedule, reschedule, and execute snapshot times.
- Record historical account balances and total supply at snapshot boundaries.
- Expose snapshot state for downstream on-chain features like dividends, rewards, and governance.

Note:
- `CMTAT/` is a git submodule and should be treated as external code.

- Update `CHANGELOG.md` for each new relevant modification.
- After each implemented feature or fix, provide a one-line GitHub commit message for all changes since the last commit.
2 changes: 1 addition & 1 deletion CMTAT
Submodule CMTAT updated 691 files
41 changes: 41 additions & 0 deletions FEEDBACK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Code Review Feedback

## Findings

### 1. High: `getNextSnapshots()` can revert when current snapshot is already the last scheduled snapshot
- Location: `contracts/library/SnapshotBase.sol:86-90`, `contracts/library/SnapshotBase.sol:431-434`
- What happens:
- `_findScheduledMostRecentPastSnapshot()` can return `(0, currentArraySize)` when `_currentSnapshotIndex + 1 == currentArraySize` and `_currentSnapshotTime != 0`.
- `getNextSnapshots()` then evaluates `indexLowerBound + 1 != $._scheduledSnapshots.length` as `true` (because `currentArraySize + 1 != currentArraySize`).
- It computes `arraySize = length - indexLowerBound - 1`, which underflows and reverts in Solidity 0.8+.
- Impact:
- Read-only calls to `getNextSnapshots()` can unexpectedly revert for valid protocol state (no future snapshots left), breaking integrations and monitoring.
- Recommended fix:
- In `getNextSnapshots()`, use a strict guard before computing `arraySize`:
- `if (indexLowerBound + 1 < $._scheduledSnapshots.length) { ... }`
- Preferred approach: fix this in `getNextSnapshots()` only.
- Do **not** change `_findScheduledMostRecentPastSnapshot()` return semantics unless strictly necessary, because that function is also used by `_setCurrentSnapshot()` and has broader behavioral impact.

### 2. Medium: Missing `SnapshotUnschedule` event in non-optimized unschedule path
- Location: `contracts/library/SnapshotBase.sol:238-251`
- What happens:
- `_unscheduleLastSnapshot()` emits `SnapshotUnschedule(time)`.
- `_unscheduleSnapshotNotOptimized()` removes a snapshot but does not emit `SnapshotUnschedule`.
- Impact:
- Off-chain indexers/audit logs miss unschedule actions taken through this code path, creating inconsistent event-driven state.
- Recommended fix:
- Emit `SnapshotUnschedule(time)` at the end of `_unscheduleSnapshotNotOptimized()`.

## Open Questions / Assumptions
- I assumed both unschedule functions are intended to have equivalent externally observable behavior except algorithmic complexity.
- I assumed `getNextSnapshots()` should return an empty array (not revert) when there are no future snapshots.

## Testing Gaps
- No test currently appears to assert the terminal-index path for `getNextSnapshots()` (current snapshot at the end, no future snapshots).
- No test currently appears to assert `SnapshotUnschedule` emission for `unscheduleSnapshotNotOptimized()`.

## Verification Notes
- `npx hardhat compile` succeeds.
- `npx hardhat test` could not be completed in this environment due a Mocha reporter/runtime issue:
- `ERR_MOCHA_INVALID_REPORTER`
- `TypeError: spawnSync .../node EPERM`
Loading
Loading