fix: Push3 optimizer: dyadic rational input interface (8 slots) + 4-output redesign (#548)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c3792b2a63
commit
5d204e5649
5 changed files with 409 additions and 229 deletions
|
|
@ -31,25 +31,13 @@ contract OptimizerV3Push3 {
|
|||
require(inputs[k].shift == 0, "shift not yet supported");
|
||||
}
|
||||
|
||||
// Decode dyadic rational inputs (mantissa * 2^(-shift); shift=0 for current inputs)
|
||||
uint256 _d0 = uint256(inputs[0].mantissa);
|
||||
uint256 _d1 = uint256(inputs[1].mantissa);
|
||||
/* _d2 = uint256(inputs[2].mantissa); */
|
||||
// Available but not used in current implementation
|
||||
/* _d3 = uint256(inputs[3].mantissa); */
|
||||
// Available but not used in current implementation
|
||||
/* _d4 = uint256(inputs[4].mantissa); */
|
||||
// Available but not used in current implementation
|
||||
/* _d5 = uint256(inputs[5].mantissa); */
|
||||
// Available but not used in current implementation
|
||||
/* _d6 = uint256(inputs[6].mantissa); */
|
||||
// Available but not used in current implementation
|
||||
/* _d7 = uint256(inputs[7].mantissa); */
|
||||
// Available but not used in current implementation
|
||||
uint256 rawpct = uint256(_d0);
|
||||
uint256 taxrate = uint256(_d1);
|
||||
uint256 staked = uint256(((rawpct * 100) / 1000000000000000000));
|
||||
bool b33;
|
||||
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;
|
||||
|
|
@ -125,172 +113,60 @@ contract OptimizerV3Push3 {
|
|||
r11 = uint256(17);
|
||||
} else {
|
||||
uint256 r10;
|
||||
if ((taxrate <= 63917525773195876))
|
||||
{
|
||||
if ((taxrate <= 63917525773195876)) {
|
||||
r10 = uint256(18);
|
||||
} else {
|
||||
uint256 r9;
|
||||
if (
|
||||
(
|
||||
taxrate
|
||||
<= 83505154639175257
|
||||
)
|
||||
) {
|
||||
if ((taxrate <= 83505154639175257)) {
|
||||
r9 = uint256(19);
|
||||
} else {
|
||||
uint256 r8;
|
||||
if (
|
||||
(
|
||||
taxrate
|
||||
<=
|
||||
109278350515463917
|
||||
)
|
||||
) {
|
||||
if ((taxrate <= 109278350515463917)) {
|
||||
r8 = uint256(20);
|
||||
} else {
|
||||
uint256 r7;
|
||||
if (
|
||||
(
|
||||
taxrate
|
||||
<=
|
||||
144329896907216494
|
||||
)
|
||||
) {
|
||||
if ((taxrate <= 144329896907216494)) {
|
||||
r7 = uint256(21);
|
||||
} else {
|
||||
uint256 r6;
|
||||
if (
|
||||
(
|
||||
taxrate
|
||||
<=
|
||||
185567010309278350
|
||||
)
|
||||
) {
|
||||
if ((taxrate <= 185567010309278350)) {
|
||||
r6 = uint256(22);
|
||||
} else {
|
||||
uint256 r5;
|
||||
if (
|
||||
(
|
||||
taxrate
|
||||
<=
|
||||
237113402061855670
|
||||
)
|
||||
) {
|
||||
r5 = uint256(
|
||||
23
|
||||
);
|
||||
if ((taxrate <= 237113402061855670)) {
|
||||
r5 = uint256(23);
|
||||
} else {
|
||||
uint256 r4;
|
||||
if (
|
||||
(
|
||||
taxrate
|
||||
<=
|
||||
309278350515463917
|
||||
)
|
||||
) {
|
||||
r4 =
|
||||
uint256(
|
||||
24
|
||||
);
|
||||
if ((taxrate <= 309278350515463917)) {
|
||||
r4 = uint256(24);
|
||||
} else {
|
||||
uint256
|
||||
r3;
|
||||
if (
|
||||
(
|
||||
taxrate
|
||||
<=
|
||||
402061855670103092
|
||||
)
|
||||
) {
|
||||
r3 =
|
||||
uint256(
|
||||
25
|
||||
);
|
||||
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
|
||||
);
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
r0
|
||||
=
|
||||
uint256(
|
||||
29
|
||||
);
|
||||
}
|
||||
r1
|
||||
=
|
||||
uint256(
|
||||
r0
|
||||
);
|
||||
r1 = uint256(r0);
|
||||
}
|
||||
r2
|
||||
=
|
||||
uint256(
|
||||
r1
|
||||
);
|
||||
r2 = uint256(r1);
|
||||
}
|
||||
r3 =
|
||||
uint256(
|
||||
r2
|
||||
);
|
||||
r3 = uint256(r2);
|
||||
}
|
||||
r4 =
|
||||
uint256(
|
||||
r3
|
||||
);
|
||||
r4 = uint256(r3);
|
||||
}
|
||||
r5 = uint256(
|
||||
r4
|
||||
);
|
||||
r5 = uint256(r4);
|
||||
}
|
||||
r6 = uint256(r5);
|
||||
}
|
||||
|
|
@ -353,28 +229,34 @@ contract OptimizerV3Push3 {
|
|||
r32 = uint256(dup29);
|
||||
}
|
||||
uint256 effidx = uint256(r32);
|
||||
b33 = (((((deltas * deltas) * deltas) * effidx) / 20) < 50);
|
||||
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 {
|
||||
b33 = false;
|
||||
r37 = uint256(300000000000000000);
|
||||
r38 = uint256(100);
|
||||
r39 = uint256(300000000000000000);
|
||||
r40 = uint256(0);
|
||||
}
|
||||
uint256 r34;
|
||||
uint256 r35;
|
||||
uint256 r36;
|
||||
uint256 r37;
|
||||
if (b33) {
|
||||
r34 = uint256(1000000000000000000);
|
||||
r35 = uint256(20);
|
||||
r36 = uint256(1000000000000000000);
|
||||
r37 = uint256(0);
|
||||
} else {
|
||||
r34 = uint256(300000000000000000);
|
||||
r35 = uint256(100);
|
||||
r36 = uint256(300000000000000000);
|
||||
r37 = uint256(0);
|
||||
}
|
||||
ci = uint256(r37);
|
||||
anchorShare = uint256(r36);
|
||||
anchorWidth = uint24(r35);
|
||||
discoveryDepth = uint256(r34);
|
||||
ci = uint256(r40);
|
||||
anchorShare = uint256(r39);
|
||||
anchorWidth = uint24(r38);
|
||||
discoveryDepth = uint256(r37);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
222
tools/push3-transpiler/optimizer_seed.push3
Normal file
222
tools/push3-transpiler/optimizer_seed.push3
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
;; optimizer_seed.push3 — initial seed for Push3 evolution (#544, #545, #546)
|
||||
;;
|
||||
;; This is the starting population member for the evolutionary optimizer.
|
||||
;; It implements the same binary bear/bull logic as optimizer_v3.push3 and
|
||||
;; uses all 8 input slots of the dyadic rational interface (slots 2-7 reserved
|
||||
;; for future trackers; currently passed as 0 and discarded here).
|
||||
;;
|
||||
;; Inputs on DYADIC stack (slot 0 on top, slot 7 at bottom):
|
||||
;; [0] percentageStaked (0 to 1e18, where 1e18 = 100%)
|
||||
;; [1] averageTaxRate (0 to 1e18, normalized from Stake contract)
|
||||
;; [2] vwapX96 (future; 0 if unavailable)
|
||||
;; [3] currentTick (future; 0 if unavailable)
|
||||
;; [4] recentVolume (future; 0 if unavailable)
|
||||
;; [5] timeSinceLastRecenter (future; 0 if unavailable)
|
||||
;; [6] movingAveragePrice (future; 0 if unavailable)
|
||||
;; [7] reserved 0
|
||||
;;
|
||||
;; Outputs on DYADIC stack at termination (top to bottom):
|
||||
;; top: capitalInefficiency (0..1e18)
|
||||
;; anchorShare (0..1e18)
|
||||
;; anchorWidth (tick units)
|
||||
;; bot: discoveryDepth (0..1e18)
|
||||
;;
|
||||
;; BULL params: CI=0, AS=1e18, AW=20, DD=1e18
|
||||
;; BEAR params: CI=0, AS=0.3e18, AW=100, DD=0.3e18
|
||||
|
||||
(
|
||||
;; Step 1: Bind slot 0 (top) to PERCENTAGESTAKED, slot 1 to TAXRATE.
|
||||
PERCENTAGESTAKED DYADIC.DEFINE
|
||||
TAXRATE DYADIC.DEFINE
|
||||
|
||||
;; Step 2: Discard unused inputs (slots 2-7) — 6 pops.
|
||||
DYADIC.POP
|
||||
DYADIC.POP
|
||||
DYADIC.POP
|
||||
DYADIC.POP
|
||||
DYADIC.POP
|
||||
DYADIC.POP
|
||||
|
||||
;; Step 3: Compute stakedPct = percentageStaked * 100 / 1e18 (integer 0..100)
|
||||
PERCENTAGESTAKED
|
||||
100 DYADIC.*
|
||||
1000000000000000000 DYADIC./
|
||||
STAKED DYADIC.DEFINE
|
||||
|
||||
;; Step 4: Main conditional — stakedPct > 91?
|
||||
STAKED 91 DYADIC.>
|
||||
|
||||
EXEC.IF
|
||||
|
||||
;; TRUE branch: stakedPct > 91 — compute penalty
|
||||
(
|
||||
;; deltaS = 100 - stakedPct
|
||||
100 STAKED DYADIC.-
|
||||
DELTAS DYADIC.DEFINE
|
||||
|
||||
;; Compute raw tax index via 30-way threshold lookup.
|
||||
TAXRATE 206185567010309 DYADIC.<=
|
||||
EXEC.IF
|
||||
0
|
||||
( TAXRATE 412371134020618 DYADIC.<=
|
||||
EXEC.IF
|
||||
1
|
||||
( TAXRATE 618556701030927 DYADIC.<=
|
||||
EXEC.IF
|
||||
2
|
||||
( TAXRATE 1030927835051546 DYADIC.<=
|
||||
EXEC.IF
|
||||
3
|
||||
( TAXRATE 1546391752577319 DYADIC.<=
|
||||
EXEC.IF
|
||||
4
|
||||
( TAXRATE 2164948453608247 DYADIC.<=
|
||||
EXEC.IF
|
||||
5
|
||||
( TAXRATE 2783505154639175 DYADIC.<=
|
||||
EXEC.IF
|
||||
6
|
||||
( TAXRATE 3608247422680412 DYADIC.<=
|
||||
EXEC.IF
|
||||
7
|
||||
( TAXRATE 4639175257731958 DYADIC.<=
|
||||
EXEC.IF
|
||||
8
|
||||
( TAXRATE 5670103092783505 DYADIC.<=
|
||||
EXEC.IF
|
||||
9
|
||||
( TAXRATE 7216494845360824 DYADIC.<=
|
||||
EXEC.IF
|
||||
10
|
||||
( TAXRATE 9278350515463917 DYADIC.<=
|
||||
EXEC.IF
|
||||
11
|
||||
( TAXRATE 11855670103092783 DYADIC.<=
|
||||
EXEC.IF
|
||||
12
|
||||
( TAXRATE 15979381443298969 DYADIC.<=
|
||||
EXEC.IF
|
||||
13
|
||||
( TAXRATE 22164948453608247 DYADIC.<=
|
||||
EXEC.IF
|
||||
14
|
||||
( TAXRATE 29381443298969072 DYADIC.<=
|
||||
EXEC.IF
|
||||
15
|
||||
( TAXRATE 38144329896907216 DYADIC.<=
|
||||
EXEC.IF
|
||||
16
|
||||
( TAXRATE 49484536082474226 DYADIC.<=
|
||||
EXEC.IF
|
||||
17
|
||||
( TAXRATE 63917525773195876 DYADIC.<=
|
||||
EXEC.IF
|
||||
18
|
||||
( TAXRATE 83505154639175257 DYADIC.<=
|
||||
EXEC.IF
|
||||
19
|
||||
( TAXRATE 109278350515463917 DYADIC.<=
|
||||
EXEC.IF
|
||||
20
|
||||
( TAXRATE 144329896907216494 DYADIC.<=
|
||||
EXEC.IF
|
||||
21
|
||||
( TAXRATE 185567010309278350 DYADIC.<=
|
||||
EXEC.IF
|
||||
22
|
||||
( TAXRATE 237113402061855670 DYADIC.<=
|
||||
EXEC.IF
|
||||
23
|
||||
( TAXRATE 309278350515463917 DYADIC.<=
|
||||
EXEC.IF
|
||||
24
|
||||
( TAXRATE 402061855670103092 DYADIC.<=
|
||||
EXEC.IF
|
||||
25
|
||||
( TAXRATE 520618556701030927 DYADIC.<=
|
||||
EXEC.IF
|
||||
26
|
||||
( TAXRATE 680412371134020618 DYADIC.<=
|
||||
EXEC.IF
|
||||
27
|
||||
( TAXRATE 886597938144329896 DYADIC.<=
|
||||
EXEC.IF
|
||||
28
|
||||
29
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; Apply effIdx shift: if raw_idx >= 14, effIdx = min(raw_idx + 1, 29)
|
||||
DYADIC.DUP 14 DYADIC.>=
|
||||
EXEC.IF
|
||||
(
|
||||
1 DYADIC.+
|
||||
DYADIC.DUP 29 DYADIC.>
|
||||
EXEC.IF
|
||||
( DYADIC.POP 29 )
|
||||
( )
|
||||
)
|
||||
( )
|
||||
|
||||
EFFIDX DYADIC.DEFINE
|
||||
|
||||
;; penalty = deltaS^3 * effIdx / 20
|
||||
DELTAS DELTAS DYADIC.*
|
||||
DELTAS DYADIC.*
|
||||
EFFIDX DYADIC.*
|
||||
20 DYADIC./
|
||||
|
||||
;; penalty < 50 → BULL; else → BEAR
|
||||
50 DYADIC.<
|
||||
|
||||
EXEC.IF
|
||||
;; BULL: push 4 outputs bottom-first (discoveryDepth at bottom, ci at top)
|
||||
(
|
||||
1000000000000000000
|
||||
20
|
||||
1000000000000000000
|
||||
0
|
||||
)
|
||||
;; BEAR
|
||||
(
|
||||
300000000000000000
|
||||
100
|
||||
300000000000000000
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
;; FALSE branch: stakedPct <= 91 — always bear
|
||||
(
|
||||
300000000000000000
|
||||
100
|
||||
300000000000000000
|
||||
0
|
||||
)
|
||||
)
|
||||
|
|
@ -1,38 +1,57 @@
|
|||
;; OptimizerV3 in Push3
|
||||
;; OptimizerV3 in Push3 — 8-input / 4-output redesign
|
||||
;;
|
||||
;; Computes isBullMarket(percentageStaked_1e18, averageTaxRate_1e18)
|
||||
;; Inputs on DYADIC stack (slot 0 on top, slot 7 at bottom):
|
||||
;; [0] percentageStaked (0 to 1e18, where 1e18 = 100%)
|
||||
;; [1] averageTaxRate (0 to 1e18, normalized from Stake contract)
|
||||
;; [2] vwapX96 (future; 0 if unavailable)
|
||||
;; [3] currentTick (future; 0 if unavailable)
|
||||
;; [4] recentVolume (future; 0 if unavailable)
|
||||
;; [5] timeSinceLastRecenter (future; 0 if unavailable)
|
||||
;; [6] movingAveragePrice (future; 0 if unavailable)
|
||||
;; [7] reserved 0
|
||||
;;
|
||||
;; Inputs on DYADIC stack (top to bottom when called):
|
||||
;; top: percentageStaked (0 to 1e18, where 1e18 = 100%)
|
||||
;; below: averageTaxRate (0 to 1e18, normalized from Stake contract)
|
||||
;; Outputs on DYADIC stack at termination (top to bottom):
|
||||
;; top: capitalInefficiency (0..1e18)
|
||||
;; anchorShare (0..1e18)
|
||||
;; anchorWidth (tick units)
|
||||
;; bot: discoveryDepth (0..1e18)
|
||||
;;
|
||||
;; Output on BOOLEAN stack:
|
||||
;; top: TRUE if bull market, FALSE if bear market
|
||||
;;
|
||||
;; Logic mirrors OptimizerV3.isBullMarket:
|
||||
;; Logic: binary bear/bull from slots 0 and 1
|
||||
;; stakedPct = percentageStaked * 100 / 1e18 (0-100)
|
||||
;; if stakedPct <= 91 → FALSE (always bear)
|
||||
;; if stakedPct <= 91 → BEAR
|
||||
;; deltaS = 100 - stakedPct
|
||||
;; effIdx = _taxRateToEffectiveIndex(averageTaxRate) (0-29, with +1 shift at >=14)
|
||||
;; penalty = deltaS^3 * effIdx / 20
|
||||
;; return penalty < 50
|
||||
;; if penalty < 50 → BULL, else → BEAR
|
||||
;;
|
||||
;; BULL params: CI=0, AS=1e18, AW=20, DD=1e18
|
||||
;; BEAR params: CI=0, AS=0.3e18, AW=100, DD=0.3e18
|
||||
|
||||
(
|
||||
;; Step 1: Bind inputs to names.
|
||||
;; Stack on entry: [percentageStaked_1e18 (top), averageTaxRate_1e18 (below)]
|
||||
DYADIC.SWAP
|
||||
;; Stack: [averageTaxRate_1e18 (top), percentageStaked_1e18 (below)]
|
||||
;; Step 1: Bind slot 0 (top) to PERCENTAGESTAKED, slot 1 to TAXRATE.
|
||||
PERCENTAGESTAKED DYADIC.DEFINE
|
||||
;; Stack: [slot7(bot), slot6, slot5, slot4, slot3, slot2, slot1(top)]
|
||||
TAXRATE DYADIC.DEFINE
|
||||
;; Stack: [percentageStaked_1e18]
|
||||
;; Stack: [slot7(bot), slot6, slot5, slot4, slot3, slot2(top)]
|
||||
|
||||
;; Step 2: Compute stakedPct = percentageStaked * 100 / 1e18 (integer 0..100)
|
||||
;; Step 2: Discard unused inputs (slots 2-7) — 6 pops.
|
||||
DYADIC.POP
|
||||
DYADIC.POP
|
||||
DYADIC.POP
|
||||
DYADIC.POP
|
||||
DYADIC.POP
|
||||
DYADIC.POP
|
||||
;; Stack: []
|
||||
|
||||
;; Step 3: Compute stakedPct = percentageStaked * 100 / 1e18 (integer 0..100)
|
||||
PERCENTAGESTAKED
|
||||
100 DYADIC.*
|
||||
1000000000000000000 DYADIC./
|
||||
;; Stack: [stakedPct]
|
||||
STAKED DYADIC.DEFINE
|
||||
;; Stack: []
|
||||
|
||||
;; Step 3: Main conditional — stakedPct > 91?
|
||||
;; Step 4: Main conditional — stakedPct > 91?
|
||||
STAKED 91 DYADIC.>
|
||||
;; bool_stack: [stakedPct > 91]
|
||||
|
||||
|
|
@ -164,7 +183,7 @@
|
|||
)
|
||||
)
|
||||
)
|
||||
;; Stack: [raw_idx (0-29)]
|
||||
;; Stack: [raw_idx (0-29)]
|
||||
|
||||
;; Apply effIdx shift: if raw_idx >= 14, effIdx = min(raw_idx + 1, 29)
|
||||
DYADIC.DUP 14 DYADIC.>=
|
||||
|
|
@ -177,7 +196,7 @@
|
|||
( )
|
||||
)
|
||||
( )
|
||||
;; Stack: [effIdx (0-29)]
|
||||
;; Stack: [effIdx (0-29)]
|
||||
|
||||
EFFIDX DYADIC.DEFINE
|
||||
;; Stack: []
|
||||
|
|
@ -189,13 +208,32 @@
|
|||
20 DYADIC./
|
||||
;; Stack: [penalty]
|
||||
|
||||
;; Return penalty < 50
|
||||
;; penalty < 50 → BULL; else → BEAR
|
||||
50 DYADIC.<
|
||||
;; bool_stack: [penalty < 50]
|
||||
|
||||
EXEC.IF
|
||||
;; BULL: push 4 outputs bottom-first (discoveryDepth at bottom, ci at top)
|
||||
(
|
||||
1000000000000000000
|
||||
20
|
||||
1000000000000000000
|
||||
0
|
||||
)
|
||||
;; BEAR
|
||||
(
|
||||
300000000000000000
|
||||
100
|
||||
300000000000000000
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
;; FALSE branch: stakedPct <= 91 — always bear
|
||||
(
|
||||
FALSE
|
||||
300000000000000000
|
||||
100
|
||||
300000000000000000
|
||||
0
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@
|
|||
*
|
||||
* Usage: ts-node src/index.ts <input.push3> <output.sol>
|
||||
*
|
||||
* Reads a Push3 program, transpiles isBullMarket logic, and emits a
|
||||
* Solidity contract that can be compared against the hand-written OptimizerV3.
|
||||
* Reads a Push3 program that consumes 8 dyadic rational inputs (slot 0 on top
|
||||
* of the DYADIC stack) and leaves 4 values at termination, then emits a
|
||||
* Solidity contract implementing calculateParams(OptimizerInput[8]).
|
||||
*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
|
|
@ -28,31 +29,47 @@ function main(): void {
|
|||
const ast = parse(src);
|
||||
console.log('Transpiling...');
|
||||
|
||||
const { functionBody, resultVar } = transpile(ast);
|
||||
const { functionBody, ciVar, anchorShareVar, anchorWidthVar, discoveryDepthVar } = transpile(ast);
|
||||
|
||||
const solidityLines = [
|
||||
'// SPDX-License-Identifier: GPL-3.0-or-later',
|
||||
'pragma solidity ^0.8.19;',
|
||||
'',
|
||||
'import {OptimizerInput} from "./IOptimizer.sol";',
|
||||
'',
|
||||
'/**',
|
||||
' * @title OptimizerV3Push3',
|
||||
' * @notice Auto-generated from optimizer_v3.push3 via Push3→Solidity transpiler.',
|
||||
' * Implements the same isBullMarket logic as OptimizerV3.',
|
||||
' * Implements calculateParams with 8 dyadic rational inputs and 4 outputs.',
|
||||
' */',
|
||||
'contract OptimizerV3Push3 {',
|
||||
' /**',
|
||||
' * @notice Determines if the market is in bull configuration.',
|
||||
' * @param percentageStaked Percentage of authorized stake in use (0 to 1e18).',
|
||||
' * @param averageTaxRate Normalized average tax rate from Stake contract (0 to 1e18).',
|
||||
' * @return bull True if bull config, false if bear.',
|
||||
' * @notice Compute liquidity parameters from 8 dyadic rational inputs.',
|
||||
' * @param inputs 8-slot dyadic rational array: slot 0 = percentageStaked (top of Push3 stack),',
|
||||
' * slot 1 = averageTaxRate, slots 2-7 = extended metrics (0 if unavailable).',
|
||||
' * @return ci Capital inefficiency (0..1e18).',
|
||||
' * @return anchorShare Fraction of non-floor ETH in anchor (0..1e18).',
|
||||
' * @return anchorWidth Anchor position width in tick units.',
|
||||
' * @return discoveryDepth Discovery liquidity density (0..1e18).',
|
||||
' */',
|
||||
' function isBullMarket(',
|
||||
' uint256 percentageStaked,',
|
||||
' uint256 averageTaxRate',
|
||||
' ) public pure returns (bool bull) {',
|
||||
' require(percentageStaked <= 1e18, "Invalid percentage staked");',
|
||||
' function calculateParams(OptimizerInput[8] memory inputs)',
|
||||
' public',
|
||||
' 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)',
|
||||
' for (uint256 k = 0; k < 8; k++) {',
|
||||
' require(inputs[k].shift == 0, "shift not yet supported");',
|
||||
' }',
|
||||
'',
|
||||
...functionBody,
|
||||
` bull = ${resultVar};`,
|
||||
` ci = uint256(${ciVar});`,
|
||||
` anchorShare = uint256(${anchorShareVar});`,
|
||||
` anchorWidth = uint24(${anchorWidthVar});`,
|
||||
` discoveryDepth = uint256(${discoveryDepthVar});`,
|
||||
' }',
|
||||
'}',
|
||||
'',
|
||||
|
|
@ -64,7 +81,7 @@ function main(): void {
|
|||
|
||||
// Print a summary
|
||||
console.log(` Function body: ${functionBody.length} lines`);
|
||||
console.log(` Result var: ${resultVar}`);
|
||||
console.log(` Outputs: ci=${ciVar}, anchorShare=${anchorShareVar}, anchorWidth=${anchorWidthVar}, discoveryDepth=${discoveryDepthVar}`);
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
|
|||
|
|
@ -345,25 +345,41 @@ function toItems(node: Node): Node[] {
|
|||
// ---- Public API ----
|
||||
|
||||
export interface TranspileResult {
|
||||
functionBody: string[];
|
||||
resultVar: string;
|
||||
functionBody: string[];
|
||||
ciVar: string;
|
||||
anchorShareVar: string;
|
||||
anchorWidthVar: string;
|
||||
discoveryDepthVar: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transpile a Push3 program (top-level list) into Solidity function body lines.
|
||||
*
|
||||
* Inputs are primed on the DYADIC stack:
|
||||
* bottom: averageTaxRate (0 to 1e18)
|
||||
* top: percentageStaked (0 to 1e18)
|
||||
* Inputs are primed on the DYADIC stack as 8 dyadic rationals (slot 0 on top,
|
||||
* slot 7 at bottom). Each slot is represented as uint256(inputs[i].mantissa);
|
||||
* shift support is reserved for future evolution — callers must pass shift=0.
|
||||
*
|
||||
* The Push3 program's first instruction is DYADIC.SWAP so it binds averageTaxRate
|
||||
* first, then computes stakedPct.
|
||||
* The program must leave exactly 4 values on the DYADIC stack at termination:
|
||||
* top (index 3): capitalInefficiency
|
||||
* index 2: anchorShare
|
||||
* index 1: anchorWidth
|
||||
* bottom (index 0): discoveryDepth
|
||||
*/
|
||||
export function transpile(program: Node): TranspileResult {
|
||||
if (program.kind !== 'list') throw new Error('Expected top-level list');
|
||||
|
||||
// Prime DYADIC stack: slot 7 at bottom (index 0), slot 0 at top (index 7).
|
||||
const state: TranspilerState = {
|
||||
dStack: ['averageTaxRate', 'percentageStaked'],
|
||||
dStack: [
|
||||
'uint256(inputs[7].mantissa)',
|
||||
'uint256(inputs[6].mantissa)',
|
||||
'uint256(inputs[5].mantissa)',
|
||||
'uint256(inputs[4].mantissa)',
|
||||
'uint256(inputs[3].mantissa)',
|
||||
'uint256(inputs[2].mantissa)',
|
||||
'uint256(inputs[1].mantissa)',
|
||||
'uint256(inputs[0].mantissa)',
|
||||
],
|
||||
bStack: [],
|
||||
nameStack: [],
|
||||
lines: [],
|
||||
|
|
@ -374,6 +390,11 @@ export function transpile(program: Node): TranspileResult {
|
|||
|
||||
processItems(program.items, state);
|
||||
|
||||
const resultVar = state.bStack[state.bStack.length - 1] ?? 'false';
|
||||
return { functionBody: state.lines, resultVar };
|
||||
// Pop 4 outputs: top → ci, then anchorShare, anchorWidth, discoveryDepth.
|
||||
const ciVar = state.dStack.pop() ?? '0';
|
||||
const anchorShareVar = state.dStack.pop() ?? '0';
|
||||
const anchorWidthVar = state.dStack.pop() ?? '0';
|
||||
const discoveryDepthVar = state.dStack.pop() ?? '0';
|
||||
|
||||
return { functionBody: state.lines, ciVar, anchorShareVar, anchorWidthVar, discoveryDepthVar };
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue