diff --git a/onchain/src/OptimizerV3.sol b/onchain/src/OptimizerV3.sol index e7375f9..44705ff 100644 --- a/onchain/src/OptimizerV3.sol +++ b/onchain/src/OptimizerV3.sol @@ -1,19 +1,20 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.19; -import {Optimizer} from "./Optimizer.sol"; -import {IOptimizer, OptimizerInput} from "./IOptimizer.sol"; +import { IOptimizer, OptimizerInput } from "./IOptimizer.sol"; +import { Optimizer } from "./Optimizer.sol"; +import { OptimizerV3Push3Lib } from "./OptimizerV3Push3Lib.sol"; /** * @title OptimizerV3 * @notice UUPS-upgradeable Optimizer whose calculateParams is overridden by - * the Push3 transpiler output. The body below is a verbatim copy of - * OptimizerV3Push3.calculateParams — kept in sync by the deploy pipeline - * (transpile → overwrite this file → compile → upgrade). + * the Push3 transpiler output. Delegates to OptimizerV3Push3Lib — + * the single canonical copy of the transpiler logic — so that future + * transpiler changes require only one edit. * * @dev No new storage slots. Only overrides the pure calculateParams function. * Register-to-output mapping must match OptimizerV3Push3 exactly: - * r40 → ci, r39 → anchorShare, r38 → anchorWidth, r37 → discoveryDepth + * r40 -> ci, r39 -> anchorShare, r38 -> anchorWidth, r37 -> discoveryDepth */ contract OptimizerV3 is Optimizer { function calculateParams(OptimizerInput[8] memory inputs) @@ -22,327 +23,6 @@ contract OptimizerV3 is Optimizer { override returns (uint256 ci, uint256 anchorShare, uint24 anchorWidth, uint256 discoveryDepth) { - // Guard against non-zero shift and negative mantissa. - // shift is reserved for future use; uint256() cast silently wraps negatives. - for (uint256 k; k < 8; k++) { - require(inputs[k].shift == 0, "shift not yet supported"); - require(inputs[k].mantissa >= 0, "negative mantissa"); - } - - // ── BEGIN TRANSPILER OUTPUT (optimizer_v3.push3) ── - // Do NOT edit by hand — regenerate via: npx tsx tools/push3-transpiler/transpile-cli.ts - - uint256 percentagestaked = uint256(uint256(inputs[0].mantissa)); - uint256 taxrate = uint256(uint256(inputs[1].mantissa)); - uint256 staked = uint256(((percentagestaked * 100) / 1000000000000000000)); - - uint256 r37; - uint256 r38; - uint256 r39; - uint256 r40; - - if ((staked > 91)) { - uint256 deltas = uint256((100 - staked)); - uint256 r0; - if ((taxrate <= 206185567010309)) { - r0 = 0; - } else { - uint256 r1; - if ((taxrate <= 412371134020618)) { - r1 = 1; - } else { - uint256 r2; - if ((taxrate <= 618556701030927)) { - r2 = 2; - } else { - uint256 r3; - if ((taxrate <= 1030927835051546)) { - r3 = 3; - } else { - uint256 r4; - if ((taxrate <= 1546391752577319)) { - r4 = 4; - } else { - uint256 r5; - if ((taxrate <= 2164948453608247)) { - r5 = 5; - } else { - uint256 r6; - if ((taxrate <= 2783505154639175)) { - r6 = 6; - } else { - uint256 r7; - if ((taxrate <= 3608247422680412)) { - r7 = 7; - } else { - uint256 r8; - if ((taxrate <= 4639175257731958)) { - r8 = 8; - } else { - uint256 r9; - if ((taxrate <= 5670103092783505)) { - r9 = 9; - } else { - uint256 r10; - if ((taxrate <= 7216494845360824)) { - r10 = 10; - } else { - uint256 r11; - if ((taxrate <= 9278350515463917)) { - r11 = 11; - } else { - uint256 r12; - if ((taxrate <= 11855670103092783)) { - r12 = 12; - } else { - uint256 r13; - if ((taxrate <= 15979381443298969)) { - r13 = 13; - } else { - uint256 r14; - if ((taxrate <= 22164948453608247)) { - r14 = 14; - } else { - uint256 r15; - if ((taxrate <= 29381443298969072)) { - r15 = 15; - } else { - uint256 r16; - if ((taxrate <= 38144329896907216)) { - r16 = 16; - } else { - uint256 r17; - if ((taxrate <= 49484536082474226)) { - r17 = 17; - } else { - uint256 r18; - if ((taxrate <= 63917525773195876)) - { - r18 = 18; - } else { - uint256 r19; - if ( - ( - taxrate - <= 83505154639175257 - ) - ) { - r19 = 19; - } else { - uint256 r20; - if ( - ( - taxrate - <= - 109278350515463917 - ) - ) { - r20 = 20; - } else { - uint256 r21; - if ( - ( - taxrate - <= - 144329896907216494 - ) - ) { - r21 = 21; - } else { - uint256 r22; - if ( - ( - taxrate - <= - 185567010309278350 - ) - ) { - r22 = 22; - } else { - uint256 r23; - if ( - ( - taxrate - <= - 237113402061855670 - ) - ) { - r23 = 23; - } else { - uint256 r24; - if ( - ( - taxrate - <= - 309278350515463917 - ) - ) { - r24 = 24; - } else { - uint256 - r25; - if ( - ( - taxrate - <= - 402061855670103092 - ) - ) { - r25 - = 25; - } else { - uint256 - r26; - if ( - ( - taxrate - <= - 520618556701030927 - ) - ) { - r26 - = - 26; - } - else - { - uint256 - r27; - if ( - ( - taxrate - <= - 680412371134020618 - ) - ) - { - r27 - = - 27; - } - else - { - uint256 - r28; - if ( - ( - taxrate - <= - 886597938144329896 - ) - ) - { - r28 - = - 28; - } - else - { - r28 - = - 29; - } - r27 - = - r28; - } - r26 - = - r27; - } - r25 - = - r26; - } - r24 = - r25; - } - r23 = r24; - } - r22 = r23; - } - r21 = r22; - } - r20 = r21; - } - r19 = r20; - } - r18 = r19; - } - r17 = r18; - } - r16 = r17; - } - r15 = r16; - } - r14 = r15; - } - r13 = r14; - } - r12 = r13; - } - r11 = r12; - } - r10 = r11; - } - r9 = r10; - } - r8 = r9; - } - r7 = r8; - } - r6 = r7; - } - r5 = r6; - } - r4 = r5; - } - r3 = r4; - } - r2 = r3; - } - r1 = r2; - } - r0 = r1; - } - - uint256 dup29 = r0; - uint256 r32; - if ((dup29 >= 14)) { - uint256 dup30 = uint256((dup29 + 1)); - if ((dup30 > 29)) { - r32 = 29; - } else { - r32 = dup30; - } - } else { - r32 = dup29; - } - uint256 effidx = r32; - - if ((((((deltas * deltas) * deltas) * effidx) / 20) < 50)) { - r37 = uint256(1000000000000000000); - r38 = uint256(20); - r39 = uint256(1000000000000000000); - r40 = uint256(0); - } else { - r37 = uint256(300000000000000000); - r38 = uint256(100); - r39 = uint256(300000000000000000); - r40 = uint256(0); - } - } else { - r37 = uint256(300000000000000000); - r38 = uint256(100); - r39 = uint256(300000000000000000); - r40 = uint256(0); - } - - // Register-to-output mapping (matches OptimizerV3Push3 exactly) - ci = uint256(r40); - anchorShare = uint256(r39); - anchorWidth = uint24(r38); - discoveryDepth = uint256(r37); - // ── END TRANSPILER OUTPUT ── + return OptimizerV3Push3Lib.calculateParams(inputs); } } diff --git a/onchain/src/OptimizerV3Push3.sol b/onchain/src/OptimizerV3Push3.sol index a24578f..31bb68a 100644 --- a/onchain/src/OptimizerV3Push3.sol +++ b/onchain/src/OptimizerV3Push3.sol @@ -1,12 +1,15 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.19; -import {IOptimizer, OptimizerInput} from "./IOptimizer.sol"; +import { IOptimizer, OptimizerInput } from "./IOptimizer.sol"; +import { OptimizerV3Push3Lib } from "./OptimizerV3Push3Lib.sol"; /** * @title OptimizerV3Push3 - * @notice Auto-generated from optimizer_v3.push3 via Push3→Solidity transpiler. - * Implements calculateParams with 8 dyadic rational inputs and 4 outputs. + * @notice Standalone contract wrapping the Push3 transpiler output. + * The actual calculation logic lives in OptimizerV3Push3Lib and is + * shared with OptimizerV3 so that transpiler changes require only + * one edit point. */ contract OptimizerV3Push3 is IOptimizer { /** @@ -16,18 +19,16 @@ contract OptimizerV3Push3 is IOptimizer { * This contract is a standalone transpiler output without access to on-chain stake data; * use OptimizerV3 (which inherits Optimizer) for a live deployment with real inputs. */ - function getLiquidityParams() - external - view - returns (uint256 capitalInefficiency, uint256 anchorShare, uint24 anchorWidth, uint256 discoveryDepth) - { + function getLiquidityParams() external view returns (uint256 capitalInefficiency, uint256 anchorShare, uint24 anchorWidth, uint256 discoveryDepth) { OptimizerInput[8] memory inputs; return calculateParams(inputs); } /** * @notice Compute liquidity parameters from 8 dyadic rational inputs. - * @dev capitalInefficiency (ci) is intentionally hardcoded to 0 in both the bear + * @dev Delegates to OptimizerV3Push3Lib.calculateParams — the single + * canonical copy of the transpiler output. + * capitalInefficiency (ci) is intentionally hardcoded to 0 in both the bear * and bull branches of this implementation. CI is a pure risk lever that * controls the VWAP bias applied when placing the floor position: CI=0 means * the floor tracks the raw VWAP with no upward adjustment, which is the @@ -52,242 +53,6 @@ contract OptimizerV3Push3 is IOptimizer { pure returns (uint256 ci, uint256 anchorShare, uint24 anchorWidth, uint256 discoveryDepth) { - // Validate mantissa for percentageStaked - require(inputs[0].mantissa <= 1e18, "mantissa overflow"); - - // Validate that shift is 0 (future-only field, not yet supported) - // and that no mantissa is negative (uint256 cast silently wraps negatives). - for (uint256 k = 0; k < 8; k++) { - require(inputs[k].shift == 0, "shift not yet supported"); - require(inputs[k].mantissa >= 0, "negative mantissa"); - } - - uint256 percentagestaked = uint256(uint256(inputs[0].mantissa)); - uint256 taxrate = uint256(uint256(inputs[1].mantissa)); - uint256 staked = uint256(((percentagestaked * 100) / 1000000000000000000)); - uint256 r37; - uint256 r38; - uint256 r39; - uint256 r40; - if ((staked > 91)) { - uint256 deltas = uint256((100 - staked)); - uint256 r28; - if ((taxrate <= 206185567010309)) { - r28 = uint256(0); - } else { - uint256 r27; - if ((taxrate <= 412371134020618)) { - r27 = uint256(1); - } else { - uint256 r26; - if ((taxrate <= 618556701030927)) { - r26 = uint256(2); - } else { - uint256 r25; - if ((taxrate <= 1030927835051546)) { - r25 = uint256(3); - } else { - uint256 r24; - if ((taxrate <= 1546391752577319)) { - r24 = uint256(4); - } else { - uint256 r23; - if ((taxrate <= 2164948453608247)) { - r23 = uint256(5); - } else { - uint256 r22; - if ((taxrate <= 2783505154639175)) { - r22 = uint256(6); - } else { - uint256 r21; - if ((taxrate <= 3608247422680412)) { - r21 = uint256(7); - } else { - uint256 r20; - if ((taxrate <= 4639175257731958)) { - r20 = uint256(8); - } else { - uint256 r19; - if ((taxrate <= 5670103092783505)) { - r19 = uint256(9); - } else { - uint256 r18; - if ((taxrate <= 7216494845360824)) { - r18 = uint256(10); - } else { - uint256 r17; - if ((taxrate <= 9278350515463917)) { - r17 = uint256(11); - } else { - uint256 r16; - if ((taxrate <= 11855670103092783)) { - r16 = uint256(12); - } else { - uint256 r15; - if ((taxrate <= 15979381443298969)) { - r15 = uint256(13); - } else { - uint256 r14; - if ((taxrate <= 22164948453608247)) { - r14 = uint256(14); - } else { - uint256 r13; - if ((taxrate <= 29381443298969072)) { - r13 = uint256(15); - } else { - uint256 r12; - if ((taxrate <= 38144329896907216)) { - r12 = uint256(16); - } else { - uint256 r11; - if ((taxrate <= 49484536082474226)) { - r11 = uint256(17); - } else { - uint256 r10; - if ((taxrate <= 63917525773195876)) { - r10 = uint256(18); - } else { - uint256 r9; - if ((taxrate <= 83505154639175257)) { - r9 = uint256(19); - } else { - uint256 r8; - if ((taxrate <= 109278350515463917)) { - r8 = uint256(20); - } else { - uint256 r7; - if ((taxrate <= 144329896907216494)) { - r7 = uint256(21); - } else { - uint256 r6; - if ((taxrate <= 185567010309278350)) { - r6 = uint256(22); - } else { - uint256 r5; - if ((taxrate <= 237113402061855670)) { - r5 = uint256(23); - } else { - uint256 r4; - if ((taxrate <= 309278350515463917)) { - r4 = uint256(24); - } else { - uint256 r3; - if ((taxrate <= 402061855670103092)) { - r3 = uint256(25); - } else { - uint256 r2; - if ((taxrate <= 520618556701030927)) { - r2 = uint256(26); - } else { - uint256 r1; - if ((taxrate <= 680412371134020618)) { - r1 = uint256(27); - } else { - uint256 r0; - if ((taxrate <= 886597938144329896)) { - r0 = uint256(28); - } else { - r0 = uint256(29); - } - r1 = uint256(r0); - } - r2 = uint256(r1); - } - r3 = uint256(r2); - } - r4 = uint256(r3); - } - r5 = uint256(r4); - } - r6 = uint256(r5); - } - r7 = uint256(r6); - } - r8 = uint256(r7); - } - r9 = uint256(r8); - } - r10 = uint256(r9); - } - r11 = uint256(r10); - } - r12 = uint256(r11); - } - r13 = uint256(r12); - } - r14 = uint256(r13); - } - r15 = uint256(r14); - } - r16 = uint256(r15); - } - r17 = uint256(r16); - } - r18 = uint256(r17); - } - r19 = uint256(r18); - } - r20 = uint256(r19); - } - r21 = uint256(r20); - } - r22 = uint256(r21); - } - r23 = uint256(r22); - } - r24 = uint256(r23); - } - r25 = uint256(r24); - } - r26 = uint256(r25); - } - r27 = uint256(r26); - } - r28 = uint256(r27); - } - uint256 dup29 = uint256(r28); - uint256 r32; - if ((dup29 >= 14)) { - uint256 dup30 = uint256((dup29 + 1)); - uint256 r31; - if ((dup30 > 29)) { - r31 = uint256(29); - } else { - r31 = uint256(dup30); - } - r32 = uint256(r31); - } else { - r32 = uint256(dup29); - } - uint256 effidx = uint256(r32); - uint256 r33; - uint256 r34; - uint256 r35; - uint256 r36; - if ((((((deltas * deltas) * deltas) * effidx) / 20) < 50)) { - r33 = uint256(1000000000000000000); - r34 = uint256(20); - r35 = uint256(1000000000000000000); - r36 = uint256(0); - } else { - r33 = uint256(300000000000000000); - r34 = uint256(100); - r35 = uint256(300000000000000000); - r36 = uint256(0); - } - r37 = uint256(r33); - r38 = uint256(r34); - r39 = uint256(r35); - r40 = uint256(r36); - } else { - r37 = uint256(300000000000000000); - r38 = uint256(100); - r39 = uint256(300000000000000000); - r40 = uint256(0); - } - ci = uint256(r40); - anchorShare = uint256(r39); - anchorWidth = uint24(r38); - discoveryDepth = uint256(r37); + return OptimizerV3Push3Lib.calculateParams(inputs); } } diff --git a/onchain/src/OptimizerV3Push3Lib.sol b/onchain/src/OptimizerV3Push3Lib.sol new file mode 100644 index 0000000..da3774b --- /dev/null +++ b/onchain/src/OptimizerV3Push3Lib.sol @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.19; + +import { OptimizerInput } from "./IOptimizer.sol"; + +/** + * @title OptimizerV3Push3Lib + * @notice Shared library containing the canonical Push3 transpiler output for + * OptimizerV3 parameter calculation. Used by both OptimizerV3Push3 + * (standalone) and OptimizerV3 (UUPS-upgradeable Optimizer) so that + * future transpiler changes require only one edit. + * @dev Regenerate via: npx tsx tools/push3-transpiler/transpile-cli.ts + */ +library OptimizerV3Push3Lib { + function calculateParams(OptimizerInput[8] memory inputs) + internal + pure + returns (uint256 ci, uint256 anchorShare, uint24 anchorWidth, uint256 discoveryDepth) + { + // Validate mantissa for percentageStaked + require(inputs[0].mantissa <= 1e18, "mantissa overflow"); + + // Validate that shift is 0 (future-only field, not yet supported) + // and that no mantissa is negative (uint256 cast silently wraps negatives). + for (uint256 k = 0; k < 8; k++) { + require(inputs[k].shift == 0, "shift not yet supported"); + require(inputs[k].mantissa >= 0, "negative mantissa"); + } + + uint256 percentagestaked = uint256(uint256(inputs[0].mantissa)); + uint256 taxrate = uint256(uint256(inputs[1].mantissa)); + uint256 staked = uint256(((percentagestaked * 100) / 1_000_000_000_000_000_000)); + uint256 r37; + uint256 r38; + uint256 r39; + uint256 r40; + if ((staked > 91)) { + uint256 deltas = uint256((100 - staked)); + uint256 r28; + if ((taxrate <= 206_185_567_010_309)) { + r28 = uint256(0); + } else { + uint256 r27; + if ((taxrate <= 412_371_134_020_618)) { + r27 = uint256(1); + } else { + uint256 r26; + if ((taxrate <= 618_556_701_030_927)) { + r26 = uint256(2); + } else { + uint256 r25; + if ((taxrate <= 1_030_927_835_051_546)) { + r25 = uint256(3); + } else { + uint256 r24; + if ((taxrate <= 1_546_391_752_577_319)) { + r24 = uint256(4); + } else { + uint256 r23; + if ((taxrate <= 2_164_948_453_608_247)) { + r23 = uint256(5); + } else { + uint256 r22; + if ((taxrate <= 2_783_505_154_639_175)) { + r22 = uint256(6); + } else { + uint256 r21; + if ((taxrate <= 3_608_247_422_680_412)) { + r21 = uint256(7); + } else { + uint256 r20; + if ((taxrate <= 4_639_175_257_731_958)) { + r20 = uint256(8); + } else { + uint256 r19; + if ((taxrate <= 5_670_103_092_783_505)) { + r19 = uint256(9); + } else { + uint256 r18; + if ((taxrate <= 7_216_494_845_360_824)) { + r18 = uint256(10); + } else { + uint256 r17; + if ((taxrate <= 9_278_350_515_463_917)) { + r17 = uint256(11); + } else { + uint256 r16; + if ((taxrate <= 11_855_670_103_092_783)) { + r16 = uint256(12); + } else { + uint256 r15; + if ((taxrate <= 15_979_381_443_298_969)) { + r15 = uint256(13); + } else { + uint256 r14; + if ((taxrate <= 22_164_948_453_608_247)) { + r14 = uint256(14); + } else { + uint256 r13; + if ((taxrate <= 29_381_443_298_969_072)) { + r13 = uint256(15); + } else { + uint256 r12; + if ((taxrate <= 38_144_329_896_907_216)) { + r12 = uint256(16); + } else { + uint256 r11; + if ((taxrate <= 49_484_536_082_474_226)) { + r11 = uint256(17); + } else { + uint256 r10; + if ((taxrate <= 63_917_525_773_195_876)) { + r10 = uint256(18); + } else { + uint256 r9; + if ((taxrate <= 83_505_154_639_175_257)) { + r9 = uint256(19); + } else { + uint256 r8; + if ((taxrate <= 109_278_350_515_463_917)) { + r8 = uint256(20); + } else { + uint256 r7; + if ((taxrate <= 144_329_896_907_216_494)) { + r7 = uint256(21); + } else { + uint256 r6; + if ((taxrate <= 185_567_010_309_278_350)) { + r6 = uint256(22); + } else { + uint256 r5; + if ((taxrate <= 237_113_402_061_855_670)) { + r5 = uint256(23); + } else { + uint256 r4; + if ((taxrate <= 309_278_350_515_463_917)) { + r4 = uint256(24); + } else { + uint256 r3; + if ((taxrate <= 402_061_855_670_103_092)) { + r3 = uint256(25); + } else { + uint256 r2; + if ((taxrate <= 520_618_556_701_030_927)) { + r2 = uint256(26); + } else { + uint256 r1; + if ( + (taxrate <= 680_412_371_134_020_618) + ) { + r1 = uint256(27); + } else { + uint256 r0; + if ( + ( + taxrate + <= 886_597_938_144_329_896 + ) + ) { + r0 = uint256(28); + } else { + r0 = uint256(29); + } + r1 = uint256(r0); + } + r2 = uint256(r1); + } + r3 = uint256(r2); + } + r4 = uint256(r3); + } + r5 = uint256(r4); + } + r6 = uint256(r5); + } + r7 = uint256(r6); + } + r8 = uint256(r7); + } + r9 = uint256(r8); + } + r10 = uint256(r9); + } + r11 = uint256(r10); + } + r12 = uint256(r11); + } + r13 = uint256(r12); + } + r14 = uint256(r13); + } + r15 = uint256(r14); + } + r16 = uint256(r15); + } + r17 = uint256(r16); + } + r18 = uint256(r17); + } + r19 = uint256(r18); + } + r20 = uint256(r19); + } + r21 = uint256(r20); + } + r22 = uint256(r21); + } + r23 = uint256(r22); + } + r24 = uint256(r23); + } + r25 = uint256(r24); + } + r26 = uint256(r25); + } + r27 = uint256(r26); + } + r28 = uint256(r27); + } + uint256 dup29 = uint256(r28); + uint256 r32; + if ((dup29 >= 14)) { + uint256 dup30 = uint256((dup29 + 1)); + uint256 r31; + if ((dup30 > 29)) { + r31 = uint256(29); + } else { + r31 = uint256(dup30); + } + r32 = uint256(r31); + } else { + r32 = uint256(dup29); + } + uint256 effidx = uint256(r32); + uint256 r33; + uint256 r34; + uint256 r35; + uint256 r36; + if ((((((deltas * deltas) * deltas) * effidx) / 20) < 50)) { + r33 = uint256(1_000_000_000_000_000_000); + r34 = uint256(20); + r35 = uint256(1_000_000_000_000_000_000); + r36 = uint256(0); + } else { + r33 = uint256(300_000_000_000_000_000); + r34 = uint256(100); + r35 = uint256(300_000_000_000_000_000); + r36 = uint256(0); + } + r37 = uint256(r33); + r38 = uint256(r34); + r39 = uint256(r35); + r40 = uint256(r36); + } else { + r37 = uint256(300_000_000_000_000_000); + r38 = uint256(100); + r39 = uint256(300_000_000_000_000_000); + r40 = uint256(0); + } + ci = uint256(r40); + anchorShare = uint256(r39); + anchorWidth = uint24(r38); + discoveryDepth = uint256(r37); + } +}