Repository navigation
feat(evm): ProofBridgeUtils, one linked library both escrows share, for AdManager's EIP-170 headroom - #54
Merged
Conversation
… for AdManager's EIP-170 headroom AdManager had 135 bytes left under the 24,576-byte limit. The five order helpers both escrows inlined (DecimalScaling.scale / assertInRange / assertMatchesOnChain, OrderHash.checkWidths / digest) now sit behind one `public` library, ProofBridgeUtils, that the escrows DELEGATECALL: AdManager 24,441 → 23,936 (640 spare), OrderPortal 15,102 → 14,912. DecimalScaling and OrderHash stay internal and untouched; the hash, the reverts and the ABI are unchanged. What the compiler changes underneath, handled: - the seven DecimalScaling__* / OrderHash__* errors leave the escrow ABIs (they arrive through the DELEGATECALL), so they are declared again on IEscrow, NonExactDownscale on IAdManager; both error lists are byte-for-byte what they were; - each call is a DELEGATECALL with ABI encoding: AdManager escrow-only unlock 81,259 → 84,439 (ceiling 91,000), OrderPortal full unlock 369,232 → 371,719 (400,000), recordSettled 218,383 → 220,905 (245,000); lockForOrder about 8k more. Ceilings unchanged. - the finalize-clock library idea measured +70 B and is not done; the rule is many call sites x small interface. Deploy CLI: the library is deployed before the escrows and linked into both. The manifest entry `contracts.proofBridgeUtils` is a record, never an input: a reused escrow is reused with the library its own code names, a library counts only if its code equals this build's artifact (allowing solc's own-address stamp) or it answers the probe (vector 0 of order-hash-v2.json through the link, scale, the typed decimals revert), a wrong entry is repaired from the chain, and a fresh copy is probed before anything links it. The probe takes `digest`'s selector from the artifact's methodIdentifiers: solc hashes a library's struct parameter by its declared name, not the ABI's tuple. Tripwire: test/SizeBudget.t.sol fails at 24,200 deployed bytes, 376 before the wall (re-inlining the five calls puts AdManager at 24,523 and the test goes red). Specs on Anvil: the probe refuses another contract at the address, a reused escrow whose library no longer answers is refused with nothing sent, and a wrong manifest entry is repaired. Release bundle list carries ProofBridgeUtils.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
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 |
…nternal libraries, lock refusals through the link; review 54 pass 1 L1: every test that checked hashing or decimals called the internal libraries, so the five-line door the escrows actually run through was tested by nothing (four mutations, suite green). test/ProofBridgeUtils.t.sol pins each door function against DecimalScaling / OrderHash through a real DELEGATECALL (digest over every frozen vector), and three escrow-level tests prove a lock is refused through the link and decodes by the IEscrow re-declaration. Each of the four door mutations now turns at least one test red. Deploy CLI: L4 the probe rethrows anything that is not a revert (an RPC failure or a stripped artifact is its own error, never "does not answer… redeploy the escrow"); L5 the library's runtime code and digest selector are read before the first transaction, so a stripped bundle is refused with nothing sent; L6 the loaders pass literal names and the release scan covers deployedCode / methodIdentifier, so dropping ProofBridgeUtils from the bundle list fails the scan (proven locally); L7 the frozen vector's field order is asserted against the fixture; L8 two escrows linking different libraries is refused, not half-recorded; L9 unused DecimalScaling imports dropped; L10 one verdict per address across the two escrows. Specs for L4 and L5.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this does
AdManager had 135 bytes left under the EVM's 24,576-byte contract-size limit. One more small fix (the contracts#53 fix pass is next) could have stopped it deploying.
The fix is the one Aave and Uniswap use. The five order helpers both escrows carried a copy of (decimal scaling, the width check, the order digest) now live in one deployed contract per chain,
ProofBridgeUtils, that both escrows call into.DecimalScalingandOrderHashare untouched and still internal;ProofBridgeUtilsis a thin public door in front of them.Nothing about an order changes: same hash, same reverts, same ABI, same Soroban side (no mirror needed, the Soroban ad-manager WASM is at about 55% of its cap).
Why one library and not the finalize-clock library discussed earlier
Measured, not guessed. Moving the finalize clock out made AdManager 70 bytes bigger: it needs sixteen inputs read from storage, and encoding them for the call costs more than the code it moves. What pays is many call sites with a small interface. The measurements and the rejected options are in the size hand-off; the docs page in the monorepo PR carries the summary.
Two things the compiler changes underneath, handled
DecimalScaling__*/OrderHash__*on the escrows. They are declared again onIEscrow(andDecimalScaling__NonExactDownscaleonIAdManager, the only escrow that scales). Both error lists are byte for byte what they were, so the relayer and frontend keep decoding them by name.recordSettled218,383 → 220,905 (ceiling 245,000).lockForOrderpays about 8k more (six library calls, one cold). The ceilings are unchanged.Deploy CLI
ProofBridgeUtilsis ownerless, one per chain, deployed before the escrows and linked into both (theAgentPolicyCodecpattern). The manifest records it ascontracts.proofBridgeUtils, and as for the codec that entry is a record, never an input:order-hash-v2.jsonhashes through the link,scale(1e6, 6, 18)is 1e18,assertInRange(31)reverts with the typed error;One quirk worth knowing: solc hashes a library's struct parameter by its declared name (
digest(OrderHash.Order)), not by the tuple the ABI lists, so ethers and cast call adigestselector the library does not have. The escrows are unaffected. The probe reads the selector from the artifact'smethodIdentifiers.Tripwire
test/SizeBudget.t.solfails when a deployed escrow passes 24,200 bytes, 376 before the wall, so the next feature gets a red test with room to measure instead of a red build at the limit.Tests on the door itself (review pass 1)
The first push tested only the internal libraries: every hashing and decimals test called
OrderHash/DecimalScalingdirectly, so the five-line door the escrows actually run through was tested by nothing.test/ProofBridgeUtils.t.solnow pins each door function against the internal library through a real DELEGATECALL (digestover every frozen vector oforder-hash-v2.json), and three escrow-level tests prove a lock is refused through the link and decodes by the errorIEscrowre-declares.Proven to fail
digest→bytes32(0):test_digest_everyVectorThroughTheDoor(and an unlock test, every order now hashes alike).scale→return amount: the threescaledoor tests.assertMatchesOnChain→ no-op: the door test and both escrow guard tests (test_lock_rejects_adDecimalsNotTheTokens,test_createOrder_rejects_orderDecimalsNotTheTokens).checkWidths→ no-op: the door test andtest_createOrder_rejects_amountTooWide.ProofBridgeUtilsfromEVM_ARTIFACTSnow fails the scan (the loaders use literals anddeployedCode/methodIdentifierare scanned).Checks
forge test(non-invariant): 2057 passed.forge fmt --checkclean. Error lists 71 / 52, unchanged.handover-check.sh33/33 on two Anvils.ProofBridgeUtils.Monorepo half
The schema entry, the bundle fetcher list and the docs page are on
feat/escrow-linked-libraryin ProofBridge; its PR follows this one and bumps the submodule pointer. Then contracts#53 rebases onto main so its fixes have room.