Skip to content

Commit 4a71510

Browse files
committed
test(wip): basic harness for precision loss analysis
1 parent 9a95f5a commit 4a71510

File tree

3 files changed

+129
-1
lines changed

3 files changed

+129
-1
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,5 @@ deployed_strategies.json
5353
populate_src*
5454

5555
# cerota
56-
.certora_internal/*
56+
.certora_internal/*
57+
/snapshots/
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.27;
3+
4+
import "src/test/integration/IntegrationChecks.t.sol";
5+
6+
contract Integration_Rounding is IntegrationCheckUtils {
7+
using ArrayLib for *;
8+
using StdStyle for *;
9+
10+
User attacker;
11+
AVS badAVS;
12+
IStrategy strategy;
13+
IERC20Metadata token;
14+
15+
OperatorSet mOpSet; // "manipOpSet" used for magnitude manipulation
16+
OperatorSet rOpSet; // redistributable opset used to exploit precision loss and trigger redistribution
17+
18+
function _init() internal override {
19+
_configAssetTypes(HOLDS_LST);
20+
21+
attacker = new User("Attacker");
22+
badAVS = new AVS("BadAVS");
23+
strategy = lstStrats[0];
24+
token = IERC20Metadata(address(strategy.underlyingToken()));
25+
26+
// Register attacker as operator and create attacker-controller AVS/OpSets
27+
attacker.registerAsOperator(0);
28+
rollForward({blocks: ALLOCATION_CONFIGURATION_DELAY + 1});
29+
badAVS.updateAVSMetadataURI("https://example.com");
30+
mOpSet = badAVS.createOperatorSet(strategy.toArray());
31+
rOpSet = badAVS.createRedistributingOperatorSet(strategy.toArray(), address(attacker));
32+
33+
// Register for both opsets
34+
attacker.registerForOperatorSet(mOpSet);
35+
attacker.registerForOperatorSet(rOpSet);
36+
37+
_print("setup");
38+
}
39+
40+
function test_rounding() public rand(0) {
41+
_magnitudeManipulation();
42+
_setupFinal();
43+
_final();
44+
}
45+
46+
// TODO - another way to mess with rounding/precision loss is to manipulate DSF
47+
function _magnitudeManipulation() internal {
48+
attacker.modifyAllocations(AllocateParams({
49+
operatorSet: mOpSet,
50+
strategies: strategy.toArray(),
51+
newMagnitudes: WAD.toArrayU64()
52+
}));
53+
54+
_print("allocate");
55+
56+
badAVS.slashOperator(SlashingParams({
57+
operator: address(attacker),
58+
operatorSetId: mOpSet.id,
59+
strategies: strategy.toArray(),
60+
wadsToSlash: uint(WAD-1).toArrayU256(),
61+
description: ""
62+
}));
63+
64+
_print("slash");
65+
}
66+
67+
function _setupFinal() internal {
68+
// create redistributable opset
69+
// deposit assets
70+
}
71+
72+
function _final() internal {
73+
// perform f
74+
}
75+
76+
function _print(string memory phaseName) internal {
77+
address a = address(attacker);
78+
79+
console.log("");
80+
console.log("===Attacker Info: %s phase===".cyan(), phaseName);
81+
82+
{
83+
console.log("\nRaw Assets:".magenta());
84+
console.log(" - token: %s", token.symbol());
85+
console.log(" - held balance: %d", token.balanceOf(a));
86+
// TODO - amt deposited, possibly keep track of this separately?
87+
}
88+
89+
{
90+
console.log("\nShares:".magenta());
91+
92+
(uint[] memory withdrawableArr, uint[] memory depositArr)
93+
= delegationManager.getWithdrawableShares(a, strategy.toArray());
94+
uint withdrawableShares = withdrawableArr.length == 0 ? 0 : withdrawableArr[0];
95+
uint depositShares = depositArr.length == 0 ? 0 : depositArr[0];
96+
console.log(" - deposit shares: %d", depositShares);
97+
console.log(" - withdrawable shares: %d", withdrawableShares);
98+
console.log(" - operator shares: %d", delegationManager.operatorShares(a, strategy));
99+
}
100+
101+
{
102+
console.log("\nScaling:".magenta());
103+
104+
Allocation memory mAlloc = allocationManager.getAllocation(a, mOpSet, strategy);
105+
Allocation memory rAlloc = allocationManager.getAllocation(a, rOpSet, strategy);
106+
107+
console.log(" - Init Mag: %d", WAD);
108+
console.log(
109+
" - Max Mag: %d\n -- Total Allocated: %d\n -- Total Available: %d",
110+
allocationManager.getMaxMagnitude(a, strategy),
111+
allocationManager.getEncumberedMagnitude(a, strategy),
112+
allocationManager.getAllocatableMagnitude(a, strategy)
113+
);
114+
console.log(" - Allocated to mOpSet: %d", mAlloc.currentMagnitude);
115+
console.log(" - Allocated to rOpSet: %d", rAlloc.currentMagnitude);
116+
console.log(" - DSF: %d", delegationManager.depositScalingFactor(a, strategy));
117+
}
118+
119+
console.log("\n ===\n".cyan());
120+
}
121+
}

src/test/integration/users/User.t.sol

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ contract User is Logger, IDelegationManagerTypes, IAllocationManagerTypes {
166166
print.gasUsed();
167167
}
168168

169+
function registerAsOperator(uint32 allocDelay) public virtual createSnapshot {
170+
print.method("registerAsOperator");
171+
delegationManager.registerAsOperator(address(0), allocDelay, "metadata");
172+
print.gasUsed();
173+
}
174+
169175
/// @dev Delegate to the operator without a signature
170176
function delegateTo(User operator) public virtual createSnapshot {
171177
print.method("delegateTo", operator.NAME_COLORED());

0 commit comments

Comments
 (0)