Skip to content

Commit 7d86752

Browse files
committed
refactor: bind Retargetter to a single owner-set PositionManager (3F-483)
Replace the position-manager whitelist with a single instance binding: the Retargetter runs every operation against one owner-bound PositionManager instead of taking it as a caller-supplied argument. - Bind via initialize (optional positionManager_ param, threaded through createRetargetter) or setPositionManager(address), rebindable by the owner only while no operation is active. Both validate the contract and its asset-pair match. - Drop the positionManager argument from startRetargetting and startSyncRetargetting; they read the bound manager. maxPrincipal() drops its argument too. isPositionManager -> boundPositionManager view. - Error PositionManagerNotWhitelisted -> PositionManagerNotBound; event PositionManagerSet -> PositionManagerBound. Smaller than the whitelist (no mapping, no per-call arg): Retargetter runtime 23,949 B on the ci profile, 627 B under EIP-170 (was 24,136 / 440 B). Full suite 2349 passing, 74 invariants passing; the not-bound guard is mutation-checked.
1 parent d2fccf9 commit 7d86752

12 files changed

Lines changed: 248 additions & 297 deletions

File tree

‎src/interfaces/manager/rebalancer/IRetargetter.sol‎

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,9 @@ interface IRetargetter {
151151
/// @param whitelisted Whether the module is now whitelisted
152152
event FlashLoanModuleSet(address indexed module, bool whitelisted);
153153

154-
/// @notice Emitted when a position manager's whitelist entry is set.
155-
/// @param positionManager The position manager
156-
/// @param whitelisted Whether the position manager is now whitelisted
157-
event PositionManagerSet(address indexed positionManager, bool whitelisted);
154+
/// @notice Emitted when the owner binds the instance to a position manager.
155+
/// @param positionManager The position manager the instance is now bound to
156+
event PositionManagerBound(address indexed positionManager);
158157

159158
/// @notice Emitted when the yield estimates are updated.
160159
/// @param estimates The new estimates
@@ -168,19 +167,18 @@ interface IRetargetter {
168167
/* ASYNC FLOW */
169168
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
170169

171-
/// @notice Starts an asynchronous retargetting operation by deploying a fresh Request.
170+
/// @notice Starts an asynchronous retargetting operation against the bound position manager
171+
/// by deploying a fresh Request.
172172
/// @dev The repayment terms (horizon, tick duration, tick threshold) and the effective
173173
/// yield cap are snapshotted into the operation here; a later setConfig does not
174-
/// reprice a started operation.
175-
/// @param positionManager The owner-whitelisted position manager to retarget
174+
/// reprice a started operation. Reverts if no position manager is bound.
176175
/// @param principal The intended principal, fail-fast checked against the cap
177176
/// @param maxYieldBps_ The caller's yield cap; the effective cap is min(config, caller)
178177
/// @param fund The whitelisted fund to bind to the operation
179178
/// @param requestName The base name for the Request's PT/YT tokens
180179
/// @param requestSymbol The base symbol for the Request's PT/YT tokens
181180
/// @return request The deployed Request
182181
function startRetargetting(
183-
address positionManager,
184182
uint256 principal,
185183
uint16 maxYieldBps_,
186184
address fund,
@@ -302,27 +300,23 @@ interface IRetargetter {
302300
/* SYNC FLOW */
303301
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
304302

305-
/// @notice Runs a whole retargetting operation atomically inside a flash loan.
303+
/// @notice Runs a whole retargetting operation against the bound position manager atomically
304+
/// inside a flash loan.
306305
/// @dev The steps are supplied as a multicall payload executed inside the flash-loan
307306
/// callback. The callback is bound to this exact payload (digest match) and requires
308307
/// the loan delivered in full before any step runs. At window close no order may be
309308
/// stored and the Retargetter's balances of both bound assets must be within the
310-
/// configured residual tolerance. The position manager's rebalance cooldown is
311-
/// enforced per rebalance call, so with a nonzero cooldown compatible legs must be
312-
/// packed into a single rebalance step, and a route needing an intervening fund action
313-
/// between two rebalances runs as separate transactions.
314-
/// @param positionManager The owner-whitelisted position manager to retarget
309+
/// configured residual tolerance. Reverts if no position manager is bound. The position
310+
/// manager's rebalance cooldown is enforced per rebalance call, so with a nonzero
311+
/// cooldown compatible legs must be packed into a single rebalance step, and a route
312+
/// needing an intervening fund action between two rebalances runs as separate
313+
/// transactions.
315314
/// @param flashLoanModule The whitelisted flash-loan module to borrow through
316315
/// @param flashLoanAmount The flash-loan size, checked against the principal cap
317316
/// @param fund The whitelisted fund the payload may create orders against
318317
/// @param data The step calls executed inside the flash-loan window
319-
function startSyncRetargetting(
320-
address positionManager,
321-
address flashLoanModule,
322-
uint256 flashLoanAmount,
323-
address fund,
324-
bytes[] calldata data
325-
) external;
318+
function startSyncRetargetting(address flashLoanModule, uint256 flashLoanAmount, address fund, bytes[] calldata data)
319+
external;
326320

327321
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
328322
/* CONFIGURATION */
@@ -354,15 +348,14 @@ interface IRetargetter {
354348
/// @param whitelisted Whether the module should be whitelisted
355349
function setFlashLoanModule(address module, bool whitelisted) external;
356350

357-
/// @notice Sets a position manager's whitelist entry.
358-
/// @dev Operations only bind to whitelisted position managers: every start-gate and
359-
/// principal-cap read trusts what the bound address reports about itself, so the
360-
/// binding is owner-curated like funds and flash-loan modules. Whitelisting checks
361-
/// the position manager is a contract and its assets match the bound pair; removal
362-
/// skips those checks but reverts while it is bound to the active operation.
363-
/// @param positionManager The position manager
364-
/// @param whitelisted Whether the position manager should be whitelisted
365-
function setPositionManager(address positionManager, bool whitelisted) external;
351+
/// @notice Binds the single position manager every operation runs against.
352+
/// @dev Operations never take a position manager as an argument: they run against this
353+
/// binding, so every start-gate and principal-cap read trusts an owner-curated
354+
/// address rather than a caller-supplied one. Checks the position manager is a
355+
/// contract and its assets match the bound pair, and reverts while an operation is
356+
/// active (the binding can only be rotated while idle). Also settable at initialize.
357+
/// @param positionManager The position manager to bind
358+
function setPositionManager(address positionManager) external;
366359

367360
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
368361
/* VIEWS */
@@ -412,18 +405,18 @@ interface IRetargetter {
412405
/// flash-loan window for the duration of its transaction).
413406
function isActive() external view returns (bool);
414407

415-
/// @notice Computes the current principal cap for a position manager.
408+
/// @notice Computes the current principal cap for the bound position manager.
416409
/// @dev Quoter formula on live state with the owner estimates, auto-detected direction,
417410
/// times one plus the principal buffer. Below target the cap is further bounded by
418411
/// the one-trip repayment bound, so a cap-sized, fully deployed operation can always
419412
/// borrow its worst permitted repayment back at target in a single settlement trip.
420413
/// This view sizes that bound on the config yield-cap ceiling, a safe floor for
421414
/// every permissible operation; the operation gates size it on the effective
422415
/// per-operation cap (zero for a SYNC window, whose flash repayment carries no
423-
/// yield) and can admit up to that looser bound.
424-
/// @param positionManager The position manager to size against
416+
/// yield) and can admit up to that looser bound. Reverts if no position manager is
417+
/// bound.
425418
/// @return The principal cap in debt-asset units
426-
function maxPrincipal(address positionManager) external view returns (uint256);
419+
function maxPrincipal() external view returns (uint256);
427420

428421
/// @notice Returns the current amount owed on the active operation's Request.
429422
function owed() external view returns (uint256);
@@ -447,9 +440,8 @@ interface IRetargetter {
447440
/// @param module The module to check
448441
function isFlashLoanModule(address module) external view returns (bool);
449442

450-
/// @notice Returns whether a position manager is whitelisted.
451-
/// @param positionManager The position manager to check
452-
function isPositionManager(address positionManager) external view returns (bool);
443+
/// @notice Returns the bound position manager (zero when none is bound).
444+
function boundPositionManager() external view returns (address);
453445

454446
/// @notice Returns the quoter holding the sizing math.
455447
function quoter() external view returns (address);

‎src/libs/manager/rebalancer/LibRetargetterErrors.sol‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ library LibRetargetterErrors {
3636
/// @notice Thrown when binding a fund that is not owner-whitelisted.
3737
error FundNotWhitelisted();
3838

39-
/// @notice Thrown when binding a position manager that is not owner-whitelisted.
40-
error PositionManagerNotWhitelisted();
39+
/// @notice Thrown when starting an operation before the owner has bound a position manager.
40+
error PositionManagerNotBound();
4141

4242
/// @notice Thrown when using a flash-loan module that is not owner-whitelisted.
4343
error ModuleNotWhitelisted();

‎src/libs/manager/rebalancer/LibStorage.sol‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,26 @@ import {
1717
MIN_DEADLINE_BUFFER
1818
} from "./LibRetargetterConstants.sol";
1919

20-
/// @notice The Retargetter's bound asset pair (namespace "retargetter.assets").
21-
/// @dev Written once at initialize, never mutated afterwards.
20+
/// @notice The Retargetter's instance bindings (namespace "retargetter.assets").
21+
/// @dev The pair is written once at initialize and never mutated; the position manager is
22+
/// owner-bound and rebindable while no operation is active.
2223
/// @param collateralAsset The collateral asset every position manager and fund must match
2324
/// @param debtAsset The debt asset every position manager, fund and Request must match
25+
/// @param positionManager The single position manager every operation runs against, bound by
26+
/// the owner (its assets are checked against the pair at bind time)
2427
struct RetargetterAssets {
2528
address collateralAsset;
2629
address debtAsset;
30+
address positionManager;
2731
}
2832

2933
/// @notice The Retargetter's whitelists (namespace "retargetter.whitelists").
3034
/// @dev Plain mappings without enumeration; indexers use the add/remove events.
3135
/// @param funds The owner-approved venues
3236
/// @param flashLoanModules The owner-approved flash-loan adapters
33-
/// @param positionManagers The owner-approved position managers an operation may bind to
3437
struct RetargetterWhitelists {
3538
mapping(address fund => bool) funds;
3639
mapping(address module => bool) flashLoanModules;
37-
mapping(address positionManager => bool) positionManagers;
3840
}
3941

4042
/// @notice The one in-flight operation (namespace "retargetter.operation").

0 commit comments

Comments
 (0)