Skip to content

Commit

Permalink
fix: update position state for unsynced adjust (#4)
Browse files Browse the repository at this point in the history
* fix pos safe margin min for unsynced adjust

* update ape config for marginal/[email protected]
  • Loading branch information
0xcivita authored Jun 26, 2024
1 parent 3831eb0 commit ef04074
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 73 deletions.
4 changes: 2 additions & 2 deletions ape-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ dependencies:
ref: 0.8
- name: marginal-v1-core
github: MarginalProtocol/v1-core
ref: v1.0.0-rc.5
ref: v1.0.1

solidity:
via_ir: true
import_remapping:
- "@openzeppelin/contracts=openzeppelin/v4.8.3"
- "@uniswap/v3-core/contracts=uniswap-v3-core/v0.8"
- "@uniswap/v3-periphery/contracts=uniswap-v3-periphery/v0.8"
- "@marginal/v1-core/contracts=marginal-v1-core/v1.0.0-rc.5"
- "@marginal/v1-core/contracts=marginal-v1-core/v1.0.1"
114 changes: 58 additions & 56 deletions contracts/base/PositionState.sol
Original file line number Diff line number Diff line change
Expand Up @@ -86,34 +86,31 @@ abstract contract PositionState {
uint256 rewards
)
{
bytes32 key = keccak256(abi.encodePacked(recipient, id));

uint128 _debt0;
uint128 _debt1;
int24 _tick;
uint32 _blockTimestamp;
int56 _tickCumulativeDelta;
(
size,
_debt0,
_debt1,
,
,
zeroForOne,
liquidated,
_tick,
_blockTimestamp,
_tickCumulativeDelta,
margin,
,
rewards
) = IMarginalV1Pool(pool).positions(key);

uint24 maintenance = IMarginalV1Pool(pool).maintenance();

// update for funding with library
PositionLibrary.Info memory info;
{
PositionLibrary.Info memory info = PositionLibrary.Info({
bytes32 key = keccak256(abi.encodePacked(recipient, id));

uint128 _debt0;
uint128 _debt1;
int24 _tick;
uint32 _blockTimestamp;
int56 _tickCumulativeDelta;
(
size,
_debt0,
_debt1,
,
,
zeroForOne,
liquidated,
_tick,
_blockTimestamp,
_tickCumulativeDelta,
margin,
,
rewards
) = IMarginalV1Pool(pool).positions(key);
info = PositionLibrary.Info({
size: size,
debt0: _debt0,
debt1: _debt1,
Expand All @@ -128,9 +125,15 @@ abstract contract PositionState {
liquidityLocked: 0, // @dev irrelevant for sync
rewards: rewards
});
}

uint24 maintenance = IMarginalV1Pool(pool).maintenance();
uint128 marginMinimum = info.marginMinimum(maintenance);

// sync if not settled or liquidated
if (info.size > 0) {
// sync if not settled or liquidated
if (info.size > 0) {
int56 oracleTickCumulativeDelta;
{
(
,
,
Expand All @@ -145,7 +148,7 @@ abstract contract PositionState {
int56[] memory oracleTickCumulativesLast = getOracleSynced(
pool
);
int56 oracleTickCumulativeDelta = OracleLibrary
oracleTickCumulativeDelta = OracleLibrary
.oracleTickCumulativeDelta(
oracleTickCumulativesLast[0],
oracleTickCumulativesLast[1]
Expand All @@ -158,32 +161,36 @@ abstract contract PositionState {
PoolConstants.tickCumulativeRateMax,
PoolConstants.fundingPeriod
);
safe = info.safe(
OracleLibrary.oracleSqrtPriceX96(
oracleTickCumulativeDelta,
PoolConstants.secondsAgo
),
maintenance
);
safeMarginMinimum = _safeMarginMinimum(
info,
maintenance,
oracleTickCumulativeDelta
);
}

debt = zeroForOne ? info.debt0 : info.debt1;
safe = info.safe(
OracleLibrary.oracleSqrtPriceX96(
oracleTickCumulativeDelta,
PoolConstants.secondsAgo
),
maintenance
);
safeMarginMinimum = _safeMarginMinimum(
info,
marginMinimum,
maintenance,
oracleTickCumulativeDelta
);
}

debt = zeroForOne ? info.debt0 : info.debt1;
}

/// @notice Calculates the minimum margin requirement for the position to remain safe from liquidation
/// @dev c_y (safe) >= (1+M) * d_x * max(P, TWAP) - s_y when zeroForOne = true
/// or c_x (safe) >= (1+M) * d_y / min(P, TWAP) - s_x when zeroForOne = false
/// @param info The position info
/// @dev c_y (safe) >= (1+M) * d_x * max(P, TWAP) - s_y when zeroForOne = true when no funding
/// or c_x (safe) >= (1+M) * d_y / min(P, TWAP) - s_x when zeroForOne = false when no funding
/// @param info The synced position info
/// @param marginMinimum The margin minimum when ignoring funding and liquidation
/// @param maintenance The minimum maintenance margin requirement
/// @param oracleTickCumulativeDelta The difference in oracle tick cumulatives averaged over to assess position safety with
function _safeMarginMinimum(
PositionLibrary.Info memory info,
uint128 marginMinimum,
uint24 maintenance,
int56 oracleTickCumulativeDelta
) internal pure returns (uint128 safeMarginMinimum) {
Expand All @@ -192,17 +199,12 @@ abstract contract PositionState {
oracleTickCumulativeDelta / int56(uint56(PoolConstants.secondsAgo))
);

// change to using oracle tick for safe margin minimum calculation if
// greater than position tick when zeroForOne = true
// or less than position tick when zeroForOne = false
if (
(info.zeroForOne && oracleTick > positionTick) ||
(!info.zeroForOne && oracleTick < positionTick)
) {
info.tick = oracleTick;
}

// change to using oracle tick for safe margin minimum calculation with liquidation and funding
info.tick = oracleTick;
safeMarginMinimum = info.marginMinimum(maintenance);
if (marginMinimum > safeMarginMinimum)
safeMarginMinimum = marginMinimum;

info.tick = positionTick; // in case reuse info, return to actual position tick
}
}
1 change: 1 addition & 0 deletions contracts/lens/Quoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ contract Quoter is
);
safeMarginMinimum = _safeMarginMinimum(
position,
marginMinimum,
params.maintenance,
oracleTickCumulativeDelta
);
Expand Down
17 changes: 2 additions & 15 deletions contracts/test/MarginalV1Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -442,17 +442,7 @@ contract MarginalV1Pool is IMarginalV1Pool, ERC20 {
Position.Info memory position = positions.get(msg.sender, id);
if (position.size == 0) revert InvalidPosition();

// zero seconds ago for oracle tickCumulative
int56 oracleTickCumulative = oracleTickCumulatives(new uint32[](1))[0];

// update debts for funding
position = position.sync(
_state.blockTimestamp,
_state.tickCumulative,
oracleTickCumulative,
tickCumulativeRateMax,
fundingPeriod
);
// don't update position stored debts for funding to avoid short circuiting and min margin zero issues
uint128 marginMinimum = position.marginMinimum(maintenance);
if (
int256(uint256(position.margin)) + int256(marginDelta) <
Expand Down Expand Up @@ -494,10 +484,7 @@ contract MarginalV1Pool is IMarginalV1Pool, ERC20 {
position.margin = margin1.toUint128();
}

// don't update position stored debts for funding to avoid short circuiting issues
Position.Info memory _position = positions.get(msg.sender, id);
_position.margin = position.margin;
positions.set(msg.sender, id, _position);
positions.set(msg.sender, id, position);

// update pool state to latest
state = _state;
Expand Down

0 comments on commit ef04074

Please sign in to comment.