From 528d6941cb1194c13c6aff951db4aa32f9664db8 Mon Sep 17 00:00:00 2001 From: Punk 6529 <108035228+punk6529@users.noreply.github.com> Date: Thu, 11 Jun 2026 18:50:13 +0000 Subject: [PATCH 1/4] Recover StreamCore bytecode headroom --- CHANGELOG.md | 10 +++ ...anvil-6529stream-v0.1.0-001-broadcast.json | 6 +- .../anvil-6529stream-v0.1.0-001.json | 6 +- ...anvil-6529stream-v0.1.0-001-broadcast.json | 8 +-- .../examples/anvil-6529stream-v0.1.0-001.json | 8 +-- docs/status.md | 12 +++- ops/AUTONOMOUS_RUN.md | 70 +++++++++++++++++-- ops/ROADMAP.md | 23 +++--- release-artifacts/latest/SHA256SUMS | 16 ++--- release-artifacts/latest/abi-checksums.json | 14 ++-- .../latest/release-artifact-manifest.json | 2 +- .../latest/release-checksums.json | 18 ++--- .../latest/release-manifest.json | 32 ++++----- .../latest/source-verification-inputs.json | 54 +++++++------- smart-contracts/StreamCore.sol | 43 +++++++----- test/StreamCoreCustomErrors.t.sol | 51 ++++++++++++++ 16 files changed, 255 insertions(+), 118 deletions(-) create mode 100644 test/StreamCoreCustomErrors.t.sol diff --git a/CHANGELOG.md b/CHANGELOG.md index ed1de515..a53ec329 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,9 @@ the release policy in `docs/release-policy.md`. for required metadata image inputs. - Added production collection base URI and external library URL validation, keeping those fields optional while rejecting unsafe non-empty URI values. +- Added focused `StreamCore` custom-error regressions covering function-admin + authorization, artist signatures, metadata array lengths, and final-supply + timing. ### Fixed @@ -38,6 +41,9 @@ the release policy in `docs/release-policy.md`. - Rejected initial zero collection supply with a typed supply error instead of arithmetic panic, and rejected dependency registry swaps to non-contract addresses with `InvalidDependencyRegistryContract()`. +- Recovered `StreamCore` runtime bytecode headroom by replacing selected legacy + string reverts with typed custom errors, bringing the production IR-optimized + runtime to 24,143 bytes with 433 bytes of EIP-170 headroom. ### Release Impact @@ -68,6 +74,10 @@ the release policy in `docs/release-policy.md`. - Gate D/G release artifacts now include the ABI and bytecode deltas from explicit initial zero-supply rejection and dependency registry target validation. +- Gate D/G release artifacts now include the ABI and bytecode deltas from + `StreamCore` size-recovery custom errors: + `ArtistSignatureUnauthorized()`, `FunctionAdminUnauthorized()`, + `InvalidTokenMetadataInput()`, and `FinalSupplyTimeNotPassed()`. - Detached checksum signatures, signed release tags, production address books, and verified live deployment addresses remain future release-ceremony work. diff --git a/deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json b/deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json index 15f3f0ef..8986b4b0 100644 --- a/deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json +++ b/deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json @@ -3,7 +3,7 @@ "generated_by": "scripts/generate_address_books.py:1", "source": { "deployment_manifest": "deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json", - "deployment_manifest_sha256": "sha256:565975bbbe565eeeb0d53bfbe491b8080f77685997e26885c36e82a90ea7c2d5", + "deployment_manifest_sha256": "sha256:208a2688119ac9678e7b74c566a47d9a061189120738eb9bdb26b0ca44680ce6", "release_artifacts": "release-artifacts/latest", "abi_checksums": "release-artifacts/latest/abi-checksums.json", "event_topic_catalog": "release-artifacts/latest/event-topic-catalog.json" @@ -65,8 +65,8 @@ "address": "0x1000000000000000000000000000000000000003", "source": "smart-contracts/StreamCore.sol", "artifact_path": "out/StreamCore.sol/StreamCore.json", - "abi_hash": "sha256:2e01e1c03a39528d9a90d2d0c2544431538c33103fbb6038c2ec6987866a883d", - "runtime_bytecode_hash": "sha256:15a9f2929ad9e43fbf5a4fd7293212b91a4a1fb377353b06abc153248310aae3", + "abi_hash": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", + "runtime_bytecode_hash": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", "verification_status": "not_applicable" }, "StreamCuratorsPool": { diff --git a/deployments/address-books/anvil-6529stream-v0.1.0-001.json b/deployments/address-books/anvil-6529stream-v0.1.0-001.json index 6f886c49..d6aa3c09 100644 --- a/deployments/address-books/anvil-6529stream-v0.1.0-001.json +++ b/deployments/address-books/anvil-6529stream-v0.1.0-001.json @@ -3,7 +3,7 @@ "generated_by": "scripts/generate_address_books.py:1", "source": { "deployment_manifest": "deployments/examples/anvil-6529stream-v0.1.0-001.json", - "deployment_manifest_sha256": "sha256:58be318490fe0daedc978d2ae1e76bdf91ecefc87b30db4943d4f481310b0eac", + "deployment_manifest_sha256": "sha256:3dfe1802893f9eb5f45fdee014761365d0cc6baf33e26d938ed6547680b26645", "release_artifacts": "release-artifacts/latest", "abi_checksums": "release-artifacts/latest/abi-checksums.json", "event_topic_catalog": "release-artifacts/latest/event-topic-catalog.json" @@ -65,8 +65,8 @@ "address": "0x0000000000000000000000000000000000000003", "source": "smart-contracts/StreamCore.sol", "artifact_path": "out/StreamCore.sol/StreamCore.json", - "abi_hash": "sha256:2e01e1c03a39528d9a90d2d0c2544431538c33103fbb6038c2ec6987866a883d", - "runtime_bytecode_hash": "sha256:15a9f2929ad9e43fbf5a4fd7293212b91a4a1fb377353b06abc153248310aae3", + "abi_hash": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", + "runtime_bytecode_hash": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", "verification_status": "not_applicable" }, "StreamCuratorsPool": { diff --git a/deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json b/deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json index 9760776a..f220b279 100644 --- a/deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json +++ b/deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json @@ -49,8 +49,8 @@ "0x0000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000002" ], - "abi_hash": "sha256:2e01e1c03a39528d9a90d2d0c2544431538c33103fbb6038c2ec6987866a883d", - "bytecode_hash": "sha256:15a9f2929ad9e43fbf5a4fd7293212b91a4a1fb377353b06abc153248310aae3", + "abi_hash": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", + "bytecode_hash": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", "verification_status": "not_applicable" }, "StreamCuratorsPool": { @@ -166,11 +166,11 @@ ] }, "release_artifacts": { - "manifest_sha256": "sha256:565975bbbe565eeeb0d53bfbe491b8080f77685997e26885c36e82a90ea7c2d5", + "manifest_sha256": "sha256:208a2688119ac9678e7b74c566a47d9a061189120738eb9bdb26b0ca44680ce6", "abi_hashes": { "StreamAdmins": "sha256:0dec302776ef6fe8038a96a716c7300d697c52c9b8d79559ab86c2b5c6599dd5", "DependencyRegistry": "sha256:8600876198d591fdae934b20c5d370490939504890944dbd8249d85ef17a6795", - "StreamCore": "sha256:2e01e1c03a39528d9a90d2d0c2544431538c33103fbb6038c2ec6987866a883d", + "StreamCore": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", "StreamCuratorsPool": "sha256:f5d65fb2b17cf0caae7c8c75c6736c5828c869502f55634279556ba8483e6daf", "StreamMinter": "sha256:5464ee3c1b5c40867aba4565d11fe6b708ea2b2e93aba4f7e3a52ebbe4296c3e", "StreamDrops": "sha256:2314f89858673138e8b9c2e421dd7a727c7e7746d5eb069e58a61699f2f4de6a", diff --git a/deployments/examples/anvil-6529stream-v0.1.0-001.json b/deployments/examples/anvil-6529stream-v0.1.0-001.json index 4799e709..2894a9dd 100644 --- a/deployments/examples/anvil-6529stream-v0.1.0-001.json +++ b/deployments/examples/anvil-6529stream-v0.1.0-001.json @@ -49,8 +49,8 @@ "0x0000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000002" ], - "abi_hash": "sha256:2e01e1c03a39528d9a90d2d0c2544431538c33103fbb6038c2ec6987866a883d", - "bytecode_hash": "sha256:15a9f2929ad9e43fbf5a4fd7293212b91a4a1fb377353b06abc153248310aae3", + "abi_hash": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", + "bytecode_hash": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", "verification_status": "not_applicable" }, "StreamCuratorsPool": { @@ -166,11 +166,11 @@ ] }, "release_artifacts": { - "manifest_sha256": "sha256:58be318490fe0daedc978d2ae1e76bdf91ecefc87b30db4943d4f481310b0eac", + "manifest_sha256": "sha256:3dfe1802893f9eb5f45fdee014761365d0cc6baf33e26d938ed6547680b26645", "abi_hashes": { "StreamAdmins": "sha256:0dec302776ef6fe8038a96a716c7300d697c52c9b8d79559ab86c2b5c6599dd5", "DependencyRegistry": "sha256:8600876198d591fdae934b20c5d370490939504890944dbd8249d85ef17a6795", - "StreamCore": "sha256:2e01e1c03a39528d9a90d2d0c2544431538c33103fbb6038c2ec6987866a883d", + "StreamCore": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", "StreamCuratorsPool": "sha256:f5d65fb2b17cf0caae7c8c75c6736c5828c869502f55634279556ba8483e6daf", "StreamMinter": "sha256:5464ee3c1b5c40867aba4565d11fe6b708ea2b2e93aba4f7e3a52ebbe4296c3e", "StreamDrops": "sha256:2314f89858673138e8b9c2e421dd7a727c7e7746d5eb069e58a61699f2f4de6a", diff --git a/docs/status.md b/docs/status.md index 8a2319b5..2c3efd74 100644 --- a/docs/status.md +++ b/docs/status.md @@ -7,9 +7,11 @@ The current Gate A smoke baseline proves: - Foundry is configured to compile `smart-contracts`. - `forge build` runs against Solidity `0.8.19`. - `forge build --sizes --via-ir --skip test --skip script --force` runs as the production - size gate. Current `StreamCore` production runtime size is 24,545 bytes, - leaving 31 bytes of EIP-170 headroom under the IR-optimized deployment - profile. + size gate. Current `StreamCore` production runtime size is 24,143 bytes, + leaving 433 bytes of EIP-170 headroom under the IR-optimized deployment + profile. This satisfies the current 384-byte minimum release floor; future + non-trivial `StreamCore` feature work should preserve at least 512 bytes of + warning-threshold headroom or document an explicit size-budget exception. - `forge test -vvv` executes real tests for admin guards, target-scoped function-admin permission regressions, domain-scoped pause controls, signer-manager lifecycle controls with approved targets, EIP-712 and ERC-1271 @@ -77,6 +79,10 @@ The current Gate A smoke baseline proves: `ipfs://`, and `ar://` content URIs plus rejected empty required token image URIs, JavaScript, hostless HTTPS, whitespace-bearing token image/base URI inputs, and non-HTTPS external library URLs. + `StreamCoreCustomErrors.t.sol` proves the typed failure selectors used to + recover `StreamCore` bytecode headroom for function-admin authorization, + artist-signature authorization, metadata-array length validation, and + final-supply timing. `scripts/test_metadata_fixtures.py` and `scripts/check_metadata_fixtures.py` validate the committed metadata golden fixtures outside Foundry by strictly decoding JSON and HTML data URIs, diff --git a/ops/AUTONOMOUS_RUN.md b/ops/AUTONOMOUS_RUN.md index 2f299bbc..ac47a339 100644 --- a/ops/AUTONOMOUS_RUN.md +++ b/ops/AUTONOMOUS_RUN.md @@ -32,11 +32,11 @@ tests, security hardening, deployment discipline, and release/audit readiness. | Field | Value | | --- | --- | | Remote | `https://github.com/6529-Collections/6529Stream.git` | -| Active PR branch | `codex/metadata-collection-uri-policy` | -| Last merged PR | `https://github.com/6529-Collections/6529Stream/pull/113` | +| Active PR branch | `codex/recover-streamcore-headroom` | +| Last merged PR | `https://github.com/6529-Collections/6529Stream/pull/114` | | Roadmap file | `ops/ROADMAP.md` | | State file | `ops/AUTONOMOUS_RUN.md` | -| Last updated | `2026-06-11 18:22 UTC` | +| Last updated | `2026-06-11 18:48 UTC` | ## Packaging Notes @@ -113,14 +113,67 @@ The queue will evolve as PRs merge and bot feedback arrives. | 57 | Add metadata size limits | Gate D/Gate G support | Continue P1-META-006 by enforcing numeric byte caps for metadata storage inputs, generated `tokenURI` output, and dependency registry metadata, with focused tests, docs, release artifact refresh, and roadmap traceability | Merged in PR #111 | | 58 | Add metadata render-sandbox fixture checks | Gate D | Continue P1-META-006 by validating committed metadata golden fixtures for JSON/data-URI/HTML script-boundary shape and URI scheme policy in local/CI gates, without changing production bytecode | Merged in PR #112 | | 59 | Add metadata token image URI policy | Gate D/Gate G support | Continue P1-META-006 by defining renderer content/script URI policy helpers and rejecting unsafe token image URI writes in production while preserving collection base URI, external library URL, structured-attributes, invalid-UTF-8, and browser-sandbox work as follow-up slices | Merged in PR #113 | -| 60 | Add collection URI production enforcement | Gate D/Gate G support | Continue P1-META-006 by enforcing optional collection base URI and external library URL policy in production, preserving empty optional fields, using custom-error cleanup to keep `StreamCore` under EIP-170, and updating docs/artifacts/state traceability | Active | +| 60 | Add collection URI production enforcement | Gate D/Gate G support | Continue P1-META-006 by enforcing optional collection base URI and external library URL policy in production, preserving empty optional fields, using custom-error cleanup to keep `StreamCore` under EIP-170, and updating docs/artifacts/state traceability | Merged in PR #114 | +| 61 | Recover `StreamCore` bytecode headroom | Gate D/Gate G support | Implement P1-SIZE-001 by replacing selected legacy `StreamCore` string reverts with typed custom errors, adding focused selector regressions, documenting the minimum size floor and warning threshold, and refreshing release artifacts | Active | ## Current PR Worklog -### PR candidate: Collection URI production enforcement (Queue Item 60) +### PR candidate: Recover `StreamCore` bytecode headroom (Queue Item 61) -Status: CodeRabbit outside-diff follow-up implemented and validated locally; -ready to commit, push, and request CodeRabbit review. +Status: local implementation validated; ready to commit, push, open PR, and +request CodeRabbit review. +Branch: `codex/recover-streamcore-headroom`. +Pull request: TBD. + +Goal: + +- Recover sustainable `StreamCore` runtime bytecode margin before further + non-trivial Core feature work. +- Preserve public success behavior and ABI compatibility while documenting the + intentional revert-data change from selected string reverts to typed custom + errors. +- Set the current Core size policy in repo docs: 384 bytes is the minimum + release floor under the production IR size gate, and 512 bytes is the warning + threshold for future non-trivial Core work. +- Regenerate release artifacts because the `StreamCore` ABI and bytecode change. + +Candidate files: + +- `smart-contracts/StreamCore.sol` +- `test/StreamCoreCustomErrors.t.sol` +- `docs/status.md` +- `ops/ROADMAP.md` +- `ops/AUTONOMOUS_RUN.md` +- `CHANGELOG.md` +- `release-artifacts/latest/` + +Validation: + +- `forge test --match-contract StreamCoreCustomErrorsTest -vvv` passed with + 4 tests covering `FunctionAdminUnauthorized()`, + `ArtistSignatureUnauthorized()`, `InvalidTokenMetadataInput()`, and + `FinalSupplyTimeNotPassed()`. +- `forge build --sizes --via-ir --skip test --skip script --force` passed; + final measured `StreamCore` runtime size is 24,143 bytes with 433 bytes of + EIP-170 headroom. +- `make release-checksums` passed and regenerated release/deployment artifacts. +- `make check` passed. +- `powershell -ExecutionPolicy Bypass -File scripts\check.ps1` passed. +- `forge fmt --check smart-contracts\StreamCore.sol + test\StreamCoreCustomErrors.t.sol` passed. +- `git diff --check` passed, with only the known Windows line-ending warning + for `release-artifacts/latest/SHA256SUMS`. + +Notes: + +- A separate `burn` authorization custom-error experiment increased runtime + size by 20 bytes versus the first pass, so it was intentionally dropped. +- The recovery is intentionally narrow: no contract state layout, external + function signatures, event signatures, or successful-path behavior changed. + +### PR #114: Collection URI production enforcement (Queue Item 60) + +Status: Merged in PR #114. Branch: `codex/metadata-collection-uri-policy`. Pull request: `https://github.com/6529-Collections/6529Stream/pull/114`. @@ -5430,6 +5483,9 @@ Outcome: | Time UTC | Decision | Rationale | | --- | --- | --- | +| 2026-06-11 18:48 | Validate Queue Item 61 locally | Focused custom-error regressions, production size gate, regenerated release artifacts, full `make check`, Windows wrapper, targeted formatting, and whitespace checks all pass; `StreamCore` is 24,143 runtime bytes with 433 bytes of EIP-170 headroom | +| 2026-06-11 18:39 | Set interim `StreamCore` size policy | The local P1-SIZE-001 pass measures `StreamCore` at 24,143 runtime bytes with 433 bytes of EIP-170 headroom, so the repo now documents a 384-byte minimum release floor and a 512-byte warning threshold for future non-trivial Core work | +| 2026-06-11 18:37 | Drop burn custom-error experiment | Replacing the `burn` owner/approval string revert with a custom error increased `StreamCore` runtime by 20 bytes versus the narrower pass, so the change was abandoned before documentation and tests | | 2026-06-11 18:22 | Validate PR #114 outside-diff follow-up locally | Focused regressions, production size gate, regenerated release artifacts, full `make check`, Windows wrapper, targeted formatting, and whitespace checks all pass; `StreamCore` remains deployable at 24,545 bytes with 31 bytes of EIP-170 headroom | | 2026-06-11 18:15 | Accept CodeRabbit PR #114 outside-diff findings | The zero-supply path still reverted via arithmetic panic on first initialization, and dependency registry swaps still accepted EOAs or zero addresses; both are fixed locally with typed errors/regressions while keeping `StreamCore` deployable at 24,545 bytes and 31 bytes of EIP-170 headroom | | 2026-06-11 18:00 | Track PR #114 bytecode headroom risk | CodeRabbit correctly highlighted that `StreamCore` has only 61 bytes of EIP-170 margin after the review fix, so issue #115 and the roadmap now track recovering sustainable Core headroom before further non-trivial Core feature work | diff --git a/ops/ROADMAP.md b/ops/ROADMAP.md index e271c085..eb3a568c 100644 --- a/ops/ROADMAP.md +++ b/ops/ROADMAP.md @@ -46,9 +46,11 @@ order. verification input bundle, generated release manifest, and release checksum bundle, while live fork/testnet rehearsals, production broadcast retention, and live artifact verification remain open. Near-term `StreamCore` bytecode - headroom is now a tracked release risk: PR #114 leaves 31 bytes of EIP-170 - margin, so future non-trivial Core work should recover headroom or explicitly - spend an approved size budget first. + headroom remains a tracked release risk: the P1-SIZE-001 recovery pass brings + the IR-optimized runtime to 24,143 bytes with 433 bytes of EIP-170 headroom, + satisfying the current 384-byte minimum release floor. Future non-trivial + Core work should preserve at least 512 bytes of warning-threshold headroom or + explicitly spend an approved size budget first. - Public docs must describe actual on-chain behavior, not intended product behavior. @@ -70,7 +72,7 @@ order. | --- | --- | --- | --- | | Build | Passes with warnings when `forge` is invoked through the installed binary path | `forge build` | Build passes in CI and locally with warnings burned down or documented | | Unit/integration tests | Tests cover admin guards, target-scoped function-admin permission regressions, domain-scoped pause controls, EIP-712/ERC-1271 drop authorization, auction custody and payment credits, fixed-price pull-payment credits, curator reward credits, current emergency-withdrawal boundaries, randomizer lifecycle/callback validation, randomness/pending metadata behavior, ERC-4906 metadata update signaling, raw-output hash storage, dependency-script encoding hashes, explicit local-initialization regressions, vendored utility-library regressions, and retained airdrop mint-accounting behavior; broader P0/P1 tests are missing | `forge test -vvv` | P0 regression and integration suite exists | -| Production size | Production deployable contracts pass the IR-optimized size gate; after PR #114 review follow-ups, `StreamCore` is 24,545 runtime bytes with 31 bytes of EIP-170 headroom; [`P1-SIZE-001`](https://github.com/6529-Collections/6529Stream/issues/115) tracks recovering sustainable Core bytecode margin before further feature work | `forge build --sizes --via-ir --skip test --skip script --force` | Production size gate passes in CI and deployment scripts use the same profile, with an agreed minimum `StreamCore` margin | +| Production size | Production deployable contracts pass the IR-optimized size gate; the P1-SIZE-001 recovery pass replaces selected legacy `StreamCore` string reverts with typed custom errors and measures `StreamCore` at 24,143 runtime bytes with 433 bytes of EIP-170 headroom; current minimum release floor is 384 bytes, and future non-trivial Core work should stay above the 512-byte warning threshold or document an approved size-budget exception | `forge build --sizes --via-ir --skip test --skip script --force` | Production size gate passes in CI and deployment scripts use the same profile, with the agreed minimum `StreamCore` margin enforced before release | | Formatting | Fails broadly | `forge fmt --check smart-contracts` | Passing, or vendored exclusions documented | | Static analysis | Runs with a tracked high/medium baseline: 717 total findings, including 4 High, 19 Medium, and 93 Low; current high/medium rows are fixed, accepted, or documented false positives | `slither . --config-file slither.config.json --foundry-compile-all`, `ops/SLITHER_BASELINE.md`, and `docs/vendored-libraries.md` | High/medium findings fixed, accepted, or documented | | Deployment | Partial local baseline: deploy-and-wire rehearsal script, manifest schema, address-book schema, generated Anvil manifest config/example, sanitized Foundry broadcast fixture ingestion, generated Anvil and broadcast-derived address books, manifest parsing test, and generated ABI/bytecode checksum inputs exist; live fork/testnet rehearsal and production broadcast retention remain missing | `forge script script/RehearseDeployment.s.sol:RehearseDeployment --sig "run()" --via-ir`, `test/StreamDeploymentManifest.t.sol`, `scripts/generate_broadcast_manifest_input.py --check`, `scripts/generate_deployment_manifest.py --check`, `scripts/generate_deployment_manifest.py --config deployments/config/anvil-6529stream-v0.1.0-001-broadcast.json --check`, `scripts/generate_address_books.py --check`, `deployments/broadcasts/`, `deployments/schema/deployment-manifest.schema.json`, `deployments/schema/address-book.schema.json`, `deployments/address-books/`, and `release-artifacts/latest/abi-checksums.json` | Anvil deployment and fork rehearsal pass | @@ -432,7 +434,7 @@ This is the recommended first batch of issues. 31. [`P1-RELEASE-006`](https://github.com/6529-Collections/6529Stream/issues/105) / P1/OPS+TEST+DOCS: Generate a machine-readable release manifest tying release artifacts, deployment artifacts, governance docs, and release-ceremony status together. 32. [`P1-RELEASE-007`](https://github.com/6529-Collections/6529Stream/issues/107) / P1/OPS+TEST+DOCS: Generate source verification inputs from production Foundry artifacts, source files, compiler settings, and contract config. 33. [`P1-DEPLOY-004`](https://github.com/6529-Collections/6529Stream/issues/109) / P1/OPS+TEST+DOCS: Ingest sanitized Foundry broadcast output into deterministic deployment-manifest evidence. -34. [`P1-SIZE-001`](https://github.com/6529-Collections/6529Stream/issues/115) / P1/CODE+TEST+OPS: Recover sustainable `StreamCore` bytecode headroom or define an explicit size budget before adding further non-trivial Core feature work. +34. [`P1-SIZE-001`](https://github.com/6529-Collections/6529Stream/issues/115) / P1/CODE+TEST+OPS: Recover sustainable `StreamCore` bytecode headroom or define an explicit size budget before adding further non-trivial Core feature work. Active recovery pass measures `StreamCore` at 24,143 runtime bytes with 433 bytes of EIP-170 headroom, above the 384-byte minimum release floor. ## 5. Best-Practice Checklist @@ -1817,9 +1819,13 @@ No P0 contract PR may merge without: - Keep the production size gate in `make check`, Windows/Linux check scripts, and CI: `forge build --sizes --via-ir --skip test --skip script --force`. - Track `StreamCore` size as a release risk while headroom is below the agreed - minimum. [`P1-SIZE-001`](https://github.com/6529-Collections/6529Stream/issues/115) - blocks further non-trivial Core feature work unless the PR recovers headroom - or documents an explicit size-budget exception. + warning threshold. The current minimum release floor is 384 bytes of EIP-170 + runtime headroom under the IR-optimized production profile; the warning + threshold for future non-trivial Core feature work is 512 bytes. PRs that + leave `StreamCore` below 512 bytes of headroom must either recover headroom + elsewhere or document an explicit size-budget exception tied to acceptance + criteria. [`P1-SIZE-001`](https://github.com/6529-Collections/6529Stream/issues/115) + records the first recovery pass. - Treat generic all-artifact `forge build --sizes` as a diagnostic only while test-only invariant handlers exceed initcode limits. - Add exact tool pinning for: @@ -2241,6 +2247,7 @@ Status values: `Missing`, `Planned`, `In Progress`, `Passing`, `Blocked`. | Pending randomness metadata | Off-chain and on-chain `tokenURI` pending/final behavior is deterministic and never treats zero hash as finalized randomness | `test/StreamMetadataGolden.t.sol`, later `test/StreamMetadata.t.sol` | Passing for schema-v1 coverage: off-chain pending/final URIs match fixtures, on-chain pending output returns base64 JSON with `metadata_state: "pending"` and no final animation HTML, and on-chain final output returns base64 JSON with `metadata_state: "final"` and the animation URL. Stale-state display remains future metadata/randomness work. | [`P1-META-ADR`](https://github.com/6529-Collections/6529Stream/issues/45), [`P1-META-001`](https://github.com/6529-Collections/6529Stream/issues/46), [`P0-RAND-004`](https://github.com/6529-Collections/6529Stream/issues/40) | Gate C/Gate D | TBD | | Metadata schema golden files | Off-chain URI rules, on-chain pending JSON, on-chain final JSON, and generated HTML remain deterministic under the accepted schema | `test/StreamMetadataGolden.t.sol` | Passing for current schema-v1 slice: `offchain-pending-token-uri.txt`, `offchain-final-token-uri.txt`, `onchain-pending-schema-v1-token-uri.txt`, and `onchain-final-schema-v1-token-uri.txt` lock output, and `metadataSchemaVersion()` plus `tokenMetadataState(tokenId)` expose the active schema and state. Escaping and stale-state display remain future P1-META work. | [`P1-META-001`](https://github.com/6529-Collections/6529Stream/issues/46) | Gate D | TBD | | Metadata escaping and render safety | JSON, HTML, JavaScript, raw attributes, URI, and size-limit inputs are escaped, validated, or rejected | `test/StreamMetadataEscaping.t.sol`, `test/StreamMetadataSizeLimits.t.sol`, `test/StreamMetadataUriPolicy.t.sol`, `scripts/test_metadata_fixtures.py`, `scripts/check_metadata_fixtures.py` | Partial: on-chain JSON string fields are escaped for schema-v1 output; raw attribute fragments reject literal control characters, unterminated strings, unbalanced delimiters, and unquoted array/object breakout attempts; decoded metadata is parser-checked for hostile collection/image strings; final animation HTML is decoded to assert library-attribute escaping, escaped `tokenData` and dependency-script JavaScript string embedding, and closing-script neutralization; numeric byte caps are enforced for collection display fields, collection scripts, token data, token images, token attributes, generated `tokenURI` output, dependency scripts, and dependency provenance; committed metadata golden fixtures are checked outside Foundry for strict JSON/HTML data-URI decoding, metadata JSON shape, current URI scheme policy, and generated final animation wrapper/script boundaries; production writes reject unsafe token image, collection base URI, and external library URL values. Remaining work: semantic attribute schema validation or structured attributes, invalid UTF-8 policy, and full browser execution sandbox tests. | [`P1-META-006`](https://github.com/6529-Collections/6529Stream/issues/51) | Gate D | TBD | +| `StreamCore` bytecode headroom | Optimized failure paths keep the same guarded behavior, expose typed selectors, and production bytecode stays above the agreed minimum floor | `test/StreamCoreCustomErrors.t.sol`, production size gate | Passing locally: selected admin, artist-signature, metadata-array length, and final-supply timing string reverts now use custom errors with direct selector regressions; `forge build --sizes --via-ir --skip test --skip script --force` measures `StreamCore` at 24,143 runtime bytes with 433 bytes of EIP-170 headroom, above the 384-byte minimum release floor and below the 512-byte warning threshold for future non-trivial Core work | [`P1-SIZE-001`](https://github.com/6529-Collections/6529Stream/issues/115) | Gate D/Gate G | TBD | | Collection freeze boundary | Frozen collections cannot mutate collection fields, base URI, metadata mode, scripts, dependency references, token data, image, attributes, final supply, or live-token metadata state | `test/StreamMetadataFreeze.t.sol` | Passing for current `StreamCore` boundary: freeze requires ended minting, elapsed final-supply delay, and final live-token metadata; stores and exposes `collectionFreezeManifestHash`; emits `CollectionFrozen`; finalizes supply to minted-ever count; tightens the reserved max token ID; blocks dependency-registry swaps while any collection is frozen; and rejects current metadata-significant writes after freeze. Dependency version pins are included in the freeze manifest; escaping and richer invariant/fork coverage remain future P1-META work. | [`P1-META-002`](https://github.com/6529-Collections/6529Stream/issues/47) | Gate D | TBD | | Dependency registry immutability | Dependency versions are immutable, pinned by key/version/content hash/registry address, and cannot change frozen collection output | `test/StreamDependencyRegistry.t.sol` | Passing: registry writes create new immutable versions, chunk-index updates derive a new version without mutating the previous one, version records expose typed content hash/provenance/creator/creation/deprecation views, collection metadata pins key/version/content hash/registry address, explicit repinning moves an unfrozen collection to the latest dependency in the current registry, output and freeze manifests stay stable after later registry versions or registry swaps until explicit repin, and segment-boundary hashes remain distinct in `test/StreamMetadataEncoding.t.sol`. Dependency artifact packaging and migration runbooks remain future operational work. | [`P1-META-003`](https://github.com/6529-Collections/6529Stream/issues/48) | Gate D | TBD | | ERC-4906 metadata signaling | `supportsInterface(0x49064906)` succeeds and `MetadataUpdate` / `BatchMetadataUpdate` emit from metadata write paths that can change token JSON | `test/StreamMetadataEvents.t.sol` | Passing for current `StreamCore` behavior: ERC-4906 interface support succeeds, randomness fulfillment and token metadata input writes emit `MetadataUpdate`, collection-level metadata mode/base URI/display/script/dependency-reference writes emit `BatchMetadataUpdate` over the minted-ever range, empty collections do not emit empty batch events, and mint-only plus burn paths do not emit ERC-4906. Dependency registry version creation does not emit ERC-4906 for pinned collections because their output does not change; explicit repinning goes through `updateCollectionInfo` and emits the existing collection-range update. | [`P1-META-004`](https://github.com/6529-Collections/6529Stream/issues/49), [`P1-META-003`](https://github.com/6529-Collections/6529Stream/issues/48) | Gate D | TBD | diff --git a/release-artifacts/latest/SHA256SUMS b/release-artifacts/latest/SHA256SUMS index 3f1b911a..73fa743b 100644 --- a/release-artifacts/latest/SHA256SUMS +++ b/release-artifacts/latest/SHA256SUMS @@ -1,17 +1,17 @@ -49d39d2fe776e95344e9b0e7d548342bdbbdde74377f647c06a1c2f02114505f deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json -4586bbd9805bedd0512c639ee90e37364aaa4c043fe049df4501f616a4bdea06 deployments/address-books/anvil-6529stream-v0.1.0-001.json +ab441b5d3b80c071b29f261d2dcc0dd3534dc27146c5377c632d920eda136ce6 deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json +6e7b7ea8717f661ca83dcf36919da703baf8024457b0ec82d35e8c6dea5ccb97 deployments/address-books/anvil-6529stream-v0.1.0-001.json 5697fb0387369b1127666f8c38b2a952dc2b085f7ab1188c1d18ac32da6141d3 deployments/broadcasts/anvil-6529stream-v0.1.0-001-run-latest.json b4ebc06aaa7c06ccf1a15ef8a79a6fdc866785f5d4996fc34af42bf3deed07f5 deployments/config/anvil-6529stream-v0.1.0-001-broadcast.json 03ff60467a5271ff5c8c638525dc355c3d00d78781cbcaa23c2d380995bb658b deployments/config/anvil-6529stream-v0.1.0-001.json -bb0eb8bbc50f9cc186c7843a59f1f68ba6d477ba001b728061a8de0114846d0f deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json -cb60d51735ba011e62521035a9504644ad0a3d2664fde5da0a53be194f5f3102 deployments/examples/anvil-6529stream-v0.1.0-001.json +acf786414981880ea5bb5dd68893bf094c7f7cfca949a415bdfc1b34b4e6e157 deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json +67bfb20c740c2ee76433369d50bec171fcc783868c5aad484239f3ed672a3704 deployments/examples/anvil-6529stream-v0.1.0-001.json e36a4a98e66c0bdcd6f5cd6c8125e547c53bd4537a7ee2c25a69f041ec2c3d13 deployments/schema/address-book.schema.json 3de078b625d0bf9fd49e352137efe7320d8ef701c04b0d5dc3dbfb5e560b7cfd deployments/schema/deployment-manifest.schema.json 44e97807c70ed606edb985cca85eace493a893a62c345212c18e7834ba6c08be release-artifacts/baselines/v0.1.0/abi-surface.json da895fbb51bc43b91b9c704bdef2186f718f171158487a52332023b858489011 release-artifacts/contracts.json -e7846a307e21aed326105452a183f61137d00206bd189bbb819c6d012b44544c release-artifacts/latest/abi-checksums.json +029cf68482f991196e0c8dccd055d62abdcc518e8df23b8e558b98d244b52bb9 release-artifacts/latest/abi-checksums.json 6dd5190f816fd3ab72adcc6f1ae761aadf900dd24f0bd0f7bebc1697fed423af release-artifacts/latest/event-topic-catalog.json 8a8a41d89757d3d16f0718638d1175290dcd00cfea86204665cd525f608d7c1a release-artifacts/latest/interface-ids.json -034a29ae384329745dc62620377adc9de71d73e0092dc188cdac2dcdac16def2 release-artifacts/latest/release-artifact-manifest.json -ad7c8262430e811a8ffbda27fe549133aa6dbdd41ded3d439e75b32cefc21e48 release-artifacts/latest/release-manifest.json -8d1251e1c738eb6b2c66edd53ea46d16406095212d1b5e745a07012f202df1c9 release-artifacts/latest/source-verification-inputs.json +33294e594946270d4fd58d1b0dcbe6b088a3cce3d3fcbbd93f6bb02bd1489bfe release-artifacts/latest/release-artifact-manifest.json +4f9b885ecfb6b30b9b3d9a3a3951b87f889894f74945bccf33ad32e5ce054c17 release-artifacts/latest/release-manifest.json +b3ed8edf726267acc4a99ca0bd97423c601748faa3ed83c9371c85d54e29e152 release-artifacts/latest/source-verification-inputs.json diff --git a/release-artifacts/latest/abi-checksums.json b/release-artifacts/latest/abi-checksums.json index 1939dca0..a8bb26de 100644 --- a/release-artifacts/latest/abi-checksums.json +++ b/release-artifacts/latest/abi-checksums.json @@ -11,7 +11,7 @@ "NextGenRandomizerVRF": "sha256:d913a668add41a0e37da1913191d4e35b3428fb62c5e55be96f1e9ba239b58c6", "StreamAdmins": "sha256:0dec302776ef6fe8038a96a716c7300d697c52c9b8d79559ab86c2b5c6599dd5", "StreamAuctions": "sha256:8fca4fb9860c9dd5fcbe7287dcd3cc86c69ae5d28488302602e27f0dfc3685d6", - "StreamCore": "sha256:2e01e1c03a39528d9a90d2d0c2544431538c33103fbb6038c2ec6987866a883d", + "StreamCore": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", "StreamCuratorsPool": "sha256:f5d65fb2b17cf0caae7c8c75c6736c5828c869502f55634279556ba8483e6daf", "StreamDrops": "sha256:2314f89858673138e8b9c2e421dd7a727c7e7746d5eb069e58a61699f2f4de6a", "StreamMinter": "sha256:5464ee3c1b5c40867aba4565d11fe6b708ea2b2e93aba4f7e3a52ebbe4296c3e" @@ -79,12 +79,12 @@ }, "StreamCore": { "creation": { - "sha256": "sha256:033188fba5c658b0b6b4ea991d5ecb4f48b803b622f306cf64c79de3cf62dacf", + "sha256": "sha256:b4dff26f761549ee3e635f099803d789fb3ec2a009e12b6b55a85ab4eea5d46c", "linked": false, "hash_mode": "unlinked_artifact_object" }, "runtime": { - "sha256": "sha256:15a9f2929ad9e43fbf5a4fd7293212b91a4a1fb377353b06abc153248310aae3", + "sha256": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", "linked": false, "hash_mode": "unlinked_artifact_object" } @@ -205,14 +205,14 @@ "StreamCore": { "source": "smart-contracts/StreamCore.sol", "artifact_path": "out/StreamCore.sol/StreamCore.json", - "abi_sha256": "sha256:2e01e1c03a39528d9a90d2d0c2544431538c33103fbb6038c2ec6987866a883d", - "bytecode_sha256": "sha256:033188fba5c658b0b6b4ea991d5ecb4f48b803b622f306cf64c79de3cf62dacf", + "abi_sha256": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", + "bytecode_sha256": "sha256:b4dff26f761549ee3e635f099803d789fb3ec2a009e12b6b55a85ab4eea5d46c", "bytecode_linked": false, "bytecode_hash_mode": "unlinked_artifact_object", - "deployed_bytecode_sha256": "sha256:15a9f2929ad9e43fbf5a4fd7293212b91a4a1fb377353b06abc153248310aae3", + "deployed_bytecode_sha256": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", "deployed_bytecode_linked": false, "deployed_bytecode_hash_mode": "unlinked_artifact_object", - "abi_entries": 114, + "abi_entries": 118, "function_count": 74, "event_count": 11, "constructor_count": 1 diff --git a/release-artifacts/latest/release-artifact-manifest.json b/release-artifacts/latest/release-artifact-manifest.json index 7ca2bcc4..2ca0e9b6 100644 --- a/release-artifacts/latest/release-artifact-manifest.json +++ b/release-artifacts/latest/release-artifact-manifest.json @@ -8,7 +8,7 @@ "artifacts": { "abi-checksums.json": { "path": "abi-checksums.json", - "sha256": "sha256:e7846a307e21aed326105452a183f61137d00206bd189bbb819c6d012b44544c" + "sha256": "sha256:029cf68482f991196e0c8dccd055d62abdcc518e8df23b8e558b98d244b52bb9" }, "event-topic-catalog.json": { "path": "event-topic-catalog.json", diff --git a/release-artifacts/latest/release-checksums.json b/release-artifacts/latest/release-checksums.json index 430088dd..556030eb 100644 --- a/release-artifacts/latest/release-checksums.json +++ b/release-artifacts/latest/release-checksums.json @@ -18,7 +18,7 @@ "text_checksum_file": { "path": "release-artifacts/latest/SHA256SUMS", "format": "sha256sum", - "sha256": "sha256:cc84d3cca596facfd701fd8b1f0b7cd6dc58ff7531b6faab92c383ff7b76476d" + "sha256": "sha256:e1db038db1b1d4b9626c90c5fedee53339982662edf88457c450c018645e874f" }, "manifest_file": { "path": "release-artifacts/latest/release-checksums.json", @@ -27,12 +27,12 @@ "files": [ { "path": "deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json", - "sha256": "sha256:49d39d2fe776e95344e9b0e7d548342bdbbdde74377f647c06a1c2f02114505f", + "sha256": "sha256:ab441b5d3b80c071b29f261d2dcc0dd3534dc27146c5377c632d920eda136ce6", "size_bytes": 5082 }, { "path": "deployments/address-books/anvil-6529stream-v0.1.0-001.json", - "sha256": "sha256:4586bbd9805bedd0512c639ee90e37364aaa4c043fe049df4501f616a4bdea06", + "sha256": "sha256:6e7b7ea8717f661ca83dcf36919da703baf8024457b0ec82d35e8c6dea5ccb97", "size_bytes": 5062 }, { @@ -52,12 +52,12 @@ }, { "path": "deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json", - "sha256": "sha256:bb0eb8bbc50f9cc186c7843a59f1f68ba6d477ba001b728061a8de0114846d0f", + "sha256": "sha256:acf786414981880ea5bb5dd68893bf094c7f7cfca949a415bdfc1b34b4e6e157", "size_bytes": 8299 }, { "path": "deployments/examples/anvil-6529stream-v0.1.0-001.json", - "sha256": "sha256:cb60d51735ba011e62521035a9504644ad0a3d2664fde5da0a53be194f5f3102", + "sha256": "sha256:67bfb20c740c2ee76433369d50bec171fcc783868c5aad484239f3ed672a3704", "size_bytes": 8262 }, { @@ -82,7 +82,7 @@ }, { "path": "release-artifacts/latest/abi-checksums.json", - "sha256": "sha256:e7846a307e21aed326105452a183f61137d00206bd189bbb819c6d012b44544c", + "sha256": "sha256:029cf68482f991196e0c8dccd055d62abdcc518e8df23b8e558b98d244b52bb9", "size_bytes": 11136 }, { @@ -97,17 +97,17 @@ }, { "path": "release-artifacts/latest/release-artifact-manifest.json", - "sha256": "sha256:034a29ae384329745dc62620377adc9de71d73e0092dc188cdac2dcdac16def2", + "sha256": "sha256:33294e594946270d4fd58d1b0dcbe6b088a3cce3d3fcbbd93f6bb02bd1489bfe", "size_bytes": 737 }, { "path": "release-artifacts/latest/release-manifest.json", - "sha256": "sha256:ad7c8262430e811a8ffbda27fe549133aa6dbdd41ded3d439e75b32cefc21e48", + "sha256": "sha256:4f9b885ecfb6b30b9b3d9a3a3951b87f889894f74945bccf33ad32e5ce054c17", "size_bytes": 10704 }, { "path": "release-artifacts/latest/source-verification-inputs.json", - "sha256": "sha256:8d1251e1c738eb6b2c66edd53ea46d16406095212d1b5e745a07012f202df1c9", + "sha256": "sha256:b3ed8edf726267acc4a99ca0bd97423c601748faa3ed83c9371c85d54e29e152", "size_bytes": 46335 } ] diff --git a/release-artifacts/latest/release-manifest.json b/release-artifacts/latest/release-manifest.json index 639252db..cf41001f 100644 --- a/release-artifacts/latest/release-manifest.json +++ b/release-artifacts/latest/release-manifest.json @@ -30,7 +30,7 @@ }, "abi_checksums": { "path": "release-artifacts/latest/abi-checksums.json", - "sha256": "sha256:e7846a307e21aed326105452a183f61137d00206bd189bbb819c6d012b44544c", + "sha256": "sha256:029cf68482f991196e0c8dccd055d62abdcc518e8df23b8e558b98d244b52bb9", "size_bytes": 11136, "schema_version": "6529stream.abi-checksums.v1" }, @@ -48,13 +48,13 @@ }, "artifact_manifest": { "path": "release-artifacts/latest/release-artifact-manifest.json", - "sha256": "sha256:034a29ae384329745dc62620377adc9de71d73e0092dc188cdac2dcdac16def2", + "sha256": "sha256:33294e594946270d4fd58d1b0dcbe6b088a3cce3d3fcbbd93f6bb02bd1489bfe", "size_bytes": 737, "schema_version": "6529stream.release-artifact-manifest.v1", "artifacts": { "abi-checksums.json": { "path": "abi-checksums.json", - "sha256": "sha256:e7846a307e21aed326105452a183f61137d00206bd189bbb819c6d012b44544c" + "sha256": "sha256:029cf68482f991196e0c8dccd055d62abdcc518e8df23b8e558b98d244b52bb9" }, "event-topic-catalog.json": { "path": "event-topic-catalog.json", @@ -68,7 +68,7 @@ }, "source_verification_inputs": { "path": "release-artifacts/latest/source-verification-inputs.json", - "sha256": "sha256:8d1251e1c738eb6b2c66edd53ea46d16406095212d1b5e745a07012f202df1c9", + "sha256": "sha256:b3ed8edf726267acc4a99ca0bd97423c601748faa3ed83c9371c85d54e29e152", "size_bytes": 46335, "schema_version": "6529stream.source-verification-inputs.v1" }, @@ -104,7 +104,7 @@ "manifests": [ { "path": "deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json", - "sha256": "sha256:bb0eb8bbc50f9cc186c7843a59f1f68ba6d477ba001b728061a8de0114846d0f", + "sha256": "sha256:acf786414981880ea5bb5dd68893bf094c7f7cfca949a415bdfc1b34b4e6e157", "size_bytes": 8299, "schema_version": "6529stream.deployment-manifest.v1", "protocol_version": "0.1.0", @@ -114,7 +114,7 @@ "name": "anvil", "chain_id": 31337 }, - "manifest_sha256": "sha256:565975bbbe565eeeb0d53bfbe491b8080f77685997e26885c36e82a90ea7c2d5", + "manifest_sha256": "sha256:208a2688119ac9678e7b74c566a47d9a061189120738eb9bdb26b0ca44680ce6", "contracts": [ "DependencyRegistry", "NextGenRandomizerRNG", @@ -129,7 +129,7 @@ }, { "path": "deployments/examples/anvil-6529stream-v0.1.0-001.json", - "sha256": "sha256:cb60d51735ba011e62521035a9504644ad0a3d2664fde5da0a53be194f5f3102", + "sha256": "sha256:67bfb20c740c2ee76433369d50bec171fcc783868c5aad484239f3ed672a3704", "size_bytes": 8262, "schema_version": "6529stream.deployment-manifest.v1", "protocol_version": "0.1.0", @@ -139,7 +139,7 @@ "name": "anvil", "chain_id": 31337 }, - "manifest_sha256": "sha256:58be318490fe0daedc978d2ae1e76bdf91ecefc87b30db4943d4f481310b0eac", + "manifest_sha256": "sha256:3dfe1802893f9eb5f45fdee014761365d0cc6baf33e26d938ed6547680b26645", "contracts": [ "DependencyRegistry", "NextGenRandomizerRNG", @@ -156,7 +156,7 @@ "address_books": [ { "path": "deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json", - "sha256": "sha256:49d39d2fe776e95344e9b0e7d548342bdbbdde74377f647c06a1c2f02114505f", + "sha256": "sha256:ab441b5d3b80c071b29f261d2dcc0dd3534dc27146c5377c632d920eda136ce6", "size_bytes": 5082, "schema_version": "6529stream.address-book.v1", "protocol_version": "0.1.0", @@ -167,7 +167,7 @@ "chain_id": 31337 }, "deployment_manifest": "deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json", - "deployment_manifest_sha256": "sha256:565975bbbe565eeeb0d53bfbe491b8080f77685997e26885c36e82a90ea7c2d5", + "deployment_manifest_sha256": "sha256:208a2688119ac9678e7b74c566a47d9a061189120738eb9bdb26b0ca44680ce6", "contracts": [ "DependencyRegistry", "NextGenRandomizerRNG", @@ -182,7 +182,7 @@ }, { "path": "deployments/address-books/anvil-6529stream-v0.1.0-001.json", - "sha256": "sha256:4586bbd9805bedd0512c639ee90e37364aaa4c043fe049df4501f616a4bdea06", + "sha256": "sha256:6e7b7ea8717f661ca83dcf36919da703baf8024457b0ec82d35e8c6dea5ccb97", "size_bytes": 5062, "schema_version": "6529stream.address-book.v1", "protocol_version": "0.1.0", @@ -193,7 +193,7 @@ "chain_id": 31337 }, "deployment_manifest": "deployments/examples/anvil-6529stream-v0.1.0-001.json", - "deployment_manifest_sha256": "sha256:58be318490fe0daedc978d2ae1e76bdf91ecefc87b30db4943d4f481310b0eac", + "deployment_manifest_sha256": "sha256:3dfe1802893f9eb5f45fdee014761365d0cc6baf33e26d938ed6547680b26645", "contracts": [ "DependencyRegistry", "NextGenRandomizerRNG", @@ -225,8 +225,8 @@ "release_notes_and_policy": { "changelog": { "path": "CHANGELOG.md", - "sha256": "sha256:f52baa3781be43430d4daf37723a7db3d901733e140b0a1574b4dd34731169f1", - "size_bytes": 4339 + "sha256": "sha256:cacec47bb4d61d2f1f3b30ade4fc45c68c6a2c8bedcc85b824ecc6a3f95ff73b", + "size_bytes": 4977 }, "governance_docs": [ { @@ -246,8 +246,8 @@ }, { "path": "docs/status.md", - "sha256": "sha256:f64d4c1850b393cc3366f923a507f77f195697efc24412c0e1ab1aa64ff618bc", - "size_bytes": 10381 + "sha256": "sha256:16e8fa62307ae0cceb034f17a481ae1a3bcfb254b9569cb8d57e47cfb814c474", + "size_bytes": 10848 } ] }, diff --git a/release-artifacts/latest/source-verification-inputs.json b/release-artifacts/latest/source-verification-inputs.json index b480f529..d6953dfe 100644 --- a/release-artifacts/latest/source-verification-inputs.json +++ b/release-artifacts/latest/source-verification-inputs.json @@ -375,8 +375,8 @@ }, "smart-contracts/StreamCore.sol": { "path": "smart-contracts/StreamCore.sol", - "sha256": "sha256:24848da0e3478fa58ee297b6cafec2dc0bd36260018e573187548b1459b9946f", - "solc_keccak256": "0xdba443877cabf989d7ea0c998d0a93d09264570318abf53a3f45753da9431039", + "sha256": "sha256:b057b0ed92a22125cc8e347a8a38a3657336707601a0be33532d688f12a7bf57", + "solc_keccak256": "0x1c587a61dd49d034a0cd786d1a37b4554e511667ac204e5ad19a6c3b40f95feb", "license": "MIT", "used_by": [ "StreamCore" @@ -612,7 +612,7 @@ "source_sha256": "sha256:e126bc7c0b08a3318dbb435ce24831a59b3f113c19df49752c3b71f85d748a4c", "source_solc_keccak256": "0xd5d9f10afe33ff40fa74816b9b5be05856d7a8f8a89a5b5dd22121c467291cb9", "artifact_path": "out/RandomizerVRF.sol/NextGenRandomizerVRF.json", - "artifact_sha256": "sha256:8f68c8cb284643d14602828145677ae13a060ca33d2978d196aaadf28a96defc", + "artifact_sha256": "sha256:40b9452c00d7dc882b6637a0976f675dd9ed667c8d5c81f28f6f4239dd2f753b", "compilation_target": "smart-contracts/RandomizerVRF.sol:NextGenRandomizerVRF", "compiler_version": "0.8.19+commit.7dd6d404", "language": "Solidity", @@ -840,10 +840,10 @@ }, "StreamCore": { "source": "smart-contracts/StreamCore.sol", - "source_sha256": "sha256:24848da0e3478fa58ee297b6cafec2dc0bd36260018e573187548b1459b9946f", - "source_solc_keccak256": "0xdba443877cabf989d7ea0c998d0a93d09264570318abf53a3f45753da9431039", + "source_sha256": "sha256:b057b0ed92a22125cc8e347a8a38a3657336707601a0be33532d688f12a7bf57", + "source_solc_keccak256": "0x1c587a61dd49d034a0cd786d1a37b4554e511667ac204e5ad19a6c3b40f95feb", "artifact_path": "out/StreamCore.sol/StreamCore.json", - "artifact_sha256": "sha256:0ec023dfb58ac033b481c64478490794c9a07ee7e5498efd3ec9c48c76d81764", + "artifact_sha256": "sha256:67cfdb4f37ecdcc48a4f6bbe8a52a714a0c066b62032c0fe92281fd8840b6c10", "compilation_target": "smart-contracts/StreamCore.sol:StreamCore", "compiler_version": "0.8.19+commit.7dd6d404", "language": "Solidity", @@ -857,19 +857,19 @@ "metadata_bytecode_hash": "ipfs", "libraries": {} }, - "abi_sha256": "sha256:2e01e1c03a39528d9a90d2d0c2544431538c33103fbb6038c2ec6987866a883d", + "abi_sha256": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", "bytecode_hashes": { "creation": { - "sha256": "sha256:033188fba5c658b0b6b4ea991d5ecb4f48b803b622f306cf64c79de3cf62dacf", + "sha256": "sha256:b4dff26f761549ee3e635f099803d789fb3ec2a009e12b6b55a85ab4eea5d46c", "linked": false, "hash_mode": "unlinked_artifact_object", - "release_artifact_sha256": "sha256:033188fba5c658b0b6b4ea991d5ecb4f48b803b622f306cf64c79de3cf62dacf" + "release_artifact_sha256": "sha256:b4dff26f761549ee3e635f099803d789fb3ec2a009e12b6b55a85ab4eea5d46c" }, "runtime": { - "sha256": "sha256:15a9f2929ad9e43fbf5a4fd7293212b91a4a1fb377353b06abc153248310aae3", + "sha256": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", "linked": false, "hash_mode": "unlinked_artifact_object", - "release_artifact_sha256": "sha256:15a9f2929ad9e43fbf5a4fd7293212b91a4a1fb377353b06abc153248310aae3" + "release_artifact_sha256": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90" } }, "constructor": { @@ -915,35 +915,35 @@ "library": "StreamMetadataRenderer", "positions": [ { - "start": 8008, + "start": 7939, "length": 20 }, { - "start": 10681, + "start": 10504, "length": 20 }, { - "start": 10845, + "start": 10668, "length": 20 }, { - "start": 12809, + "start": 12583, "length": 20 }, { - "start": 15515, + "start": 15170, "length": 20 }, { - "start": 21329, + "start": 20915, "length": 20 }, { - "start": 21940, + "start": 21526, "length": 20 }, { - "start": 23348, + "start": 22934, "length": 20 } ] @@ -955,35 +955,35 @@ "library": "StreamMetadataRenderer", "positions": [ { - "start": 6784, + "start": 6715, "length": 20 }, { - "start": 9457, + "start": 9280, "length": 20 }, { - "start": 9621, + "start": 9444, "length": 20 }, { - "start": 11585, + "start": 11359, "length": 20 }, { - "start": 14291, + "start": 13946, "length": 20 }, { - "start": 20105, + "start": 19691, "length": 20 }, { - "start": 20716, + "start": 20302, "length": 20 }, { - "start": 22124, + "start": 21710, "length": 20 } ] diff --git a/smart-contracts/StreamCore.sol b/smart-contracts/StreamCore.sol index 02586626..4e43991a 100644 --- a/smart-contracts/StreamCore.sol +++ b/smart-contracts/StreamCore.sol @@ -91,12 +91,16 @@ contract StreamCore is ERC721, ERC2981, Ownable, IERC4906 { uint256 collectionId, uint256 currentTimestamp, uint256 endTime ); error CollectionNotCreated(uint256 collectionId); + error ArtistSignatureUnauthorized(); error BurnedTokenRemintNotAllowed(uint256 tokenId); + error FunctionAdminUnauthorized(); error InvalidAdminContract(); error InvalidDependencyRegistryContract(); error InvalidMinterContract(); error InvalidRandomizerContract(); + error InvalidTokenMetadataInput(); error MetadataMutationPaused(); + error FinalSupplyTimeNotPassed(); error FrozenCollectionDependencyRegistry(); error MetadataFieldTooLarge(bytes32 field, uint256 actual, uint256 maximum); error MetadataFrozen(uint256 collectionId); @@ -266,11 +270,12 @@ contract StreamCore is ERC721, ERC2981, Ownable, IERC4906 { // certain functions can only be called by a global or function admin modifier FunctionAdminRequired(bytes4 _selector) { - require( - adminsContract.retrieveFunctionAdmin(msg.sender, address(this), _selector) == true - || adminsContract.retrieveGlobalAdmin(msg.sender) == true, - "Not allowed" - ); + if ( + !adminsContract.retrieveFunctionAdmin(msg.sender, address(this), _selector) + && !adminsContract.retrieveGlobalAdmin(msg.sender) + ) { + revert FunctionAdminUnauthorized(); + } _; } @@ -519,11 +524,12 @@ contract StreamCore is ERC721, ERC2981, Ownable, IERC4906 { function artistSignature(uint256 _collectionID, string memory _signature) public { _requireMetadataMutationNotPaused(); _requireCollectionNotFrozen(_collectionID); - require( - msg.sender == collectionAdditionalData[_collectionID].collectionArtistAddress - && artistSigned[_collectionID] == false, - "Not artist/Signed" - ); + if ( + msg.sender != collectionAdditionalData[_collectionID].collectionArtistAddress + || artistSigned[_collectionID] + ) { + revert ArtistSignatureUnauthorized(); + } artistsSignatures[_collectionID] = _signature; artistSigned[_collectionID] = true; } @@ -561,9 +567,9 @@ contract StreamCore is ERC721, ERC2981, Ownable, IERC4906 { string[] memory _attributes ) public FunctionAdminRequired(this.updateImagesAndAttributes.selector) { _requireMetadataMutationNotPaused(); - require( - (_tokenId.length == _images.length) && (_images.length == _attributes.length), "inv len" - ); + if (_tokenId.length != _images.length || _images.length != _attributes.length) { + revert InvalidTokenMetadataInput(); + } for (uint256 x; x < _tokenId.length; x++) { uint256 collectionId = tokenIdsToCollectionIds[_tokenId[x]]; _requireCollectionNotFrozen(collectionId); @@ -648,12 +654,13 @@ contract StreamCore is ERC721, ERC2981, Ownable, IERC4906 { FunctionAdminRequired(this.setFinalSupply.selector) { _requireCollectionNotFrozen(_collectionID); - require( + if ( block.timestamp - > IStreamMinter(minterContract).getEndTime(_collectionID) - + collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint, - "Time has not passed" - ); + <= IStreamMinter(minterContract).getEndTime(_collectionID) + + collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint + ) { + revert FinalSupplyTimeNotPassed(); + } _finalizeCollectionSupply(_collectionID); } diff --git a/test/StreamCoreCustomErrors.t.sol b/test/StreamCoreCustomErrors.t.sol new file mode 100644 index 00000000..2dd35041 --- /dev/null +++ b/test/StreamCoreCustomErrors.t.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import "../smart-contracts/StreamCore.sol"; +import "./helpers/CharacterizationTestBase.sol"; +import "./helpers/StreamFixture.sol"; + +contract StreamCoreCustomErrorsTest is CharacterizationTestBase, StreamFixture { + uint256 private constant COLLECTION_ID = 1; + address private constant ARTIST = address(0xA11CE); + address private constant UNAUTHORIZED = address(0xBAD); + + function testFunctionAdminRequiredUsesCustomError() public { + DeployedStream memory deployed = deployStream(address(0xBEEF), address(0xCAFE)); + + vm.expectRevert(abi.encodeWithSelector(StreamCore.FunctionAdminUnauthorized.selector)); + vm.prank(UNAUTHORIZED); + deployed.core.changeMetadataView(COLLECTION_ID, true); + } + + function testArtistSignatureUsesCustomErrorForWrongSignerAndDuplicateSignature() public { + DeployedStream memory deployed = deployStream(address(0xBEEF), address(0xCAFE)); + + vm.expectRevert(abi.encodeWithSelector(StreamCore.ArtistSignatureUnauthorized.selector)); + deployed.core.artistSignature(COLLECTION_ID, "not-artist"); + + vm.prank(ARTIST); + deployed.core.artistSignature(COLLECTION_ID, "artist-signature"); + + vm.expectRevert(abi.encodeWithSelector(StreamCore.ArtistSignatureUnauthorized.selector)); + vm.prank(ARTIST); + deployed.core.artistSignature(COLLECTION_ID, "second-signature"); + } + + function testUpdateImagesAndAttributesUsesCustomErrorForMismatchedArrayLengths() public { + DeployedStream memory deployed = deployStream(address(0xBEEF), address(0xCAFE)); + uint256[] memory tokenIds = new uint256[](1); + string[] memory images = new string[](0); + string[] memory attributes = new string[](1); + + vm.expectRevert(abi.encodeWithSelector(StreamCore.InvalidTokenMetadataInput.selector)); + deployed.core.updateImagesAndAttributes(tokenIds, images, attributes); + } + + function testSetFinalSupplyUsesCustomErrorBeforeFinalSupplyWindowEnds() public { + DeployedStream memory deployed = deployStream(address(0xBEEF), address(0xCAFE)); + + vm.expectRevert(abi.encodeWithSelector(StreamCore.FinalSupplyTimeNotPassed.selector)); + deployed.core.setFinalSupply(COLLECTION_ID); + } +} From 613ddf661ccfceb981dfaafc9b0d708cb74d60fd Mon Sep 17 00:00:00 2001 From: Punk 6529 <108035228+punk6529@users.noreply.github.com> Date: Thu, 11 Jun 2026 18:51:28 +0000 Subject: [PATCH 2/4] Record StreamCore headroom PR --- ops/AUTONOMOUS_RUN.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ops/AUTONOMOUS_RUN.md b/ops/AUTONOMOUS_RUN.md index ac47a339..16cbe6ce 100644 --- a/ops/AUTONOMOUS_RUN.md +++ b/ops/AUTONOMOUS_RUN.md @@ -36,7 +36,7 @@ tests, security hardening, deployment discipline, and release/audit readiness. | Last merged PR | `https://github.com/6529-Collections/6529Stream/pull/114` | | Roadmap file | `ops/ROADMAP.md` | | State file | `ops/AUTONOMOUS_RUN.md` | -| Last updated | `2026-06-11 18:48 UTC` | +| Last updated | `2026-06-11 18:51 UTC` | ## Packaging Notes @@ -120,10 +120,9 @@ The queue will evolve as PRs merge and bot feedback arrives. ### PR candidate: Recover `StreamCore` bytecode headroom (Queue Item 61) -Status: local implementation validated; ready to commit, push, open PR, and -request CodeRabbit review. +Status: PR opened; awaiting CI and CodeRabbit review. Branch: `codex/recover-streamcore-headroom`. -Pull request: TBD. +Pull request: `https://github.com/6529-Collections/6529Stream/pull/116`. Goal: @@ -5483,6 +5482,7 @@ Outcome: | Time UTC | Decision | Rationale | | --- | --- | --- | +| 2026-06-11 18:51 | Open PR #116 | `StreamCore` bytecode headroom recovery PR published at `https://github.com/6529-Collections/6529Stream/pull/116`; state-only follow-up records the PR URL before requesting CodeRabbit on the final head | | 2026-06-11 18:48 | Validate Queue Item 61 locally | Focused custom-error regressions, production size gate, regenerated release artifacts, full `make check`, Windows wrapper, targeted formatting, and whitespace checks all pass; `StreamCore` is 24,143 runtime bytes with 433 bytes of EIP-170 headroom | | 2026-06-11 18:39 | Set interim `StreamCore` size policy | The local P1-SIZE-001 pass measures `StreamCore` at 24,143 runtime bytes with 433 bytes of EIP-170 headroom, so the repo now documents a 384-byte minimum release floor and a 512-byte warning threshold for future non-trivial Core work | | 2026-06-11 18:37 | Drop burn custom-error experiment | Replacing the `burn` owner/approval string revert with a custom error increased `StreamCore` runtime by 20 bytes versus the narrower pass, so the change was abandoned before documentation and tests | From 31dc396446b0e5adbaad5e60f83e61d9f3402fdc Mon Sep 17 00:00:00 2001 From: Punk 6529 <108035228+punk6529@users.noreply.github.com> Date: Thu, 11 Jun 2026 19:18:22 +0000 Subject: [PATCH 3/4] Address StreamCore final supply guard review --- CHANGELOG.md | 7 +++- ...anvil-6529stream-v0.1.0-001-broadcast.json | 4 +- .../anvil-6529stream-v0.1.0-001.json | 4 +- ...anvil-6529stream-v0.1.0-001-broadcast.json | 4 +- .../examples/anvil-6529stream-v0.1.0-001.json | 4 +- docs/status.md | 7 ++-- ops/AUTONOMOUS_RUN.md | 23 +++++++---- ops/ROADMAP.md | 8 ++-- release-artifacts/latest/SHA256SUMS | 16 ++++---- release-artifacts/latest/abi-checksums.json | 8 ++-- .../latest/release-artifact-manifest.json | 2 +- .../latest/release-checksums.json | 18 ++++----- .../latest/release-manifest.json | 32 +++++++-------- .../latest/source-verification-inputs.json | 40 +++++++++---------- smart-contracts/StreamCore.sol | 40 +++++++++---------- test/StreamCoreCustomErrors.t.sol | 32 +++++++++++++++ 16 files changed, 146 insertions(+), 103 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a53ec329..198feaff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,8 +42,11 @@ the release policy in `docs/release-policy.md`. arithmetic panic, and rejected dependency registry swaps to non-contract addresses with `InvalidDependencyRegistryContract()`. - Recovered `StreamCore` runtime bytecode headroom by replacing selected legacy - string reverts with typed custom errors, bringing the production IR-optimized - runtime to 24,143 bytes with 433 bytes of EIP-170 headroom. + string reverts with typed custom errors and tightening repeated + `setCollectionData` storage access, bringing the production IR-optimized + runtime to 24,135 bytes with 441 bytes of EIP-170 headroom. +- Rejected `setFinalSupply` for collections with missing collection data using + `CollectionDataMissing(collectionId)` before final supply math can underflow. ### Release Impact diff --git a/deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json b/deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json index 8986b4b0..c11460ca 100644 --- a/deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json +++ b/deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json @@ -3,7 +3,7 @@ "generated_by": "scripts/generate_address_books.py:1", "source": { "deployment_manifest": "deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json", - "deployment_manifest_sha256": "sha256:208a2688119ac9678e7b74c566a47d9a061189120738eb9bdb26b0ca44680ce6", + "deployment_manifest_sha256": "sha256:40bf0fc8c39ee577ecd1af1e17fcd6cef657ef9f62c29ff3e6a91e76d6e7f707", "release_artifacts": "release-artifacts/latest", "abi_checksums": "release-artifacts/latest/abi-checksums.json", "event_topic_catalog": "release-artifacts/latest/event-topic-catalog.json" @@ -66,7 +66,7 @@ "source": "smart-contracts/StreamCore.sol", "artifact_path": "out/StreamCore.sol/StreamCore.json", "abi_hash": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", - "runtime_bytecode_hash": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", + "runtime_bytecode_hash": "sha256:909d5b85f9600b8550dda40ef08dded3a8a141d05d97a53e4bac2692130d469c", "verification_status": "not_applicable" }, "StreamCuratorsPool": { diff --git a/deployments/address-books/anvil-6529stream-v0.1.0-001.json b/deployments/address-books/anvil-6529stream-v0.1.0-001.json index d6aa3c09..6b67f530 100644 --- a/deployments/address-books/anvil-6529stream-v0.1.0-001.json +++ b/deployments/address-books/anvil-6529stream-v0.1.0-001.json @@ -3,7 +3,7 @@ "generated_by": "scripts/generate_address_books.py:1", "source": { "deployment_manifest": "deployments/examples/anvil-6529stream-v0.1.0-001.json", - "deployment_manifest_sha256": "sha256:3dfe1802893f9eb5f45fdee014761365d0cc6baf33e26d938ed6547680b26645", + "deployment_manifest_sha256": "sha256:211887f2a8e15dba3a1f8f2daf3c9dc21d84ec1e921136fb77bd6de0bd0df45e", "release_artifacts": "release-artifacts/latest", "abi_checksums": "release-artifacts/latest/abi-checksums.json", "event_topic_catalog": "release-artifacts/latest/event-topic-catalog.json" @@ -66,7 +66,7 @@ "source": "smart-contracts/StreamCore.sol", "artifact_path": "out/StreamCore.sol/StreamCore.json", "abi_hash": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", - "runtime_bytecode_hash": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", + "runtime_bytecode_hash": "sha256:909d5b85f9600b8550dda40ef08dded3a8a141d05d97a53e4bac2692130d469c", "verification_status": "not_applicable" }, "StreamCuratorsPool": { diff --git a/deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json b/deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json index f220b279..bcb70cc9 100644 --- a/deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json +++ b/deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json @@ -50,7 +50,7 @@ "0x0000000000000000000000000000000000000002" ], "abi_hash": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", - "bytecode_hash": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", + "bytecode_hash": "sha256:909d5b85f9600b8550dda40ef08dded3a8a141d05d97a53e4bac2692130d469c", "verification_status": "not_applicable" }, "StreamCuratorsPool": { @@ -166,7 +166,7 @@ ] }, "release_artifacts": { - "manifest_sha256": "sha256:208a2688119ac9678e7b74c566a47d9a061189120738eb9bdb26b0ca44680ce6", + "manifest_sha256": "sha256:40bf0fc8c39ee577ecd1af1e17fcd6cef657ef9f62c29ff3e6a91e76d6e7f707", "abi_hashes": { "StreamAdmins": "sha256:0dec302776ef6fe8038a96a716c7300d697c52c9b8d79559ab86c2b5c6599dd5", "DependencyRegistry": "sha256:8600876198d591fdae934b20c5d370490939504890944dbd8249d85ef17a6795", diff --git a/deployments/examples/anvil-6529stream-v0.1.0-001.json b/deployments/examples/anvil-6529stream-v0.1.0-001.json index 2894a9dd..3519575f 100644 --- a/deployments/examples/anvil-6529stream-v0.1.0-001.json +++ b/deployments/examples/anvil-6529stream-v0.1.0-001.json @@ -50,7 +50,7 @@ "0x0000000000000000000000000000000000000002" ], "abi_hash": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", - "bytecode_hash": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", + "bytecode_hash": "sha256:909d5b85f9600b8550dda40ef08dded3a8a141d05d97a53e4bac2692130d469c", "verification_status": "not_applicable" }, "StreamCuratorsPool": { @@ -166,7 +166,7 @@ ] }, "release_artifacts": { - "manifest_sha256": "sha256:3dfe1802893f9eb5f45fdee014761365d0cc6baf33e26d938ed6547680b26645", + "manifest_sha256": "sha256:211887f2a8e15dba3a1f8f2daf3c9dc21d84ec1e921136fb77bd6de0bd0df45e", "abi_hashes": { "StreamAdmins": "sha256:0dec302776ef6fe8038a96a716c7300d697c52c9b8d79559ab86c2b5c6599dd5", "DependencyRegistry": "sha256:8600876198d591fdae934b20c5d370490939504890944dbd8249d85ef17a6795", diff --git a/docs/status.md b/docs/status.md index 2c3efd74..0d26f729 100644 --- a/docs/status.md +++ b/docs/status.md @@ -7,8 +7,8 @@ The current Gate A smoke baseline proves: - Foundry is configured to compile `smart-contracts`. - `forge build` runs against Solidity `0.8.19`. - `forge build --sizes --via-ir --skip test --skip script --force` runs as the production - size gate. Current `StreamCore` production runtime size is 24,143 bytes, - leaving 433 bytes of EIP-170 headroom under the IR-optimized deployment + size gate. Current `StreamCore` production runtime size is 24,135 bytes, + leaving 441 bytes of EIP-170 headroom under the IR-optimized deployment profile. This satisfies the current 384-byte minimum release floor; future non-trivial `StreamCore` feature work should preserve at least 512 bytes of warning-threshold headroom or document an explicit size-budget exception. @@ -82,7 +82,8 @@ The current Gate A smoke baseline proves: `StreamCoreCustomErrors.t.sol` proves the typed failure selectors used to recover `StreamCore` bytecode headroom for function-admin authorization, artist-signature authorization, metadata-array length validation, and - final-supply timing. + final-supply timing, plus missing collection data rejection before final + supply math. `scripts/test_metadata_fixtures.py` and `scripts/check_metadata_fixtures.py` validate the committed metadata golden fixtures outside Foundry by strictly decoding JSON and HTML data URIs, diff --git a/ops/AUTONOMOUS_RUN.md b/ops/AUTONOMOUS_RUN.md index 16cbe6ce..50cfa7c7 100644 --- a/ops/AUTONOMOUS_RUN.md +++ b/ops/AUTONOMOUS_RUN.md @@ -36,7 +36,7 @@ tests, security hardening, deployment discipline, and release/audit readiness. | Last merged PR | `https://github.com/6529-Collections/6529Stream/pull/114` | | Roadmap file | `ops/ROADMAP.md` | | State file | `ops/AUTONOMOUS_RUN.md` | -| Last updated | `2026-06-11 18:51 UTC` | +| Last updated | `2026-06-11 19:17 UTC` | ## Packaging Notes @@ -120,7 +120,7 @@ The queue will evolve as PRs merge and bot feedback arrives. ### PR candidate: Recover `StreamCore` bytecode headroom (Queue Item 61) -Status: PR opened; awaiting CI and CodeRabbit review. +Status: CodeRabbit review fix validated locally; ready to push PR update. Branch: `codex/recover-streamcore-headroom`. Pull request: `https://github.com/6529-Collections/6529Stream/pull/116`. @@ -149,11 +149,12 @@ Candidate files: Validation: - `forge test --match-contract StreamCoreCustomErrorsTest -vvv` passed with - 4 tests covering `FunctionAdminUnauthorized()`, + 5 tests covering `FunctionAdminUnauthorized()`, `ArtistSignatureUnauthorized()`, `InvalidTokenMetadataInput()`, and - `FinalSupplyTimeNotPassed()`. + `FinalSupplyTimeNotPassed()`, plus `setFinalSupply` rejection when collection + data is missing. - `forge build --sizes --via-ir --skip test --skip script --force` passed; - final measured `StreamCore` runtime size is 24,143 bytes with 433 bytes of + final measured `StreamCore` runtime size is 24,135 bytes with 441 bytes of EIP-170 headroom. - `make release-checksums` passed and regenerated release/deployment artifacts. - `make check` passed. @@ -167,6 +168,12 @@ Notes: - A separate `burn` authorization custom-error experiment increased runtime size by 20 bytes versus the first pass, so it was intentionally dropped. +- CodeRabbit found that `setFinalSupply` could reach final supply math for a + created collection with missing collection data. The fix now checks the + existing mutable collection boundary, rejects missing data with + `CollectionDataMissing(collectionId)`, and keeps the size floor above 384 + bytes by collapsing duplicated `setCollectionData` writes through a storage + pointer. - The recovery is intentionally narrow: no contract state layout, external function signatures, event signatures, or successful-path behavior changed. @@ -5482,9 +5489,11 @@ Outcome: | Time UTC | Decision | Rationale | | --- | --- | --- | +| 2026-06-11 19:17 | Validate PR #116 review fix locally | `make release-checksums`, `make check`, Windows `scripts\check.ps1`, targeted `forge fmt --check`, and `git diff --check` pass after the CodeRabbit fix; `git diff --check` reports only the known Windows line-ending warning on `release-artifacts/latest/SHA256SUMS` | +| 2026-06-11 19:09 | Address CodeRabbit PR #116 finding | `setFinalSupply` now rejects created collections with missing collection data before final supply math, the focused suite passes with 5 tests, and the production size gate measures `StreamCore` at 24,135 runtime bytes with 441 bytes of EIP-170 headroom | | 2026-06-11 18:51 | Open PR #116 | `StreamCore` bytecode headroom recovery PR published at `https://github.com/6529-Collections/6529Stream/pull/116`; state-only follow-up records the PR URL before requesting CodeRabbit on the final head | -| 2026-06-11 18:48 | Validate Queue Item 61 locally | Focused custom-error regressions, production size gate, regenerated release artifacts, full `make check`, Windows wrapper, targeted formatting, and whitespace checks all pass; `StreamCore` is 24,143 runtime bytes with 433 bytes of EIP-170 headroom | -| 2026-06-11 18:39 | Set interim `StreamCore` size policy | The local P1-SIZE-001 pass measures `StreamCore` at 24,143 runtime bytes with 433 bytes of EIP-170 headroom, so the repo now documents a 384-byte minimum release floor and a 512-byte warning threshold for future non-trivial Core work | +| 2026-06-11 18:48 | Validate Queue Item 61 locally | Focused custom-error regressions, production size gate, regenerated release artifacts, full `make check`, Windows wrapper, targeted formatting, and whitespace checks all pass; the final review-fix pass records `StreamCore` at 24,135 runtime bytes with 441 bytes of EIP-170 headroom | +| 2026-06-11 18:39 | Set interim `StreamCore` size policy | The local P1-SIZE-001 pass established a repo policy of 384 bytes as the minimum release floor and 512 bytes as the warning threshold for future non-trivial Core work; final review-fix measurement is 24,135 runtime bytes with 441 bytes of EIP-170 headroom | | 2026-06-11 18:37 | Drop burn custom-error experiment | Replacing the `burn` owner/approval string revert with a custom error increased `StreamCore` runtime by 20 bytes versus the narrower pass, so the change was abandoned before documentation and tests | | 2026-06-11 18:22 | Validate PR #114 outside-diff follow-up locally | Focused regressions, production size gate, regenerated release artifacts, full `make check`, Windows wrapper, targeted formatting, and whitespace checks all pass; `StreamCore` remains deployable at 24,545 bytes with 31 bytes of EIP-170 headroom | | 2026-06-11 18:15 | Accept CodeRabbit PR #114 outside-diff findings | The zero-supply path still reverted via arithmetic panic on first initialization, and dependency registry swaps still accepted EOAs or zero addresses; both are fixed locally with typed errors/regressions while keeping `StreamCore` deployable at 24,545 bytes and 31 bytes of EIP-170 headroom | diff --git a/ops/ROADMAP.md b/ops/ROADMAP.md index eb3a568c..a5573ccd 100644 --- a/ops/ROADMAP.md +++ b/ops/ROADMAP.md @@ -47,7 +47,7 @@ order. bundle, while live fork/testnet rehearsals, production broadcast retention, and live artifact verification remain open. Near-term `StreamCore` bytecode headroom remains a tracked release risk: the P1-SIZE-001 recovery pass brings - the IR-optimized runtime to 24,143 bytes with 433 bytes of EIP-170 headroom, + the IR-optimized runtime to 24,135 bytes with 441 bytes of EIP-170 headroom, satisfying the current 384-byte minimum release floor. Future non-trivial Core work should preserve at least 512 bytes of warning-threshold headroom or explicitly spend an approved size budget first. @@ -72,7 +72,7 @@ order. | --- | --- | --- | --- | | Build | Passes with warnings when `forge` is invoked through the installed binary path | `forge build` | Build passes in CI and locally with warnings burned down or documented | | Unit/integration tests | Tests cover admin guards, target-scoped function-admin permission regressions, domain-scoped pause controls, EIP-712/ERC-1271 drop authorization, auction custody and payment credits, fixed-price pull-payment credits, curator reward credits, current emergency-withdrawal boundaries, randomizer lifecycle/callback validation, randomness/pending metadata behavior, ERC-4906 metadata update signaling, raw-output hash storage, dependency-script encoding hashes, explicit local-initialization regressions, vendored utility-library regressions, and retained airdrop mint-accounting behavior; broader P0/P1 tests are missing | `forge test -vvv` | P0 regression and integration suite exists | -| Production size | Production deployable contracts pass the IR-optimized size gate; the P1-SIZE-001 recovery pass replaces selected legacy `StreamCore` string reverts with typed custom errors and measures `StreamCore` at 24,143 runtime bytes with 433 bytes of EIP-170 headroom; current minimum release floor is 384 bytes, and future non-trivial Core work should stay above the 512-byte warning threshold or document an approved size-budget exception | `forge build --sizes --via-ir --skip test --skip script --force` | Production size gate passes in CI and deployment scripts use the same profile, with the agreed minimum `StreamCore` margin enforced before release | +| Production size | Production deployable contracts pass the IR-optimized size gate; the P1-SIZE-001 recovery pass replaces selected legacy `StreamCore` string reverts with typed custom errors, rejects missing collection data before final-supply math, and measures `StreamCore` at 24,135 runtime bytes with 441 bytes of EIP-170 headroom; current minimum release floor is 384 bytes, and future non-trivial Core work should stay above the 512-byte warning threshold or document an approved size-budget exception | `forge build --sizes --via-ir --skip test --skip script --force` | Production size gate passes in CI and deployment scripts use the same profile, with the agreed minimum `StreamCore` margin enforced before release | | Formatting | Fails broadly | `forge fmt --check smart-contracts` | Passing, or vendored exclusions documented | | Static analysis | Runs with a tracked high/medium baseline: 717 total findings, including 4 High, 19 Medium, and 93 Low; current high/medium rows are fixed, accepted, or documented false positives | `slither . --config-file slither.config.json --foundry-compile-all`, `ops/SLITHER_BASELINE.md`, and `docs/vendored-libraries.md` | High/medium findings fixed, accepted, or documented | | Deployment | Partial local baseline: deploy-and-wire rehearsal script, manifest schema, address-book schema, generated Anvil manifest config/example, sanitized Foundry broadcast fixture ingestion, generated Anvil and broadcast-derived address books, manifest parsing test, and generated ABI/bytecode checksum inputs exist; live fork/testnet rehearsal and production broadcast retention remain missing | `forge script script/RehearseDeployment.s.sol:RehearseDeployment --sig "run()" --via-ir`, `test/StreamDeploymentManifest.t.sol`, `scripts/generate_broadcast_manifest_input.py --check`, `scripts/generate_deployment_manifest.py --check`, `scripts/generate_deployment_manifest.py --config deployments/config/anvil-6529stream-v0.1.0-001-broadcast.json --check`, `scripts/generate_address_books.py --check`, `deployments/broadcasts/`, `deployments/schema/deployment-manifest.schema.json`, `deployments/schema/address-book.schema.json`, `deployments/address-books/`, and `release-artifacts/latest/abi-checksums.json` | Anvil deployment and fork rehearsal pass | @@ -434,7 +434,7 @@ This is the recommended first batch of issues. 31. [`P1-RELEASE-006`](https://github.com/6529-Collections/6529Stream/issues/105) / P1/OPS+TEST+DOCS: Generate a machine-readable release manifest tying release artifacts, deployment artifacts, governance docs, and release-ceremony status together. 32. [`P1-RELEASE-007`](https://github.com/6529-Collections/6529Stream/issues/107) / P1/OPS+TEST+DOCS: Generate source verification inputs from production Foundry artifacts, source files, compiler settings, and contract config. 33. [`P1-DEPLOY-004`](https://github.com/6529-Collections/6529Stream/issues/109) / P1/OPS+TEST+DOCS: Ingest sanitized Foundry broadcast output into deterministic deployment-manifest evidence. -34. [`P1-SIZE-001`](https://github.com/6529-Collections/6529Stream/issues/115) / P1/CODE+TEST+OPS: Recover sustainable `StreamCore` bytecode headroom or define an explicit size budget before adding further non-trivial Core feature work. Active recovery pass measures `StreamCore` at 24,143 runtime bytes with 433 bytes of EIP-170 headroom, above the 384-byte minimum release floor. +34. [`P1-SIZE-001`](https://github.com/6529-Collections/6529Stream/issues/115) / P1/CODE+TEST+OPS: Recover sustainable `StreamCore` bytecode headroom or define an explicit size budget before adding further non-trivial Core feature work. Active recovery pass measures `StreamCore` at 24,135 runtime bytes with 441 bytes of EIP-170 headroom, above the 384-byte minimum release floor. ## 5. Best-Practice Checklist @@ -2247,7 +2247,7 @@ Status values: `Missing`, `Planned`, `In Progress`, `Passing`, `Blocked`. | Pending randomness metadata | Off-chain and on-chain `tokenURI` pending/final behavior is deterministic and never treats zero hash as finalized randomness | `test/StreamMetadataGolden.t.sol`, later `test/StreamMetadata.t.sol` | Passing for schema-v1 coverage: off-chain pending/final URIs match fixtures, on-chain pending output returns base64 JSON with `metadata_state: "pending"` and no final animation HTML, and on-chain final output returns base64 JSON with `metadata_state: "final"` and the animation URL. Stale-state display remains future metadata/randomness work. | [`P1-META-ADR`](https://github.com/6529-Collections/6529Stream/issues/45), [`P1-META-001`](https://github.com/6529-Collections/6529Stream/issues/46), [`P0-RAND-004`](https://github.com/6529-Collections/6529Stream/issues/40) | Gate C/Gate D | TBD | | Metadata schema golden files | Off-chain URI rules, on-chain pending JSON, on-chain final JSON, and generated HTML remain deterministic under the accepted schema | `test/StreamMetadataGolden.t.sol` | Passing for current schema-v1 slice: `offchain-pending-token-uri.txt`, `offchain-final-token-uri.txt`, `onchain-pending-schema-v1-token-uri.txt`, and `onchain-final-schema-v1-token-uri.txt` lock output, and `metadataSchemaVersion()` plus `tokenMetadataState(tokenId)` expose the active schema and state. Escaping and stale-state display remain future P1-META work. | [`P1-META-001`](https://github.com/6529-Collections/6529Stream/issues/46) | Gate D | TBD | | Metadata escaping and render safety | JSON, HTML, JavaScript, raw attributes, URI, and size-limit inputs are escaped, validated, or rejected | `test/StreamMetadataEscaping.t.sol`, `test/StreamMetadataSizeLimits.t.sol`, `test/StreamMetadataUriPolicy.t.sol`, `scripts/test_metadata_fixtures.py`, `scripts/check_metadata_fixtures.py` | Partial: on-chain JSON string fields are escaped for schema-v1 output; raw attribute fragments reject literal control characters, unterminated strings, unbalanced delimiters, and unquoted array/object breakout attempts; decoded metadata is parser-checked for hostile collection/image strings; final animation HTML is decoded to assert library-attribute escaping, escaped `tokenData` and dependency-script JavaScript string embedding, and closing-script neutralization; numeric byte caps are enforced for collection display fields, collection scripts, token data, token images, token attributes, generated `tokenURI` output, dependency scripts, and dependency provenance; committed metadata golden fixtures are checked outside Foundry for strict JSON/HTML data-URI decoding, metadata JSON shape, current URI scheme policy, and generated final animation wrapper/script boundaries; production writes reject unsafe token image, collection base URI, and external library URL values. Remaining work: semantic attribute schema validation or structured attributes, invalid UTF-8 policy, and full browser execution sandbox tests. | [`P1-META-006`](https://github.com/6529-Collections/6529Stream/issues/51) | Gate D | TBD | -| `StreamCore` bytecode headroom | Optimized failure paths keep the same guarded behavior, expose typed selectors, and production bytecode stays above the agreed minimum floor | `test/StreamCoreCustomErrors.t.sol`, production size gate | Passing locally: selected admin, artist-signature, metadata-array length, and final-supply timing string reverts now use custom errors with direct selector regressions; `forge build --sizes --via-ir --skip test --skip script --force` measures `StreamCore` at 24,143 runtime bytes with 433 bytes of EIP-170 headroom, above the 384-byte minimum release floor and below the 512-byte warning threshold for future non-trivial Core work | [`P1-SIZE-001`](https://github.com/6529-Collections/6529Stream/issues/115) | Gate D/Gate G | TBD | +| `StreamCore` bytecode headroom | Optimized failure paths keep the same guarded behavior, expose typed selectors, and production bytecode stays above the agreed minimum floor | `test/StreamCoreCustomErrors.t.sol`, production size gate | Passing locally: selected admin, artist-signature, metadata-array length, final-supply timing, and missing collection data failures now use direct selector regressions; `forge build --sizes --via-ir --skip test --skip script --force` measures `StreamCore` at 24,135 runtime bytes with 441 bytes of EIP-170 headroom, above the 384-byte minimum release floor and below the 512-byte warning threshold for future non-trivial Core work | [`P1-SIZE-001`](https://github.com/6529-Collections/6529Stream/issues/115) | Gate D/Gate G | TBD | | Collection freeze boundary | Frozen collections cannot mutate collection fields, base URI, metadata mode, scripts, dependency references, token data, image, attributes, final supply, or live-token metadata state | `test/StreamMetadataFreeze.t.sol` | Passing for current `StreamCore` boundary: freeze requires ended minting, elapsed final-supply delay, and final live-token metadata; stores and exposes `collectionFreezeManifestHash`; emits `CollectionFrozen`; finalizes supply to minted-ever count; tightens the reserved max token ID; blocks dependency-registry swaps while any collection is frozen; and rejects current metadata-significant writes after freeze. Dependency version pins are included in the freeze manifest; escaping and richer invariant/fork coverage remain future P1-META work. | [`P1-META-002`](https://github.com/6529-Collections/6529Stream/issues/47) | Gate D | TBD | | Dependency registry immutability | Dependency versions are immutable, pinned by key/version/content hash/registry address, and cannot change frozen collection output | `test/StreamDependencyRegistry.t.sol` | Passing: registry writes create new immutable versions, chunk-index updates derive a new version without mutating the previous one, version records expose typed content hash/provenance/creator/creation/deprecation views, collection metadata pins key/version/content hash/registry address, explicit repinning moves an unfrozen collection to the latest dependency in the current registry, output and freeze manifests stay stable after later registry versions or registry swaps until explicit repin, and segment-boundary hashes remain distinct in `test/StreamMetadataEncoding.t.sol`. Dependency artifact packaging and migration runbooks remain future operational work. | [`P1-META-003`](https://github.com/6529-Collections/6529Stream/issues/48) | Gate D | TBD | | ERC-4906 metadata signaling | `supportsInterface(0x49064906)` succeeds and `MetadataUpdate` / `BatchMetadataUpdate` emit from metadata write paths that can change token JSON | `test/StreamMetadataEvents.t.sol` | Passing for current `StreamCore` behavior: ERC-4906 interface support succeeds, randomness fulfillment and token metadata input writes emit `MetadataUpdate`, collection-level metadata mode/base URI/display/script/dependency-reference writes emit `BatchMetadataUpdate` over the minted-ever range, empty collections do not emit empty batch events, and mint-only plus burn paths do not emit ERC-4906. Dependency registry version creation does not emit ERC-4906 for pinned collections because their output does not change; explicit repinning goes through `updateCollectionInfo` and emits the existing collection-range update. | [`P1-META-004`](https://github.com/6529-Collections/6529Stream/issues/49), [`P1-META-003`](https://github.com/6529-Collections/6529Stream/issues/48) | Gate D | TBD | diff --git a/release-artifacts/latest/SHA256SUMS b/release-artifacts/latest/SHA256SUMS index 73fa743b..b6086d01 100644 --- a/release-artifacts/latest/SHA256SUMS +++ b/release-artifacts/latest/SHA256SUMS @@ -1,17 +1,17 @@ -ab441b5d3b80c071b29f261d2dcc0dd3534dc27146c5377c632d920eda136ce6 deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json -6e7b7ea8717f661ca83dcf36919da703baf8024457b0ec82d35e8c6dea5ccb97 deployments/address-books/anvil-6529stream-v0.1.0-001.json +6f424cb840efb8debc1e2ff020e567cbbf307ca11fa5dd38c46cdd082f99cc98 deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json +01513b438319ebe457dc764db0c39087a4a8ec97aafe5f17445bcdb63da2af3e deployments/address-books/anvil-6529stream-v0.1.0-001.json 5697fb0387369b1127666f8c38b2a952dc2b085f7ab1188c1d18ac32da6141d3 deployments/broadcasts/anvil-6529stream-v0.1.0-001-run-latest.json b4ebc06aaa7c06ccf1a15ef8a79a6fdc866785f5d4996fc34af42bf3deed07f5 deployments/config/anvil-6529stream-v0.1.0-001-broadcast.json 03ff60467a5271ff5c8c638525dc355c3d00d78781cbcaa23c2d380995bb658b deployments/config/anvil-6529stream-v0.1.0-001.json -acf786414981880ea5bb5dd68893bf094c7f7cfca949a415bdfc1b34b4e6e157 deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json -67bfb20c740c2ee76433369d50bec171fcc783868c5aad484239f3ed672a3704 deployments/examples/anvil-6529stream-v0.1.0-001.json +00bae7664f8bc59f17d66be6e08ef075551dedc54d37ae32d87436aa141c975d deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json +1c1a9a9cda526f612a229f907b8ac6c380f8bb1c56bd8f872348df2b19cac2f8 deployments/examples/anvil-6529stream-v0.1.0-001.json e36a4a98e66c0bdcd6f5cd6c8125e547c53bd4537a7ee2c25a69f041ec2c3d13 deployments/schema/address-book.schema.json 3de078b625d0bf9fd49e352137efe7320d8ef701c04b0d5dc3dbfb5e560b7cfd deployments/schema/deployment-manifest.schema.json 44e97807c70ed606edb985cca85eace493a893a62c345212c18e7834ba6c08be release-artifacts/baselines/v0.1.0/abi-surface.json da895fbb51bc43b91b9c704bdef2186f718f171158487a52332023b858489011 release-artifacts/contracts.json -029cf68482f991196e0c8dccd055d62abdcc518e8df23b8e558b98d244b52bb9 release-artifacts/latest/abi-checksums.json +c9c8f63bb3cd76c5f71a17c97dafa875ecf99612f0c45a53490192224f30e414 release-artifacts/latest/abi-checksums.json 6dd5190f816fd3ab72adcc6f1ae761aadf900dd24f0bd0f7bebc1697fed423af release-artifacts/latest/event-topic-catalog.json 8a8a41d89757d3d16f0718638d1175290dcd00cfea86204665cd525f608d7c1a release-artifacts/latest/interface-ids.json -33294e594946270d4fd58d1b0dcbe6b088a3cce3d3fcbbd93f6bb02bd1489bfe release-artifacts/latest/release-artifact-manifest.json -4f9b885ecfb6b30b9b3d9a3a3951b87f889894f74945bccf33ad32e5ce054c17 release-artifacts/latest/release-manifest.json -b3ed8edf726267acc4a99ca0bd97423c601748faa3ed83c9371c85d54e29e152 release-artifacts/latest/source-verification-inputs.json +4fb9750bbab1c8da15571563973962f2649e80f81c577fe074f0e661ac0d7553 release-artifacts/latest/release-artifact-manifest.json +cd3634d43cfc3b9eaf78ac659d54db19bc3b945a8a3a74b7c2acfe98734bd7e1 release-artifacts/latest/release-manifest.json +e4b84a577ef363073f2a34f008a00156c45763755850193a71ea58a8dc625754 release-artifacts/latest/source-verification-inputs.json diff --git a/release-artifacts/latest/abi-checksums.json b/release-artifacts/latest/abi-checksums.json index a8bb26de..7aa21396 100644 --- a/release-artifacts/latest/abi-checksums.json +++ b/release-artifacts/latest/abi-checksums.json @@ -79,12 +79,12 @@ }, "StreamCore": { "creation": { - "sha256": "sha256:b4dff26f761549ee3e635f099803d789fb3ec2a009e12b6b55a85ab4eea5d46c", + "sha256": "sha256:f183d07e38a80cde9b0d186acaab77798a2ca7e67ee0e007de3dfdda0da03b12", "linked": false, "hash_mode": "unlinked_artifact_object" }, "runtime": { - "sha256": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", + "sha256": "sha256:909d5b85f9600b8550dda40ef08dded3a8a141d05d97a53e4bac2692130d469c", "linked": false, "hash_mode": "unlinked_artifact_object" } @@ -206,10 +206,10 @@ "source": "smart-contracts/StreamCore.sol", "artifact_path": "out/StreamCore.sol/StreamCore.json", "abi_sha256": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", - "bytecode_sha256": "sha256:b4dff26f761549ee3e635f099803d789fb3ec2a009e12b6b55a85ab4eea5d46c", + "bytecode_sha256": "sha256:f183d07e38a80cde9b0d186acaab77798a2ca7e67ee0e007de3dfdda0da03b12", "bytecode_linked": false, "bytecode_hash_mode": "unlinked_artifact_object", - "deployed_bytecode_sha256": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", + "deployed_bytecode_sha256": "sha256:909d5b85f9600b8550dda40ef08dded3a8a141d05d97a53e4bac2692130d469c", "deployed_bytecode_linked": false, "deployed_bytecode_hash_mode": "unlinked_artifact_object", "abi_entries": 118, diff --git a/release-artifacts/latest/release-artifact-manifest.json b/release-artifacts/latest/release-artifact-manifest.json index 2ca0e9b6..bb1dd616 100644 --- a/release-artifacts/latest/release-artifact-manifest.json +++ b/release-artifacts/latest/release-artifact-manifest.json @@ -8,7 +8,7 @@ "artifacts": { "abi-checksums.json": { "path": "abi-checksums.json", - "sha256": "sha256:029cf68482f991196e0c8dccd055d62abdcc518e8df23b8e558b98d244b52bb9" + "sha256": "sha256:c9c8f63bb3cd76c5f71a17c97dafa875ecf99612f0c45a53490192224f30e414" }, "event-topic-catalog.json": { "path": "event-topic-catalog.json", diff --git a/release-artifacts/latest/release-checksums.json b/release-artifacts/latest/release-checksums.json index 556030eb..602780b7 100644 --- a/release-artifacts/latest/release-checksums.json +++ b/release-artifacts/latest/release-checksums.json @@ -18,7 +18,7 @@ "text_checksum_file": { "path": "release-artifacts/latest/SHA256SUMS", "format": "sha256sum", - "sha256": "sha256:e1db038db1b1d4b9626c90c5fedee53339982662edf88457c450c018645e874f" + "sha256": "sha256:e339de97a1c9cd05cdc952e3ed3721ca30b5e289b2af5050db4794fd1571fb86" }, "manifest_file": { "path": "release-artifacts/latest/release-checksums.json", @@ -27,12 +27,12 @@ "files": [ { "path": "deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json", - "sha256": "sha256:ab441b5d3b80c071b29f261d2dcc0dd3534dc27146c5377c632d920eda136ce6", + "sha256": "sha256:6f424cb840efb8debc1e2ff020e567cbbf307ca11fa5dd38c46cdd082f99cc98", "size_bytes": 5082 }, { "path": "deployments/address-books/anvil-6529stream-v0.1.0-001.json", - "sha256": "sha256:6e7b7ea8717f661ca83dcf36919da703baf8024457b0ec82d35e8c6dea5ccb97", + "sha256": "sha256:01513b438319ebe457dc764db0c39087a4a8ec97aafe5f17445bcdb63da2af3e", "size_bytes": 5062 }, { @@ -52,12 +52,12 @@ }, { "path": "deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json", - "sha256": "sha256:acf786414981880ea5bb5dd68893bf094c7f7cfca949a415bdfc1b34b4e6e157", + "sha256": "sha256:00bae7664f8bc59f17d66be6e08ef075551dedc54d37ae32d87436aa141c975d", "size_bytes": 8299 }, { "path": "deployments/examples/anvil-6529stream-v0.1.0-001.json", - "sha256": "sha256:67bfb20c740c2ee76433369d50bec171fcc783868c5aad484239f3ed672a3704", + "sha256": "sha256:1c1a9a9cda526f612a229f907b8ac6c380f8bb1c56bd8f872348df2b19cac2f8", "size_bytes": 8262 }, { @@ -82,7 +82,7 @@ }, { "path": "release-artifacts/latest/abi-checksums.json", - "sha256": "sha256:029cf68482f991196e0c8dccd055d62abdcc518e8df23b8e558b98d244b52bb9", + "sha256": "sha256:c9c8f63bb3cd76c5f71a17c97dafa875ecf99612f0c45a53490192224f30e414", "size_bytes": 11136 }, { @@ -97,17 +97,17 @@ }, { "path": "release-artifacts/latest/release-artifact-manifest.json", - "sha256": "sha256:33294e594946270d4fd58d1b0dcbe6b088a3cce3d3fcbbd93f6bb02bd1489bfe", + "sha256": "sha256:4fb9750bbab1c8da15571563973962f2649e80f81c577fe074f0e661ac0d7553", "size_bytes": 737 }, { "path": "release-artifacts/latest/release-manifest.json", - "sha256": "sha256:4f9b885ecfb6b30b9b3d9a3a3951b87f889894f74945bccf33ad32e5ce054c17", + "sha256": "sha256:cd3634d43cfc3b9eaf78ac659d54db19bc3b945a8a3a74b7c2acfe98734bd7e1", "size_bytes": 10704 }, { "path": "release-artifacts/latest/source-verification-inputs.json", - "sha256": "sha256:b3ed8edf726267acc4a99ca0bd97423c601748faa3ed83c9371c85d54e29e152", + "sha256": "sha256:e4b84a577ef363073f2a34f008a00156c45763755850193a71ea58a8dc625754", "size_bytes": 46335 } ] diff --git a/release-artifacts/latest/release-manifest.json b/release-artifacts/latest/release-manifest.json index cf41001f..df8ba9ce 100644 --- a/release-artifacts/latest/release-manifest.json +++ b/release-artifacts/latest/release-manifest.json @@ -30,7 +30,7 @@ }, "abi_checksums": { "path": "release-artifacts/latest/abi-checksums.json", - "sha256": "sha256:029cf68482f991196e0c8dccd055d62abdcc518e8df23b8e558b98d244b52bb9", + "sha256": "sha256:c9c8f63bb3cd76c5f71a17c97dafa875ecf99612f0c45a53490192224f30e414", "size_bytes": 11136, "schema_version": "6529stream.abi-checksums.v1" }, @@ -48,13 +48,13 @@ }, "artifact_manifest": { "path": "release-artifacts/latest/release-artifact-manifest.json", - "sha256": "sha256:33294e594946270d4fd58d1b0dcbe6b088a3cce3d3fcbbd93f6bb02bd1489bfe", + "sha256": "sha256:4fb9750bbab1c8da15571563973962f2649e80f81c577fe074f0e661ac0d7553", "size_bytes": 737, "schema_version": "6529stream.release-artifact-manifest.v1", "artifacts": { "abi-checksums.json": { "path": "abi-checksums.json", - "sha256": "sha256:029cf68482f991196e0c8dccd055d62abdcc518e8df23b8e558b98d244b52bb9" + "sha256": "sha256:c9c8f63bb3cd76c5f71a17c97dafa875ecf99612f0c45a53490192224f30e414" }, "event-topic-catalog.json": { "path": "event-topic-catalog.json", @@ -68,7 +68,7 @@ }, "source_verification_inputs": { "path": "release-artifacts/latest/source-verification-inputs.json", - "sha256": "sha256:b3ed8edf726267acc4a99ca0bd97423c601748faa3ed83c9371c85d54e29e152", + "sha256": "sha256:e4b84a577ef363073f2a34f008a00156c45763755850193a71ea58a8dc625754", "size_bytes": 46335, "schema_version": "6529stream.source-verification-inputs.v1" }, @@ -104,7 +104,7 @@ "manifests": [ { "path": "deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json", - "sha256": "sha256:acf786414981880ea5bb5dd68893bf094c7f7cfca949a415bdfc1b34b4e6e157", + "sha256": "sha256:00bae7664f8bc59f17d66be6e08ef075551dedc54d37ae32d87436aa141c975d", "size_bytes": 8299, "schema_version": "6529stream.deployment-manifest.v1", "protocol_version": "0.1.0", @@ -114,7 +114,7 @@ "name": "anvil", "chain_id": 31337 }, - "manifest_sha256": "sha256:208a2688119ac9678e7b74c566a47d9a061189120738eb9bdb26b0ca44680ce6", + "manifest_sha256": "sha256:40bf0fc8c39ee577ecd1af1e17fcd6cef657ef9f62c29ff3e6a91e76d6e7f707", "contracts": [ "DependencyRegistry", "NextGenRandomizerRNG", @@ -129,7 +129,7 @@ }, { "path": "deployments/examples/anvil-6529stream-v0.1.0-001.json", - "sha256": "sha256:67bfb20c740c2ee76433369d50bec171fcc783868c5aad484239f3ed672a3704", + "sha256": "sha256:1c1a9a9cda526f612a229f907b8ac6c380f8bb1c56bd8f872348df2b19cac2f8", "size_bytes": 8262, "schema_version": "6529stream.deployment-manifest.v1", "protocol_version": "0.1.0", @@ -139,7 +139,7 @@ "name": "anvil", "chain_id": 31337 }, - "manifest_sha256": "sha256:3dfe1802893f9eb5f45fdee014761365d0cc6baf33e26d938ed6547680b26645", + "manifest_sha256": "sha256:211887f2a8e15dba3a1f8f2daf3c9dc21d84ec1e921136fb77bd6de0bd0df45e", "contracts": [ "DependencyRegistry", "NextGenRandomizerRNG", @@ -156,7 +156,7 @@ "address_books": [ { "path": "deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json", - "sha256": "sha256:ab441b5d3b80c071b29f261d2dcc0dd3534dc27146c5377c632d920eda136ce6", + "sha256": "sha256:6f424cb840efb8debc1e2ff020e567cbbf307ca11fa5dd38c46cdd082f99cc98", "size_bytes": 5082, "schema_version": "6529stream.address-book.v1", "protocol_version": "0.1.0", @@ -167,7 +167,7 @@ "chain_id": 31337 }, "deployment_manifest": "deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json", - "deployment_manifest_sha256": "sha256:208a2688119ac9678e7b74c566a47d9a061189120738eb9bdb26b0ca44680ce6", + "deployment_manifest_sha256": "sha256:40bf0fc8c39ee577ecd1af1e17fcd6cef657ef9f62c29ff3e6a91e76d6e7f707", "contracts": [ "DependencyRegistry", "NextGenRandomizerRNG", @@ -182,7 +182,7 @@ }, { "path": "deployments/address-books/anvil-6529stream-v0.1.0-001.json", - "sha256": "sha256:6e7b7ea8717f661ca83dcf36919da703baf8024457b0ec82d35e8c6dea5ccb97", + "sha256": "sha256:01513b438319ebe457dc764db0c39087a4a8ec97aafe5f17445bcdb63da2af3e", "size_bytes": 5062, "schema_version": "6529stream.address-book.v1", "protocol_version": "0.1.0", @@ -193,7 +193,7 @@ "chain_id": 31337 }, "deployment_manifest": "deployments/examples/anvil-6529stream-v0.1.0-001.json", - "deployment_manifest_sha256": "sha256:3dfe1802893f9eb5f45fdee014761365d0cc6baf33e26d938ed6547680b26645", + "deployment_manifest_sha256": "sha256:211887f2a8e15dba3a1f8f2daf3c9dc21d84ec1e921136fb77bd6de0bd0df45e", "contracts": [ "DependencyRegistry", "NextGenRandomizerRNG", @@ -225,8 +225,8 @@ "release_notes_and_policy": { "changelog": { "path": "CHANGELOG.md", - "sha256": "sha256:cacec47bb4d61d2f1f3b30ade4fc45c68c6a2c8bedcc85b824ecc6a3f95ff73b", - "size_bytes": 4977 + "sha256": "sha256:57727a255f59e1af276afd26b818ad3a531fbf6cba9fc3883a2be58951736a01", + "size_bytes": 5197 }, "governance_docs": [ { @@ -246,8 +246,8 @@ }, { "path": "docs/status.md", - "sha256": "sha256:16e8fa62307ae0cceb034f17a481ae1a3bcfb254b9569cb8d57e47cfb814c474", - "size_bytes": 10848 + "sha256": "sha256:6d2eb7a1a034fd71516b864489403675e64951bae41a72429c85a02ed4c367bd", + "size_bytes": 10915 } ] }, diff --git a/release-artifacts/latest/source-verification-inputs.json b/release-artifacts/latest/source-verification-inputs.json index d6953dfe..414baf46 100644 --- a/release-artifacts/latest/source-verification-inputs.json +++ b/release-artifacts/latest/source-verification-inputs.json @@ -375,8 +375,8 @@ }, "smart-contracts/StreamCore.sol": { "path": "smart-contracts/StreamCore.sol", - "sha256": "sha256:b057b0ed92a22125cc8e347a8a38a3657336707601a0be33532d688f12a7bf57", - "solc_keccak256": "0x1c587a61dd49d034a0cd786d1a37b4554e511667ac204e5ad19a6c3b40f95feb", + "sha256": "sha256:f82ac150bd1fd865b3a86b884599acc700a8ba5f2865befac746030a7d9256ae", + "solc_keccak256": "0xd035331b7b57711a940c3bc8ca4d7fd0a9b600aaf550f5a1b1dd720e390c7e3c", "license": "MIT", "used_by": [ "StreamCore" @@ -612,7 +612,7 @@ "source_sha256": "sha256:e126bc7c0b08a3318dbb435ce24831a59b3f113c19df49752c3b71f85d748a4c", "source_solc_keccak256": "0xd5d9f10afe33ff40fa74816b9b5be05856d7a8f8a89a5b5dd22121c467291cb9", "artifact_path": "out/RandomizerVRF.sol/NextGenRandomizerVRF.json", - "artifact_sha256": "sha256:40b9452c00d7dc882b6637a0976f675dd9ed667c8d5c81f28f6f4239dd2f753b", + "artifact_sha256": "sha256:cec2337356cf0cab3a1c41b6daa3a3cee08a2a9298b00dc9fc9b6afb4ad63994", "compilation_target": "smart-contracts/RandomizerVRF.sol:NextGenRandomizerVRF", "compiler_version": "0.8.19+commit.7dd6d404", "language": "Solidity", @@ -840,10 +840,10 @@ }, "StreamCore": { "source": "smart-contracts/StreamCore.sol", - "source_sha256": "sha256:b057b0ed92a22125cc8e347a8a38a3657336707601a0be33532d688f12a7bf57", - "source_solc_keccak256": "0x1c587a61dd49d034a0cd786d1a37b4554e511667ac204e5ad19a6c3b40f95feb", + "source_sha256": "sha256:f82ac150bd1fd865b3a86b884599acc700a8ba5f2865befac746030a7d9256ae", + "source_solc_keccak256": "0xd035331b7b57711a940c3bc8ca4d7fd0a9b600aaf550f5a1b1dd720e390c7e3c", "artifact_path": "out/StreamCore.sol/StreamCore.json", - "artifact_sha256": "sha256:67cfdb4f37ecdcc48a4f6bbe8a52a714a0c066b62032c0fe92281fd8840b6c10", + "artifact_sha256": "sha256:83148e7f4c6dec0644b9aa22ffc5ca7b6d0d96bfc7e095361133d44417a66dcc", "compilation_target": "smart-contracts/StreamCore.sol:StreamCore", "compiler_version": "0.8.19+commit.7dd6d404", "language": "Solidity", @@ -860,16 +860,16 @@ "abi_sha256": "sha256:ea674cbdafc9a379139e9998fd161d0cde58b82ed053f6e5cfc8d3a3653509cc", "bytecode_hashes": { "creation": { - "sha256": "sha256:b4dff26f761549ee3e635f099803d789fb3ec2a009e12b6b55a85ab4eea5d46c", + "sha256": "sha256:f183d07e38a80cde9b0d186acaab77798a2ca7e67ee0e007de3dfdda0da03b12", "linked": false, "hash_mode": "unlinked_artifact_object", - "release_artifact_sha256": "sha256:b4dff26f761549ee3e635f099803d789fb3ec2a009e12b6b55a85ab4eea5d46c" + "release_artifact_sha256": "sha256:f183d07e38a80cde9b0d186acaab77798a2ca7e67ee0e007de3dfdda0da03b12" }, "runtime": { - "sha256": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90", + "sha256": "sha256:909d5b85f9600b8550dda40ef08dded3a8a141d05d97a53e4bac2692130d469c", "linked": false, "hash_mode": "unlinked_artifact_object", - "release_artifact_sha256": "sha256:044cc12683a6132b7bfa566b6a9125d011e7cb01d40ceb215d30dca7201edd90" + "release_artifact_sha256": "sha256:909d5b85f9600b8550dda40ef08dded3a8a141d05d97a53e4bac2692130d469c" } }, "constructor": { @@ -927,23 +927,23 @@ "length": 20 }, { - "start": 12583, + "start": 12531, "length": 20 }, { - "start": 15170, + "start": 15162, "length": 20 }, { - "start": 20915, + "start": 20907, "length": 20 }, { - "start": 21526, + "start": 21518, "length": 20 }, { - "start": 22934, + "start": 22926, "length": 20 } ] @@ -967,23 +967,23 @@ "length": 20 }, { - "start": 11359, + "start": 11307, "length": 20 }, { - "start": 13946, + "start": 13938, "length": 20 }, { - "start": 19691, + "start": 19683, "length": 20 }, { - "start": 20302, + "start": 20294, "length": 20 }, { - "start": 21710, + "start": 21702, "length": 20 } ] diff --git a/smart-contracts/StreamCore.sol b/smart-contracts/StreamCore.sol index 4e43991a..91163339 100644 --- a/smart-contracts/StreamCore.sol +++ b/smart-contracts/StreamCore.sol @@ -331,32 +331,27 @@ contract StreamCore is ERC721, ERC2981, Ownable, IERC4906 { if (_collectionTotalSupply > _COLLECTION_TOKEN_RANGE) { revert CollectionSupplyTooLarge(); } - if (collectionAdditionalData[_collectionID].collectionTotalSupply == 0) { + collectionAdditonalDataStructure storage collectionData = + collectionAdditionalData[_collectionID]; + if (collectionData.collectionTotalSupply == 0) { if (_collectionTotalSupply == 0) { revert CollectionSupplyTooLarge(); } - collectionAdditionalData[_collectionID].collectionArtistAddress = - _collectionArtistAddress; - collectionAdditionalData[_collectionID].maxCollectionPurchases = _maxCollectionPurchases; - collectionAdditionalData[_collectionID].collectionCirculationSupply = 0; - collectionAdditionalData[_collectionID].collectionTotalSupply = _collectionTotalSupply; - collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint = - _setFinalSupplyTimeAfterMint; - collectionAdditionalData[_collectionID].reservedMinTokensIndex = - (_collectionID * _COLLECTION_TOKEN_RANGE); - collectionAdditionalData[_collectionID].reservedMaxTokensIndex = + collectionData.collectionArtistAddress = _collectionArtistAddress; + collectionData.maxCollectionPurchases = _maxCollectionPurchases; + collectionData.collectionCirculationSupply = 0; + collectionData.collectionTotalSupply = _collectionTotalSupply; + collectionData.setFinalSupplyTimeAfterMint = _setFinalSupplyTimeAfterMint; + collectionData.reservedMinTokensIndex = (_collectionID * _COLLECTION_TOKEN_RANGE); + collectionData.reservedMaxTokensIndex = (_collectionID * _COLLECTION_TOKEN_RANGE) + _collectionTotalSupply - 1; wereDataAdded[_collectionID] = true; - } else if (artistSigned[_collectionID] == false) { - collectionAdditionalData[_collectionID].collectionArtistAddress = - _collectionArtistAddress; - collectionAdditionalData[_collectionID].maxCollectionPurchases = _maxCollectionPurchases; - collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint = - _setFinalSupplyTimeAfterMint; } else { - collectionAdditionalData[_collectionID].maxCollectionPurchases = _maxCollectionPurchases; - collectionAdditionalData[_collectionID].setFinalSupplyTimeAfterMint = - _setFinalSupplyTimeAfterMint; + if (!artistSigned[_collectionID]) { + collectionData.collectionArtistAddress = _collectionArtistAddress; + } + collectionData.maxCollectionPurchases = _maxCollectionPurchases; + collectionData.setFinalSupplyTimeAfterMint = _setFinalSupplyTimeAfterMint; } } @@ -653,7 +648,10 @@ contract StreamCore is ERC721, ERC2981, Ownable, IERC4906 { public FunctionAdminRequired(this.setFinalSupply.selector) { - _requireCollectionNotFrozen(_collectionID); + _requireExistingMutableCollection(_collectionID); + if (!wereDataAdded[_collectionID]) { + revert CollectionDataMissing(_collectionID); + } if ( block.timestamp <= IStreamMinter(minterContract).getEndTime(_collectionID) diff --git a/test/StreamCoreCustomErrors.t.sol b/test/StreamCoreCustomErrors.t.sol index 2dd35041..45fd583b 100644 --- a/test/StreamCoreCustomErrors.t.sol +++ b/test/StreamCoreCustomErrors.t.sol @@ -2,6 +2,8 @@ pragma solidity ^0.8.19; import "../smart-contracts/StreamCore.sol"; +import "../smart-contracts/DependencyRegistry.sol"; +import "../smart-contracts/StreamAdmins.sol"; import "./helpers/CharacterizationTestBase.sol"; import "./helpers/StreamFixture.sol"; @@ -48,4 +50,34 @@ contract StreamCoreCustomErrorsTest is CharacterizationTestBase, StreamFixture { vm.expectRevert(abi.encodeWithSelector(StreamCore.FinalSupplyTimeNotPassed.selector)); deployed.core.setFinalSupply(COLLECTION_ID); } + + function testSetFinalSupplyUsesCustomErrorWhenCollectionDataIsMissing() public { + StreamCore core = _deployCoreWithCollectionInfoOnly(); + + vm.expectRevert( + abi.encodeWithSelector(StreamCore.CollectionDataMissing.selector, COLLECTION_ID) + ); + core.setFinalSupply(COLLECTION_ID); + } + + function _deployCoreWithCollectionInfoOnly() private returns (StreamCore core) { + StreamAdmins admins = new StreamAdmins(address(this)); + admins.registerAdmin(address(this), true); + DependencyRegistry dependencyRegistry = new DependencyRegistry(address(admins)); + core = new StreamCore("6529 Stream", "STREAM", address(admins), address(dependencyRegistry)); + + string[] memory scripts = new string[](1); + scripts[0] = "function draw(){}"; + core.createCollection( + "Genesis", + "6529", + "Description", + "https://6529.io", + "CC0", + "ipfs://base/", + "https://cdn.example/script.js", + bytes32(0), + scripts + ); + } } From fc12bc6ec019d7bd8f4f31ee1e807f056fcf4207 Mon Sep 17 00:00:00 2001 From: Punk 6529 <108035228+punk6529@users.noreply.github.com> Date: Thu, 11 Jun 2026 19:25:22 +0000 Subject: [PATCH 4/4] Record StreamCore headroom merge readiness --- ops/AUTONOMOUS_RUN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ops/AUTONOMOUS_RUN.md b/ops/AUTONOMOUS_RUN.md index 50cfa7c7..4cdd6e83 100644 --- a/ops/AUTONOMOUS_RUN.md +++ b/ops/AUTONOMOUS_RUN.md @@ -120,7 +120,7 @@ The queue will evolve as PRs merge and bot feedback arrives. ### PR candidate: Recover `StreamCore` bytecode headroom (Queue Item 61) -Status: CodeRabbit review fix validated locally; ready to push PR update. +Status: PR `#116` opened and follow-up validation complete; ready to merge. Branch: `codex/recover-streamcore-headroom`. Pull request: `https://github.com/6529-Collections/6529Stream/pull/116`.