# imdUSD gas review

## Result and scope

There are small, defensible savings in the collateral-ratio arithmetic and in canonical question-number formatting. Avoiding identical secured-collateral writes also saves on common deposit paths, but regresses changed-term paths and grows the vault; treat it as a workload-dependent candidate, not a blanket recommendation. No production source change is delivered.

**Pinned commit:** `03e8d0c9ed18204a041e48141bbff44b48da226b`. Review date: 2026-10-05. All numbers below are local measurements or explicitly labelled calculations. Passing local tests is not an independent security review or a mainnet readiness certificate.

## Method and limits

Measured the unmodified pinned tree first with `forge build --sizes`, `forge snapshot`, and `forge test --gas-report`, from an archive in `test/scratch/baseline`. Repository tracked files were not edited. The actual configuration is Forge 1.8.3 (cae51ad458f6abb64852b7709eb784352429825d), Solidity 0.8.26, optimizer 200 runs, Cancun, bytecode_hash="none", isolate=true; default fuzz 256 runs, invariant 128 runs/depth 64/fail_on_revert=true. Dependencies and configuration were copied unchanged. No network, RPC, dependency installation, or fork was needed for measurements.

Each patch was applied **independently**, never stacked. Final candidate measurements use `forge build --force --sizes` and a full snapshot plus full gas-report rerun, with fuzz seed `0x42`. Clean rebuilding matters: an initial incremental build refreshed production artifacts but left inherited test artifacts unchanged. Those preliminary candidate results were discarded, their gas-report runs interrupted, and are not used below. An initial root build also encountered the nested scratch tree; all authoritative runs use the separate archived project as their working directory.

Four original fixtures skip without fork endpoints: PermissionlessRelayTest, InHouseTest, ShareCollateralForkTest, SharePriceFeedForkTest. Thus “the full suite still passes” below means all runnable tests at the pinned checkout pass, with those same four skips. It does not claim those live integrations were exercised. Original configuration still contains Sepolia addresses and Intake/asker placeholders: this is a prelaunch optimization review, not a verification of deployed mainnet addresses.

Suite gas aggregates include reverts, fuzz distributions, and invariant traffic. They are not forecasts of typical user transactions. The controlled successful-call fixture deploys ParameterizedVault with a 24-decimal share mock at 7.95 IMD/share, IMD/ETH=0.001 and ETH/USD=2000, zero reserve, and fresh mock feeds. It measures actual last-call gas with `vm.snapshotGasLastCall`, avoiding gasleft subtraction across isolated top-level calls. Share-token internals and oracle calls are mocks, so absolute costs are not a live sIMD quote. Counts/frequencies below are illustrative; no mainnet usage dataset was supplied.

## Baseline

| Contract | Runtime bytes | Creation bytecode bytes |
|---|---:|---:|
| ParameterizedVault | 20,262 | 42,917 |
| CDPVault | 16,665 | 25,930 |
| OracleAsker | 6,497 | 8,021 |
| SwarmRelay | 3,963 | 3,995 |
| Treasury | 12,001 | 12,148 |
| PriceFeed | 7,180 | 9,640 |
| NhiFeed | 7,401 | 10,082 |
| SpotFeed | 7,068 | 9,416 |
| SharePriceFeed | 1,552 | 2,184 |
| UsdPriceFeed | 2,230 | 2,417 |

`forge build --sizes` compiles successfully but **exits 1**: ApplicationConstructionFactory (26,408 runtime bytes) and SelfContainedInvariantFactory (26,275) exceed EIP-170. They are helpers in test/FactoryDeployment.t.sol and test/SelfContainedDeployment.invariant.t.sol, not the production vault. The same pre-existing helper-size failure remains for every candidate; it is not a failed compilation or a passing size check. ParameterizedVault has 4,314 runtime bytes and 6,235 creation-bytecode bytes of reported headroom. Constructor arguments are additional to the table: six static address arguments add 192 bytes, leaving 6,043 bytes below the initcode limit for the ordinary deployment payload. No claim here includes deployer-specific extra wrapping bytes.

Initial full snapshot: **516 passed, 0 failed, 4 skipped**, 58 suites. Initial full gas report: **516 passed, 0 failed, 4 skipped**, 58 suites. The initial runs used the default random seed; their fuzz-dependent aggregate counts are recorded evidence, not guaranteed identical on another default-seed run. All final paired full-suite runs use the fixed seed 0x42.

The following is the unmodified initial `forge test --gas-report` table, including the sample counts. A blank production row is not a zero cost: barkFor and submitAttestation are shown under their directly exercised test subclasses. Successful nested callback cost is measured separately below; the low callback median here is not its stipend usage.

| Contract/artifact | Function | Min | Average | Median | Max | Calls |
|---|---|---:|---:|---:|---:|---:|
| src/CDPVault.sol:CDPVault | bark | 119078 | 120061 | 120455 | 120455 | 7 |
| src/CDPVault.sol:CDPVault | bite | 248306 | 251535 | 253150 | 253150 | 3 |
| src/CDPVault.sol:CDPVault | draw | 72980 | 263473 | 286439 | 287792 | 20 |
| src/CDPVault.sol:CDPVault | lock | 96755 | 109333 | 113797 | 113855 | 19 |
| src/CDPVault.sol:CDPVault | wipe | 222724 | 222724 | 222724 | 222724 | 1 |
| src/OracleAsker.sol:OracleAsker | arm | 43150 | 46137 | 48126 | 48126 | 5 |
| src/OracleAsker.sol:OracleAsker | ask | 24895 | 108356 | 43906 | 233415 | 22 |
| src/OracleAsker.sol:OracleAsker | askPaid | 25525 | 124378 | 114816 | 230534 | 6 |
| src/OracleAsker.sol:OracleAsker | onOracleResult | 27912 | 29030 | 29030 | 30148 | 2 |
| src/ParameterizedVault.sol:ParameterizedVault | bark | 104697 | 163105 | 166394 | 182381 | 26 |
| src/ParameterizedVault.sol:ParameterizedVault | bite | 239305 | 428862 | 458875 | 458875 | 22 |
| src/ParameterizedVault.sol:ParameterizedVault | cash | 27053 | 211437 | 206414 | 389736 | 5834 |
| src/ParameterizedVault.sol:ParameterizedVault | cover | 26831 | 160307 | 165772 | 255801 | 16 |
| src/ParameterizedVault.sol:ParameterizedVault | draw | 48821 | 217865 | 188329 | 339037 | 4590 |
| src/ParameterizedVault.sol:ParameterizedVault | free | 92764 | 148170 | 144939 | 206524 | 3096 |
| src/ParameterizedVault.sol:ParameterizedVault | lock | 97528 | 112330 | 104006 | 181897 | 4762 |
| src/ParameterizedVault.sol:ParameterizedVault | lockIMD | 29882 | 214741 | 248461 | 248568 | 8 |
| src/ParameterizedVault.sol:ParameterizedVault | wipe | 120153 | 151978 | 146614 | 254060 | 3712 |
| src/SwarmRelay.sol:SwarmRelay | relay | 33200 | 70883 | 65097 | 111270 | 6 |
| src/SwarmRelay.sol:SwarmRelay | relayAndBark | 176159 | 176159 | 176159 | 176159 | 2 |
| src/SwarmRelay.sol:SwarmRelay | relayAndBite | 53745 | 250870 | 353999 | 371099 | 5 |
| src/Treasury.sol:Treasury | fundOracle | 23985 | 103825 | 69380 | 189388 | 18 |
| src/Treasury.sol:Treasury | payStream | 34873 | 77498 | 61234 | 170255 | 10 |
| src/Treasury.sol:Treasury | sync | 29684 | 37154 | 29696 | 73898 | 2529 |
| test/QuestionBinding.t.sol:BoundFeed | submitAttestation | 61361 | 94593 | 64506 | 145659 | 11 |
| test/helpers/BaselineVault.sol:BaselineVault | barkFor | 26956 | 73117 | 73117 | 119278 | 2 |

## Controlled successful-call comparisons

Gas units, independent changes. Savings are baseline minus candidate (negative means regression). All calls use ParameterizedVault. `lockDebtFree` is an initial 200-share deposit; `lockWithDebt` adds 10 shares to the same 200-share/$1,000 position, whose secured term is already debt-capped. `lockIMDDebtFree` wraps 1,000 underlying IMD. `draw` opens $1,000 debt; `wipe` repays $100 immediately. Free releases 10 shares with/without $1,000 debt. Liquidation measurements use an IMD price fall to 0.0004 ETH and NHI 0.5, giving zero grace, with a $100 bite. Cash burns $100 from a $1,600 self-funded position with 200 shares, no reserve; these are specified representative branches, not averages of every state.

| Call | Baseline | Saturating after | Saved | Equal-write after | Saved |
|---|---:|---:|---:|---:|---:|
| lockDebtFree | 134,878 | 134,878 | +0 | 134,447 | +431 |
| lockWithDebt | 101,167 | 101,167 | +0 | 100,736 | +431 |
| lockIMDDebtFree | 168,820 | 168,820 | +0 | 168,475 | +345 |
| draw | 336,237 | 335,826 | +411 | 336,283 | -46 |
| wipe | 138,320 | 138,320 | +0 | 138,366 | -46 |
| freeDebtFree | 99,057 | 99,057 | +0 | 98,626 | +431 |
| freeWithDebt | 152,055 | 151,644 | +411 | 151,624 | +431 |
| bark | 159,726 | 159,315 | +411 | 159,726 | +0 |
| barkFor | 160,121 | 159,710 | +411 | 160,121 | +0 |
| bite | 302,267 | 301,445 | +822 | 302,359 | -92 |
| cash | 240,658 | 240,247 | +411 | 240,273 | +385 |

## Ranking by savings times frequency

No empirical frequency is known. The explicit illustrative workload below follows the supplied hot-path order and exposes how to recompute the ranking. It is not a prediction: 800 debt-free locks + 200 capped-position locks, 800 debt-free lockIMD, 600 draws, 500 wipes, 200 debt-free and 200 debt-bearing frees, 100 barks, 50 barkFor, 50 bites, 20 cash, and 100 bound feed updates, each with two eight-digit block numbers. For decimal formatting the measured question-hash delta is used per bound update, not the whole multi-call test-body delta. Callbacks and relays carrying that same update are not double-counted. Untested workload branches contribute no claimed savings.

| Rank | Independent patch | Calculated gas saved for stated workload | Adoption position |
|---|---|---:|---|
| 1 | resecure | +831,900 | Conditional only; reject unconditional rollout without state-mix data |
| 2 | decimal | +509,200 | Recommend; same hashes, smaller bound feeds |
| 3 | saturating | +439,770 | Recommend; exact local bound proof, shrinks vault |

The general rule is sum(N_call × measured_delta_call); multiply total saved gas by the applicable gas price to estimate fees. A ranking can reverse if there are many oracle updates or many secured-term changes. Gas savings of separately tested patches are not guaranteed additive; a combined patch must be rebuilt and measured before adoption.

## Proposals, exact diffs, and security properties

### 1. resecure

**File/function:** src/CDPVault.sol, `_resecure`, reached by collateral and principal changes.

**Change:** condition the two writes on the position term changing. Keep `_advanceLag`, `_clampLag`, and the transient increment in their original places; an early return from this function would be wrong.

**Security property:** aggregate secured collateral equals the sum of stored position terms. In every reachable state, the aggregate includes this position's previous term, so subtracting that term and re-adding the identical value is an identity with no overflow/underflow. Skipping the identical writes preserves state. There is no external call between these operations; the lag checkpoint still uses the old aggregate, clamps still run, and increases still enter the transaction-local exclusion. The arithmetic on changed terms stays checked. This does not narrow fields, alter storage layout, or skip an oracle read. The reasoning depends on the existing aggregate invariant, unlike the unconditional arithmetic identity in the first patch.

**Tradeoff:** ParameterizedVault grows 20,262 → 20,278 runtime bytes and 42,917 → 42,933 creation bytes (**+16 each**). The gas table gives both equal-term savings and changed-term regressions. Reject it as an unconditional default without a measured state mix. For the measured 431-gas equal-term saving and 46-gas changed-term regression, break-even is more than 46/431 = 0.107 equal-term calls per changed-term call (over 9.65% equal-term calls in that two-branch mix), before deployment cost. For other branch pairs, the break-even count ratio is changed-branch extra gas / equal-branch saved gas; include per-path frequencies and the deployment-size cost. In particular a debt-free lock is not representative of all locks.

```diff
--- a/src/CDPVault.sol
+++ b/src/CDPVault.sol
@@ -784,9 +784,9 @@
     function _resecure(Position storage position, uint256 price) private {
         uint256 before = position.secured;
         uint256 current = _secured(position, price);
-        position.secured = current;
+        if (current != before) position.secured = current;
         _advanceLag();
-        securedCollateral = securedCollateral - before + current;
+        if (current != before) securedCollateral = securedCollateral - before + current;
         _clampLag();
         if (current > before) _transientAdd(SECURED_THIS_TX_SLOT, current - before);
     }
```

**Full-suite evidence:** Ran 59 test suites in 163.42s (551.77s CPU time): 523 tests passed, 0 failed, 4 skipped (527 total tests); Ran 59 test suites in 248.42s (809.03s CPU time): 523 tests passed, 0 failed, 4 skipped (527 total tests). The full runnable suite still passes with the original four skips. Seven additional successful-call benchmark tests are included in these final runs.

### 2. decimal

**File/function:** src/SwarmFeed.sol, `_decimal`, used twice by `expectedQuestionHash` inside `_requireQuestion` during bound submitAttestation, including calls through relay, relayAndBark, relayAndBite, and the OracleAsker callback.

**Change:** widen local counters and loop values to uint256; input and all stored/ABI types remain uint64. This reduces narrow-integer cleanup and checked arithmetic overhead in the compiled loop. All arithmetic stays checked.

**Gas:** the same eight-digit production PriceFeed question hash costs **16,690 → 11,598**, saving **5,092 gas**. End-to-end callback measurements follow below. There is no saving for an unbound feed whose questionPolicy prefix is empty. Savings depend on digit count, not the block values' economic meaning.

**Security property:** value remains uint64. Each loop starts from the same value and divides by 10, producing the identical sequence and at most 20 digits. The second loop decrements exactly the count obtained in the first. Each digit is 48+(v%10), in [48,57]; the zero fast path, bytes-array bounds checks, and checked arithmetic remain. Therefore every output byte, canonical question hash, and signed-input acceptance decision is identical. No window, signature, panel, replay, freshness, deviation or relayer check changes, and no external call moves. An independent vm.toString-based reference tests zero, uint64 maximum and 1,024 fuzz pairs over the full uint64 domain with seed 0x43.

**Size:** PriceFeed 7,180 → 7,049 runtime and 9,640 → 9,509 creation; NhiFeed 7,401 → 7,270 and 10,082 → 9,951; SpotFeed 7,068 → 6,937 and 9,416 → 9,285. **131 bytes saved in each bound feed**, runtime and creation. **ParameterizedVault remains 20,262 / 42,917**: it creates wrapper feeds, not these attestation feeds.

```diff
--- a/src/SwarmFeed.sol
+++ b/src/SwarmFeed.sol
@@ -202,10 +202,10 @@
     /// widening it for.
     function _decimal(uint64 value) private pure returns (bytes memory) {
         if (value == 0) return "0";
-        uint64 digits;
-        for (uint64 v = value; v != 0; v /= 10) ++digits;
+        uint256 digits;
+        for (uint256 v = value; v != 0; v /= 10) ++digits;
         bytes memory out = new bytes(digits);
-        for (uint64 v = value; v != 0; v /= 10) out[--digits] = bytes1(uint8(48 + (v % 10)));
+        for (uint256 v = value; v != 0; v /= 10) out[--digits] = bytes1(uint8(48 + (v % 10)));
         return out;
     }
 
```

**Full-suite evidence:** Ran 59 test suites in 220.74s (545.13s CPU time): 523 tests passed, 0 failed, 4 skipped (527 total tests); Ran 59 test suites in 233.57s (816.42s CPU time): 523 tests passed, 0 failed, 4 skipped (527 total tests). The full runnable suite still passes with the original four skips. Seven additional successful-call benchmark tests are included in these final runs.

### 3. saturating

**File/function:** src/CDPVault.sol, `_saturatingAdd`, used by `_collateralRatio` and therefore draw/free/liquidation/recovery/cash health calculations.

**Change:** mark only this already-guarded arithmetic as unchecked; retain the saturating comparison unchanged.

**Proof:** let M=2^256−1. Every uint256 a satisfies 0≤a≤M, so M−a cannot underflow. If b>M−a, the branch returns M without evaluating a+b. Otherwise b≤M−a implies a+b≤M, so that addition cannot overflow. Both branches return exactly the original value for every uint256 pair, including zero and M. No authority, guard, price read, rounding, event, error, nonReentrant modifier, or external call changes. The guard is not removed or weakened. This is the only proposed unchecked block.

**Size:** ParameterizedVault 20,262 → 20,251 runtime bytes and 42,917 → 42,906 creation bytes: **11 bytes saved in each**. Controlled successful-call before/after gas is in the table above; zero-saving paths are shown explicitly. This is a modest arithmetic saving, not a redesign.

```diff
--- a/src/CDPVault.sol
+++ b/src/CDPVault.sol
@@ -1273,6 +1273,8 @@
     }
 
     function _saturatingAdd(uint256 a, uint256 b) private pure returns (uint256) {
-        return b > type(uint256).max - a ? type(uint256).max : a + b;
+        unchecked {
+            return b > type(uint256).max - a ? type(uint256).max : a + b;
+        }
     }
 }
```

**Full-suite evidence:** Ran 59 test suites in 201.30s (538.86s CPU time): 523 tests passed, 0 failed, 4 skipped (527 total tests); Ran 59 test suites in 234.10s (850.35s CPU time): 523 tests passed, 0 failed, 4 skipped (527 total tests). The full runnable suite still passes with the original four skips. Seven additional successful-call benchmark tests are included in these final runs.

## Callback stipend

The original OracleAsker callback test uses ConfigurableSwarmFeed with no pinned question. Its measured value is useful but does **not** establish the cost of the production binding path. Additional tests use the exact production NhiFeed QUESTION_PREFIX and span bounds in a test feed, with a fixture signer, mainnet chain ID 1, toBlock=26,000,600 equal to the current block, and fromBlock=26,000,000. A mock Intake calls the actual OracleAsker → SwarmRelay → bound feed path with exactly 200,000 gas. The tests assert both successful callback completion **and the accepted feed value**, so catching an out-of-gas relay cannot count as a pass. The slot must clear in either case. Seeded-update and first-value paths are measured separately; the seeded fixture begins with lastToBlock zero, making its first advancing-window write conservative relative to an already populated window slot.

Gas recorded by MockIntake includes its call overhead; it is not a refund-adjusted transaction gas price. These tests are finite payload/state fixtures, not a universal bound for arbitrary signature/answer sizes or proof of a deployed Intake implementation.

| Bound NHI callback case | Baseline | Decimal patch | Saved | Remaining from 200,000 after patch |
|---|---:|---:|---:|---:|
| First | 151,534 | 146,442 | 5,092 | 53,558 |
| Update | 118,482 | 113,390 | 5,092 | 86,610 |

**Additional-test exception:** the baseline bound-first callback successfully delivered and updated the feed within the 200,000-gas stipend, but failed the scratch fixture's stricter 150,000-gas headroom assertion (151,534 >= 150,000). The decimal candidate passes both first-value and update cases with that exact same assertion. No test threshold was relaxed. This added diagnostic was run after the original full suites, so it is not concealed by the 523-pass original-suite-plus-benchmark totals. The measured first-value headroom improves from 48,466 to 53,558 gas (about 26.8% of the stipend after the patch).

No change to arm, ask, askPaid, onOracleResult, Treasury.fundOracle/payStream/sync, or relay itself is proposed. These functions do not inherit the vault arithmetic patch; only delivery to a bound feed inherits the decimal savings.

## Measured but rejected, and already-efficient paths

* **Unconditional equal-write rollout:** measured in full, with its exact diff and proof above, but not recommended blindly because changed secured terms pay extra and vault bytecode grows. Keep it only if observed equal-term call savings dominate; the illustrative workload is not that observation.
* **Incremental-build comparisons:** rejected as evidence. After copying cached outputs, production sizes changed while inherited SeedableFeed artifacts did not. Final results use clean rebuilds, and clean decimal builds do shrink SeedableFeed artifacts. Preliminary interrupted gas logs must not be cited as completed runs.
* **Unbound callback as production-cost evidence:** measured by the existing stipend test but rejected as the only basis for a mainnet bound-feed conclusion. The additional tests above exercise the question-prefix/window path. No claim of a decimal saving is made for unbound ConfigurableSwarmFeed deliveries.
* **Gas-neutral simplifications:** none is recommended; the admitted arithmetic candidate saves gas and shrinks the vault, and the formatting candidate saves gas and shrinks feeds. No cosmetic cleanup is counted as a saving.

Static inspection, **not measured optimization claims**: lock's actual received-balance check and lockIMD's received-share measurement/forceApprove cleanup protect collateral accounting and token compatibility. Their calls and order stay intact. Price-dependent paths use raw primary/spot prices for divergence and USD/share-denominated prices for solvency: these are different checks. The repayment recovery path tolerates stale observations without incorrectly clearing a mark. Caching or dropping those reads is not established safe here.

SwarmRelay.relay is already a thin forwarder. Batch-length checks and relayAndBite's balance deltas protect atomicity, donations and custody. No worthwhile safe change to those functions was demonstrated. OracleAsker keeps price caps, in-flight exclusion, cooldown/arming rules, exact allowances and callback catch behavior. Treasury.fundOracle protects both daily spend and excess asker accumulation; payStream protects bad-debt funds; sync correctly counts receipts without treating withdrawals as negative income. Nothing measured justifies weakening any of them.

The vault already uses factories for Treasury/work-oracle creation, immutables for fixed references, and transient exclusion of same-transaction capital. Those are efficient existing choices. Replacing governed reads with constants, removing nonReentrant, changing parameter values, narrowing stored monetary amounts, weakening freshness/divergence checks, or reordering external calls is outside the admissible set and is not proposed.

## Reproduction and audit trail

From a clean checkout of the pinned commit, archive it into a separate scratch directory (do not run Forge at the parent with nested copies under test/). Run the baseline commands first. For each independent candidate create another copy, apply its inline diff, retain foundry.toml/remappings/dependencies byte-for-byte, and run:

```sh
FOUNDRY_FUZZ_SEED=0x42 forge build --force --sizes
FOUNDRY_FUZZ_SEED=0x42 forge snapshot --snap candidate.snap
FOUNDRY_FUZZ_SEED=0x42 forge test --gas-report
forge test --match-contract GasBench -vv
forge test --match-contract GasMoreBench -vv
forge test --match-contract OracleBoundBench -vv
forge test --match-contract GasQuestionBench --fuzz-seed 0x43 --fuzz-runs 1024 -vv
```

The last two fixtures are relevant to baseline/decimal; the extra liquidation fixture is relevant to baseline/saturating/resecure. The scratch-only benchmark sources and orchestration scripts are in artifacts/GasBench.t.sol, GasMoreBench.t.sol, OracleBoundBench.t.sol, GasQuestionBench.t.sol, run-experiments.py, final-measure.py and the run-extra/run-question/run-more scripts. Copy fixture sources into each scratch project's test/ so their relative helper imports resolve. No benchmark is a proposed source change. The complete original suite is always rerun, not merely matched tests. Main result tables are embedded above so this report remains useful if auxiliary evidence files are not separately uploaded.

Local raw evidence: baseline-build.txt, baseline-snapshot.txt, baseline.snap, baseline-gas.txt; {baseline,saturating,resecure,decimal}-final-{build,snapshot,gas,bench,callback}.txt and -final.snap; baseline/saturating/resecure-more.txt; baseline/decimal-bound-callback.txt and -question.txt. Full fixture source and logs permit local replay; figures do not have independent verifier authority.

Solidity's language reference documents [checked versus unchecked arithmetic](https://docs.soliditylang.org/en/v0.8.26/control-structures.html#checked-or-unchecked-arithmetic); it supports the arithmetic proof, not the gas measurements. Protocol behavior and configuration are pinned source facts in src/CDPVault.sol, src/SwarmFeed.sol, src/ParameterizedVault.sol, src/DeploymentConfig.sol, docs/MAINNET-RUNBOOK.md and docs/PARAMETERS-2026-10-05.md. Economic prices in those documents were not refreshed or revalidated; no economic parameter change is justified by this gas review.

Remaining uncertainty: actual user/state frequencies, live sIMD transfer/deposit overhead, live Intake implementation, fork-only coverage, combined-patch compiler effects, and independent security review before adoption. There is no claim that these three local experiments exhaust every possible safe optimization.

## Additional cross-checks

The three candidate trees each preserve 46 protected configuration/dependency files byte-for-byte, and 25 compiled production ABIs compare equal to the baseline. Their only source difference is the inline patch in CDPVault.sol or SwarmFeed.sol. `git diff --exit-code` at the delivered repository root is clean; artifacts remain untracked/ignored and were not added to Git.

These deterministic existing-test snapshots also support the call-path attribution. **These are whole test-body gas totals**, including preparation/signing, not isolated call quotes, and are excluded from the frequency model:

| Existing test | Baseline | Saturating | Decimal |
|---|---:|---:|---:|
| QuestionBindingTest.test_theRightQuestionIsAcceptedFromAnyone | 204,084 | 204,084 | 198,992 |
| RelayBundlingTest.test_aRelayedMarkMovesNoTokens | 285,981 | 285,570 | 285,981 |
| RelayBundlingTest.test_bundlingPaysTheKeeperExactlyWhatADirectCallWould | 1,994,353 | 1,991,065 | 1,994,353 |
| OracleAskerTest.test_deliveryRelaysIntoTheFeedInsideTheIntakeStipend (unbound fixture) | 413,382 | 413,382 | 413,382 |

The direct bound submission and the end-to-end bound callback each improve by 5,092 gas. The unchanged unbound paths demonstrate why a generic relay average must not be used to estimate bound-feed savings.

Second-seed fuzz rerun (`--match-test testFuzz --fuzz-seed 0x43 --fuzz-runs 1024`), baseline: Ran 18 test suites in 8.66s (32.43s CPU time): 40 tests passed, 0 failed, 0 skipped (40 total tests).

Second-seed fuzz rerun (`--match-test testFuzz --fuzz-seed 0x43 --fuzz-runs 1024`), saturating: Ran 17 test suites in 12.04s (43.68s CPU time): 39 tests passed, 0 failed, 0 skipped (39 total tests).

Second-seed fuzz rerun (`--match-test testFuzz --fuzz-seed 0x43 --fuzz-runs 1024`), resecure: Ran 17 test suites in 14.42s (53.53s CPU time): 39 tests passed, 0 failed, 0 skipped (39 total tests).

Second-seed fuzz rerun (`--match-test testFuzz --fuzz-seed 0x43 --fuzz-runs 1024`), decimal: Ran 18 test suites in 8.52s (38.38s CPU time): 40 tests passed, 0 failed, 0 skipped (40 total tests).

## Self-contained benchmark appendix

To reproduce the isolated measurements without separately uploaded supporting files, save the following fixtures under test/ in each scratch copy. The helpers they import already exist at the pinned commit. Run the commands above after applying one inline proposal at a time. The generated bound callback fixture intentionally fails the baseline's additional 150,000-gas assertion; retain that assertion and report the failure, as this review does. The original production suite passes independently.

### GasBench.t.sol

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {Test} from "forge-std/Test.sol";
import {TreasuryFactoryEtch} from "./helpers/TreasuryFactoryEtch.sol";
import {MockIMD} from "src/MockIMD.sol";
import {ParameterizedVault} from "src/ParameterizedVault.sol";
import {TestSwarmFeed} from "./helpers/TestSwarmFeed.sol";
import {MirroredSwarmFeed} from "./helpers/MirroredSwarmFeed.sol";
import {ReserveUsdAggregator} from "./helpers/WorkBackingFixture.sol";
import {MockShareVault} from "./helpers/MockShareVault.sol";
import {APPROVED_OPERATOR, CHAINLINK_ETH_USD} from "src/DeploymentConfig.sol";
contract GasBench is Test {
    MockIMD imd;
    MockShareVault share;
    ParameterizedVault vault;
    address constant USER = address(0xB0B);
    function setUp() public {
        TreasuryFactoryEtch.etch(vm);
        vm.chainId(1);
        vm.warp(1_000_000);
        imd = new MockIMD();
        share = new MockShareVault(imd, 7.95e12);
        TestSwarmFeed primary = new TestSwarmFeed(0.001 ether);
        TestSwarmFeed health = new TestSwarmFeed(0.9 ether);
        vm.etch(CHAINLINK_ETH_USD, address(new ReserveUsdAggregator()).code);
        ReserveUsdAggregator(CHAINLINK_ETH_USD).setDecimals(8);
        ReserveUsdAggregator(CHAINLINK_ETH_USD).set(2_000e8, block.timestamp);
        vault = new ParameterizedVault(address(share), address(0), address(0), address(primary), address(health), address(new MirroredSwarmFeed(address(primary))));
        vm.prank(APPROVED_OPERATOR);
        imd.mint(USER, 20_000 ether);
        vm.startPrank(USER);
        imd.approve(address(share), type(uint256).max);
        share.deposit(10_000 ether, USER);
        share.approve(address(vault), type(uint256).max);
        imd.approve(address(vault), type(uint256).max);
        vm.stopPrank();
    }
    function opened() private {
        vm.startPrank(USER);
        vault.lock(200e24);
        vault.draw(1_000 ether);
        vm.stopPrank();
    }
    function measure(string memory label) private {
        uint256 used = vm.snapshotGasLastCall("GasBench", label);
        emit log_named_uint(label, used);
    }
    function test_lockDebtFree() public { vm.prank(USER); vault.lock(200e24); measure("lockDebtFree"); }
    function test_lockWithDebt() public { opened(); vm.prank(USER); vault.lock(10e24); measure("lockWithDebt"); }
    function test_lockIMDDebtFree() public { vm.prank(USER); vault.lockIMD(1_000 ether); measure("lockIMDDebtFree"); }
    function test_draw() public { vm.startPrank(USER); vault.lock(200e24); vault.draw(1_000 ether); vm.stopPrank(); measure("draw"); }
    function test_wipe() public { opened(); vm.prank(USER); vault.wipe(100 ether); measure("wipe"); }
    function test_freeDebtFree() public { vm.startPrank(USER); vault.lock(200e24); vault.free(10e24); vm.stopPrank(); measure("freeDebtFree"); }
    function test_freeWithDebt() public { opened(); vm.prank(USER); vault.free(10e24); measure("freeWithDebt"); }
}
```

### GasMoreBench.t.sol

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {GasBench} from "./GasBench.t.sol";
import {TestSwarmFeed} from "./helpers/TestSwarmFeed.sol";
contract GasMoreBench is GasBench {
    function distressed() private {
        vm.startPrank(USER);
        vault.lock(200e24);
        vault.draw(1_000 ether);
        vm.stopPrank();
        TestSwarmFeed(address(vault.priceFeed())).setValue(0.0004 ether);
        TestSwarmFeed(address(vault.nhiFeed())).setValue(0.5 ether);
    }
    function test_bark() public { distressed(); vault.bark(USER); emit log_named_uint("bark",vm.snapshotGasLastCall("More","bark")); }
    function test_barkFor() public { distressed(); vault.barkFor(USER,address(this)); emit log_named_uint("barkFor",vm.snapshotGasLastCall("More","barkFor")); }
    function test_bite() public { distressed(); vault.bark(USER); vm.prank(USER); vault.bite(USER,100 ether); emit log_named_uint("bite",vm.snapshotGasLastCall("More","bite")); }
    function test_cash() public {
        vm.startPrank(USER); vault.lock(200e24); vault.draw(1_600 ether); vault.cash(100 ether,0,USER); vm.stopPrank();
        emit log_named_uint("cash",vm.snapshotGasLastCall("More","cash"));
    }
}
```

### GasQuestionBench.t.sol

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {Test} from "forge-std/Test.sol";
import {PriceFeed} from "src/PriceFeed.sol";
contract PrefixFeed is PriceFeed {
    constructor() PriceFeed(3600,2000) {}
    function prefix() external pure returns (bytes memory) { return QUESTION_PREFIX; }
}
contract GasQuestionBench is Test {
    PrefixFeed feed;
    function setUp() public { feed = new PrefixFeed(); }
    function check(uint64 fromBlock,uint64 toBlock) private view {
        bytes32 referenceHash = keccak256(abi.encodePacked(feed.prefix(),vm.toString(uint256(fromBlock)),',"toBlock":',vm.toString(uint256(toBlock)),"}}"));
        assertEq(feed.expectedQuestionHash(fromBlock,toBlock),referenceHash);
    }
    function testFuzz_fullUint64Domain(uint64 fromBlock,uint64 toBlock) public view { check(fromBlock,toBlock); }
    function test_zeroAndMaximum() public view { check(0,type(uint64).max); check(type(uint64).max,0); }
    function test_eightDigitWindowGas() public {
        feed.expectedQuestionHash(26_000_000,26_000_600);
        emit log_named_uint("eightDigitWindow",vm.snapshotGasLastCall("QuestionBench","eightDigitWindow"));
    }
}
```

### make-bound-bench.py

Save this generator under artifacts/ in a scratch checkout, run it there, and copy artifacts/OracleBoundBench.t.sol to test/. It copies the production NHI prefix and the existing test signer/setup; it changes no production constant.

```python
from pathlib import Path
import re
root=Path(__file__).resolve().parent.parent
original=(root/'test/OracleAsker.t.sol').read_text()
def fn(name):
    start=original.index('    function '+name+'(')
    brace=original.index('{',start); depth=1; end=brace+1
    while depth:
        depth += (original[end]=='{')-(original[end]=='}'); end+=1
    return original[start:end]+'\n'
prefix=re.search(r'bytes internal constant QUESTION_PREFIX = (hex"[^"]+");',(root/'src/NhiFeed.sol').read_text()).group(1)
imports=original[:original.index('/// @notice')]
helper='''contract CallbackBoundFeed is ConfigurableSwarmFeed {
    constructor(address a,address r,uint256 c,uint8 t,uint256 age,uint256 dev) ConfigurableSwarmFeed(a,r,c,t,age,dev) {}
    function questionPolicy() internal pure override returns (bytes memory,uint64,uint64) { return (PREFIX,150,1200); }
    bytes private constant PREFIX = '''+prefix+''';
}
'''
state=original[original.index('contract OracleAskerTest'):original.index('    function setUp()')].replace('OracleAskerTest','OracleBoundBench').replace('ConfigurableSwarmFeed','CallbackBoundFeed')
setup=fn('setUp').replace('ConfigurableSwarmFeed','CallbackBoundFeed').replace('vm.chainId(11155111)','vm.chainId(1)').replace('vm.roll(1_000)','vm.roll(26_000_600)').replace('        _setPool(IMD_ETH);','').replace('        healthFeed.seed(0.9 ether);','')
a=fn('_attestation').replace('keccak256("q")','healthFeed.expectedQuestionHash(26_000_000, 26_000_600)').replace('a.fromBlock = 100','a.fromBlock = 26_000_000').replace('a.toBlock = 200','a.toBlock = 26_000_600')
test=fn('test_deliveryRelaysIntoTheFeedInsideTheIntakeStipend').replace('test_deliveryRelaysIntoTheFeedInsideTheIntakeStipend','test_boundFirstCallback')
update=test.replace('test_boundFirstCallback','test_boundUpdateCallback').replace('        vm.warp(', '        healthFeed.seed(0.9 ether);\n        vm.warp(',1)
output=imports+helper+state+setup+test+update+a+fn('_sign').replace('ConfigurableSwarmFeed','CallbackBoundFeed')+'}\n'
(root/'artifacts/OracleBoundBench.t.sol').write_text(output)
```
