Uh oh!
There was an error while loading. Please reload this page.
fix: route DecimalFloat log table reads to the deployed Zoltu address (#189) - #193
Conversation
…#189) LibDecimalFloat.LOG_TABLES_ADDRESS was hardcoded to 0x6421E8a23cdEe2E6E579b2cDebc8C2A514843593, but the deployment script deterministically deploys the log tables to 0xc51a14251b0dcF0ae24A96b7153991378938f5F5 (LibDecimalFloatDeploy.ZOLTU_DEPLOYED_LOG_TABLES_ADDRESS). DecimalFloat's pow10/log10/pow/sqrt extcodecopy from the wrong address; on every production network the result is silent zeroed bytes (extcodecopy on an empty address does not revert), and every transcendental computation returns garbage. Removed the duplicate constant from LibDecimalFloat. Updated all eight callsites (4 in src/concrete/DecimalFloat.sol, 4 in test/src/concrete/*) to reference LibDecimalFloatDeploy.ZOLTU_DEPLOYED_LOG_TABLES_ADDRESS directly. Single source of truth removes the drift surface. Reported by Protofire audit, March 2026, finding H01 at commit 19a65ff. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (5)
WalkthroughThis PR removes the legacy hardcoded log-tables address, adds a runtime codehash check and error for the deployed log-tables, updates deployment constants, wires DecimalFloat to validate and use the deployed tables address, and updates/adds tests and the test harness to etch and validate the expected runtime. ChangesAddress Source Migration
Sequence Diagram(s)sequenceDiagram
participant Deployer
participant DecimalFloat
participant LibDecimalFloatDeploy
participant DeployedLogTables
Deployer->>DecimalFloat: deploy (constructor)
DecimalFloat->>LibDecimalFloatDeploy: checkLogTablesDeployed()
LibDecimalFloatDeploy->>DeployedLogTables: extcodehash(ZOLTU_DEPLOYED_LOG_TABLES_ADDRESS)
DeployedLogTables-->>LibDecimalFloatDeploy: codehash
alt codehash == expected
LibDecimalFloatDeploy-->>DecimalFloat: success
else mismatch
LibDecimalFloatDeploy-->>Deployer: revert LogTablesNotDeployed(address, expected, actual)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Address and codehash from CI's testDeployAddress and testExpectedCodeHashDecimalFloat assertion outputs after the H01 fix shifted the bytecode (and thus the deterministic Zoltu address). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
test/src/concrete/DecimalFloat.sqrt.t.sol (1)
17-27:⚠️ Potential issue | 🟠 Major | ⚡ Quick winThis test is self-referential and won’t catch a bad table deployment.
At Line 20-23 both values are derived from paths that use the same table address, so a wrong/empty deployment can still produce matching (wrong) outputs and pass. Add an independent check (e.g., codehash assertion) before comparison.
Suggested guard in test
function testSqrtDeployed(Float a) external { DecimalFloat deployed = new DecimalFloat(); + assertEq(+ LibDecimalFloatDeploy.ZOLTU_DEPLOYED_LOG_TABLES_ADDRESS.codehash,+ LibDecimalFloatDeploy.LOG_TABLES_DATA_CONTRACT_HASH+ ); try this.sqrtExternal(a) returns (Float c) { Float deployedC = deployed.sqrt(a);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/src/concrete/DecimalFloat.sqrt.t.sol` around lines 17 - 27, The test testSqrtDeployed is comparing outputs from two callers that use the same deployed table, so add an independent guard to ensure the deployed DecimalFloat table is actually deployed before comparing results: after creating DecimalFloat deployed = new DecimalFloat(); assert that address(deployed).codehash (or extcodesize(address(deployed))) indicates non-empty code (e.g., codehash != bytes32(0)) to detect an empty/wrong deployment, and only then proceed to call deployed.sqrt(a) and compare with this.sqrtExternal(a); keep the check before calling deployed.sqrt and before the assertEq so a bad/empty deployment fails the test early.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/concrete/DecimalFloat.sol`:
- Around line 233-255: Add a fail-fast check that the deployed log tables
contract exists and matches the expected codehash before any table reads in the
exposed functions pow10, log10, pow, and sqrt in DecimalFloat.sol: before
calling a.pow10(...)/a.log10(...)/a.pow(...)/a.sqrt(...), perform an extcodehash
(or similar) on LibDecimalFloatDeploy.ZOLTU_DEPLOYED_LOG_TABLES_ADDRESS and
require it equals the known expected table codehash (revert with a clear error
like "InvalidLogTablesContract" if not), so the functions revert immediately
instead of silently proceeding with a missing/mismatched table.
---
Outside diff comments:
In `@test/src/concrete/DecimalFloat.sqrt.t.sol`:
- Around line 17-27: The test testSqrtDeployed is comparing outputs from two
callers that use the same deployed table, so add an independent guard to ensure
the deployed DecimalFloat table is actually deployed before comparing results:
after creating DecimalFloat deployed = new DecimalFloat(); assert that
address(deployed).codehash (or extcodesize(address(deployed))) indicates
non-empty code (e.g., codehash != bytes32(0)) to detect an empty/wrong
deployment, and only then proceed to call deployed.sqrt(a) and compare with
this.sqrtExternal(a); keep the check before calling deployed.sqrt and before the
assertEq so a bad/empty deployment fails the test early.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 37595689-9dac-452d-b514-7a56782c31de
📒 Files selected for processing (7)
src/concrete/DecimalFloat.solsrc/lib/LibDecimalFloat.solsrc/lib/deploy/LibDecimalFloatDeploy.soltest/src/concrete/DecimalFloat.log10.t.soltest/src/concrete/DecimalFloat.pow.t.soltest/src/concrete/DecimalFloat.pow10.t.soltest/src/concrete/DecimalFloat.sqrt.t.sol
💤 Files with no reviewable changes (1)
- src/lib/LibDecimalFloat.sol
Uh oh!
There was an error while loading. Please reload this page.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Without this, the four `DecimalFloat.*Deployed` tests had both the external helper and the deployed contract `extcodecopy` from an empty address, agree on garbage, and pass without verifying anything — the exact H01 failure mode this PR fixes in production. Etching the table runtime at `ZOLTU_DEPLOYED_LOG_TABLES_ADDRESS` plus asserting its codehash against `LOG_TABLES_DATA_CONTRACT_HASH` makes those tests detect any reintroduction of an address mismatch. Per-run gas after the fix is ~3.9M, confirming the tests now exercise real table lookups instead of falling into the catch path. Addresses CodeRabbit feedback on PR #193 (suggested per-test codehash assertion; consolidated into LogTest.setUp). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds LibDecimalFloatDeploy.checkLogTablesDeployed() — reverts with LogTablesNotDeployed when ZOLTU_DEPLOYED_LOG_TABLES_ADDRESS does not have code matching LOG_TABLES_DATA_CONTRACT_HASH. DecimalFloat's constructor calls it; integrators that read from ZOLTU_DEPLOYED_LOG_TABLES_ADDRESS in their own contracts should call it from their own constructors. Closes the H02 audit finding (no runtime extcodesize/codehash check before extcodecopy on log tables). Test changes: - Concrete DecimalFloat.*Deployed tests already inherited LogTest (sqrt/pow/pow10/log10); migrated the remaining 26 concrete test files plus LibDecimalFloatDeployTest from `is Test` to `is LogTest`, so the LogTest.setUp etch makes the gated constructor reachable. - New DecimalFloat.constructor.t.sol: directly exercises the guard without inheriting LogTest. Tests: empty address reverts, wrong codehash reverts, correct etch succeeds, plus a mutation guard swapping correct runtime for zero bytes confirms the test detects the codehash check (not just any creation failure). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The constructor tests transitively exercise the lib function, but the function is meant for external integrators to call from their own constructors too — so it deserves direct coverage independent of DecimalFloat. Mirrors DecimalFloat.constructor.t.sol but invokes the lib function directly: empty address, wrong codehash, correct etch, and a mutation guard. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The new DecimalFloat constructor guard reverts if the log tables aren't already at ZOLTU_DEPLOYED_LOG_TABLES_ADDRESS. The fork target is ETH L1 (per CI_FORK_ETH_RPC_URL), where the log tables aren't pre-deployed — they live on Arbitrum/Base/Flare/Polygon. Deploy them via Zoltu in the test before deploying DecimalFloat to satisfy the guard. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/src/concrete/DecimalFloat.constructor.t.sol`:
- Around line 74-77: The assembly create result `temp` is unchecked before
calling `vm.etch`, so if `create` failed the test setup is ambiguous; after the
assembly block that does `temp := create(0, add(creationCode, 0x20),
mload(creationCode))` add an explicit assertion that `temp` is non-zero (e.g.,
require/assert that `temp != address(0)` or `temp != 0`) before `vm.etch` using
the same `temp` and reference
`LibDecimalFloatDeploy.ZOLTU_DEPLOYED_LOG_TABLES_ADDRESS` and `temp.code` to
ensure creation succeeded and fail fast with a clear message if it did not.
- Around line 84-85: The test is too broad using vm.expectRevert() before new
DecimalFloat(); — tighten it to assert the specific revert emitted by the
DecimalFloat constructor (the codehash guard) by replacing vm.expectRevert()
with vm.expectRevert(<expected>) where <expected> is the exact revert reason or
encoded selector used by the constructor (e.g., the revert string or
abi.encodeWithSelector/<encoded bytes> for the custom error). Use the
DecimalFloat constructor's actual error identifier (error name or message or
bytes4 selector) so the test fails only if that specific guard stops deployment.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: a6144314-326a-41ba-bced-9d2b763d76b9
📒 Files selected for processing (33)
src/concrete/DecimalFloat.solsrc/error/ErrDecimalFloat.solsrc/lib/deploy/LibDecimalFloatDeploy.soltest/abstract/LogTest.soltest/src/concrete/DecimalFloat.abs.t.soltest/src/concrete/DecimalFloat.add.t.soltest/src/concrete/DecimalFloat.ceil.t.soltest/src/concrete/DecimalFloat.constants.t.soltest/src/concrete/DecimalFloat.constructor.t.soltest/src/concrete/DecimalFloat.div.t.soltest/src/concrete/DecimalFloat.eq.t.soltest/src/concrete/DecimalFloat.floor.t.soltest/src/concrete/DecimalFloat.format.t.soltest/src/concrete/DecimalFloat.frac.t.soltest/src/concrete/DecimalFloat.fromFixedDecimalLossless.t.soltest/src/concrete/DecimalFloat.fromFixedDecimalLossy.t.soltest/src/concrete/DecimalFloat.gt.t.soltest/src/concrete/DecimalFloat.gte.t.soltest/src/concrete/DecimalFloat.integer.t.soltest/src/concrete/DecimalFloat.inv.t.soltest/src/concrete/DecimalFloat.isZero.t.soltest/src/concrete/DecimalFloat.lt.t.soltest/src/concrete/DecimalFloat.lte.t.soltest/src/concrete/DecimalFloat.max.t.soltest/src/concrete/DecimalFloat.min.t.soltest/src/concrete/DecimalFloat.minus.t.soltest/src/concrete/DecimalFloat.mul.t.soltest/src/concrete/DecimalFloat.parse.t.soltest/src/concrete/DecimalFloat.sub.t.soltest/src/concrete/DecimalFloat.toFixedDecimalLossless.t.soltest/src/concrete/DecimalFloat.toFixedDecimalLossy.t.soltest/src/lib/deploy/LibDecimalFloatDeploy.checkLogTablesDeployed.t.soltest/src/lib/deploy/LibDecimalFloatDeploy.t.sol
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Use LibRainDeploy.etchZoltuFactory(vm) to put the Zoltu factory at its canonical address locally, so the determinism tests don't need a real RPC fork. Eliminates CI's RPC retention-window pin maintenance and the flaky CI_FORK_ETH_RPC_URL dependency. Bumps ZOLTU_DEPLOYED_DECIMAL_FLOAT_ADDRESS to 0xc08C2137eD976fCFF68cBFa847e73017EDB8fB47 — the constructor addition in 5f3a4f5 shifted the creation code, which shifts the CREATE2-derived address. The runtime codehash (DECIMAL_FLOAT_CONTRACT_HASH) is unchanged because the constructor doesn't appear in deployed runtime. Each test now sets up only the state it needs: the testDeployAddress case deploys log tables via Zoltu before deploying DecimalFloat to satisfy the constructor's log-tables guard. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The DecimalFloat constructor's log-tables guard reverts under the post-broadcast aggregate simulation because that step does not preserve the per-network fork state where the log tables exist. Per-network broadcast simulations succeed (they fork real chain state). Skipping the aggregate simulation lets the broadcast proceed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/manual-sol-artifacts.yaml:
- Line 38: Split the single forge invocation so simulation remains enabled for
the "log-tables" suite but is skipped only for the "decimal-float" suite: call
the Deploy script twice (targeting script/Deploy.sol:Deploy) — first run for the
"log-tables" suite without the --skip-simulation flag, then run for the
"decimal-float" suite with --skip-simulation; update the workflow step in
manual-sol-artifacts.yaml to use two separate run commands (or otherwise pass a
suite selector to script/Deploy.sol to achieve the same) so only decimal-float
is run with --skip-simulation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1b5d01ae-c6fa-4b3e-aab4-ddc2b30e7dbd
📒 Files selected for processing (3)
.github/workflows/manual-sol-artifacts.yamlsrc/lib/deploy/LibDecimalFloatDeploy.soltest/src/lib/deploy/LibDecimalFloatDeploy.t.sol
Uh oh!
There was an error while loading. Please reload this page.
# Conflicts: # test/src/concrete/DecimalFloat.abs.t.sol # test/src/concrete/DecimalFloat.add.t.sol # test/src/concrete/DecimalFloat.ceil.t.sol # test/src/concrete/DecimalFloat.constants.t.sol # test/src/concrete/DecimalFloat.div.t.sol # test/src/concrete/DecimalFloat.eq.t.sol # test/src/concrete/DecimalFloat.floor.t.sol # test/src/concrete/DecimalFloat.format.t.sol # test/src/concrete/DecimalFloat.frac.t.sol # test/src/concrete/DecimalFloat.fromFixedDecimalLossless.t.sol # test/src/concrete/DecimalFloat.fromFixedDecimalLossy.t.sol # test/src/concrete/DecimalFloat.gt.t.sol # test/src/concrete/DecimalFloat.gte.t.sol # test/src/concrete/DecimalFloat.integer.t.sol # test/src/concrete/DecimalFloat.inv.t.sol # test/src/concrete/DecimalFloat.isZero.t.sol # test/src/concrete/DecimalFloat.lt.t.sol # test/src/concrete/DecimalFloat.lte.t.sol # test/src/concrete/DecimalFloat.max.t.sol # test/src/concrete/DecimalFloat.min.t.sol # test/src/concrete/DecimalFloat.minus.t.sol # test/src/concrete/DecimalFloat.mul.t.sol # test/src/concrete/DecimalFloat.parse.t.sol # test/src/concrete/DecimalFloat.sub.t.sol # test/src/concrete/DecimalFloat.toFixedDecimalLossless.t.sol # test/src/concrete/DecimalFloat.toFixedDecimalLossy.t.sol # test/src/lib/deploy/LibDecimalFloatDeploy.t.sol
- mutation test: assert specific revert (LogTablesNotDeployed) not just "any" - mutation test: check create() returned non-zero before etching - manual-sol-artifacts: scope --skip-simulation to decimal-float suite only (log-tables suite has no cross-deploy dependency, simulation stays on as a safety net) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
@coderabbitai assess this PR size classification for the totality of the PR with the following criterias and report it in your comment: S/M/L PR Classification Guidelines:This guide helps classify merged pull requests by effort and complexity rather than just line count. The goal is to assess the difficulty and scope of changes after they have been completed. Small (S)Characteristics:
Review Effort: Would have taken 5-10 minutes Examples:
Medium (M)Characteristics:
Review Effort: Would have taken 15-30 minutes Examples:
Large (L)Characteristics:
Review Effort: Would have taken 45+ minutes Examples:
Additional Factors to ConsiderWhen deciding between sizes, also consider:
Notes:
|
Tip For best results, initiate chat on the files or code changes. SIZE=L |
Summary
Fixes#189 (audit/H01 — silent numeric corruption in every transcendental call on production).
LibDecimalFloat.LOG_TABLES_ADDRESSwas hardcoded to0x6421E8a23cdEe2E6E579b2cDebc8C2A514843593, but the deployment script deterministically deploys log tables to0xc51a14251b0dcF0ae24A96b7153991378938f5F5(LibDecimalFloatDeploy.ZOLTU_DEPLOYED_LOG_TABLES_ADDRESS).DecimalFloat'spow10/log10/pow/sqrtextcodecopyfrom the wrong address —extcodecopyon an empty address silently copies zeros, so the production contract returns garbage from every transcendental call.What changed
LOG_TABLES_ADDRESSconstant fromsrc/lib/LibDecimalFloat.sol.src/concrete/DecimalFloat.sol, 4 intest/src/concrete/*.t.sol) to useLibDecimalFloatDeploy.ZOLTU_DEPLOYED_LOG_TABLES_ADDRESSdirectly.Single source of truth — no future drift between the lib's table address and the deploy script's expected address.
Breaking change
External integrators that referenced
LibDecimalFloat.LOG_TABLES_ADDRESSmust switch toLibDecimalFloatDeploy.ZOLTU_DEPLOYED_LOG_TABLES_ADDRESS. They were already broken by the bug — calls against the old constant returned zero-table garbage on every prod chain.Deploy required
This change modifies the
DecimalFloatconcrete bytecode (the address loaded into pow10/log10/pow/sqrt changes), so the deterministic deploy address shifts. TriggerManual sol artifactswith suitedecimal-floatafter merging this PR (perCLAUDE.mddeploy flow).Test plan
Lib*andLibDecimalFloatImplementation*) all pass locally.testDeployAddress/testExpectedCodeHashDecimalFloatuntil deploy constants are regenerated post-deploy).DECIMAL_FLOAT_CONTRACT_HASHandZOLTU_DEPLOYED_DECIMAL_FLOAT_ADDRESSinLibDecimalFloatDeploy.sol.🤖 Generated with Claude Code
Summary by CodeRabbit