From 9f45a12eca23f5c007bd4b2ffa2b2ea0da34e25f Mon Sep 17 00:00:00 2001 From: alexangelj Date: Sun, 30 Jan 2022 14:04:01 -0800 Subject: [PATCH 1/2] fix(#275): updates event arguments and engine --- contracts/PrimitiveEngine.sol | 10 +++---- .../engine/IPrimitiveEngineEvents.sol | 27 ++++++++++++++++--- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/contracts/PrimitiveEngine.sol b/contracts/PrimitiveEngine.sol index d805172f..54e5f368 100644 --- a/contracts/PrimitiveEngine.sol +++ b/contracts/PrimitiveEngine.sol @@ -185,7 +185,8 @@ contract PrimitiveEngine is IPrimitiveEngine { if (delRisky == 0 || delStable == 0) revert CalibrationError(delRisky, delStable); calibrations[poolId] = cal; // state update - liquidity[msg.sender][poolId] += delLiquidity - MIN_LIQUIDITY; // burn min liquidity, at cost of msg.sender + uint256 amount = delLiquidity - MIN_LIQUIDITY; + liquidity[msg.sender][poolId] += amount; // burn min liquidity, at cost of msg.sender reserves[poolId].allocate(delRisky, delStable, delLiquidity, cal.lastTimestamp); // state update (uint256 balRisky, uint256 balStable) = (balanceRisky(), balanceStable()); @@ -193,7 +194,7 @@ contract PrimitiveEngine is IPrimitiveEngine { checkRiskyBalance(balRisky + delRisky); checkStableBalance(balStable + delStable); - emit Create(msg.sender, cal.strike, cal.sigma, cal.maturity, cal.gamma); + emit Create(msg.sender, cal.strike, cal.sigma, cal.maturity, cal.gamma, delRisky, delStable, amount); } // ===== Margin ===== @@ -250,7 +251,6 @@ contract PrimitiveEngine is IPrimitiveEngine { uint256 liquidity0 = (delRisky * reserve.liquidity) / uint256(reserve.reserveRisky); uint256 liquidity1 = (delStable * reserve.liquidity) / uint256(reserve.reserveStable); delLiquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1; - if (delLiquidity == 0) revert ZeroLiquidityError(); liquidity[recipient][poolId] += delLiquidity; // increase position liquidity @@ -265,7 +265,7 @@ contract PrimitiveEngine is IPrimitiveEngine { checkStableBalance(balStable + delStable); } - emit Allocate(msg.sender, recipient, poolId, delRisky, delStable); + emit Allocate(msg.sender, recipient, poolId, delRisky, delStable, delLiquidity); } /// @inheritdoc IPrimitiveEngineActions @@ -284,7 +284,7 @@ contract PrimitiveEngine is IPrimitiveEngine { reserve.remove(delRisky, delStable, delLiquidity, _blockTimestamp()); margins[msg.sender].deposit(delRisky, delStable); - emit Remove(msg.sender, poolId, delRisky, delStable); + emit Remove(msg.sender, poolId, delRisky, delStable, delLiquidity); } struct SwapDetails { diff --git a/contracts/interfaces/engine/IPrimitiveEngineEvents.sol b/contracts/interfaces/engine/IPrimitiveEngineEvents.sol index 04743ae2..86f58087 100644 --- a/contracts/interfaces/engine/IPrimitiveEngineEvents.sol +++ b/contracts/interfaces/engine/IPrimitiveEngineEvents.sol @@ -11,7 +11,19 @@ interface IPrimitiveEngineEvents { /// @param sigma Implied Volatility of the pool /// @param maturity Maturity timestamp of the pool /// @param gamma 1 - Fee % of the pool, as an integer with precision of 1e4 - event Create(address indexed from, uint128 indexed strike, uint32 sigma, uint32 indexed maturity, uint32 gamma); + /// @param delRisky Amount of risky tokens deposited + /// @param delStable Amount of stable tokens deposited + /// @param delLiquidity Amount of liquidity granted to `recipient` + event Create( + address indexed from, + uint128 strike, + uint32 sigma, + uint32 indexed maturity, + uint32 indexed gamma, + uint256 delRisky, + uint256 delStable, + uint256 delLiquidity + ); /// @notice Updates the time until expiry of the pool with `poolId` /// @param poolId Pool Identifier @@ -41,12 +53,14 @@ interface IPrimitiveEngineEvents { /// @param poolId Pool Identifier /// @param delRisky Amount of risky tokens deposited /// @param delStable Amount of stable tokens deposited + /// @param delLiquidity Amount of liquidity granted to `recipient` event Allocate( address indexed from, address indexed recipient, bytes32 indexed poolId, uint256 delRisky, - uint256 delStable + uint256 delStable, + uint256 delLiquidity ); /// @notice Adds liquidity of risky and stable tokens to a specified `poolId` @@ -54,7 +68,14 @@ interface IPrimitiveEngineEvents { /// @param poolId Pool Identifier /// @param delRisky Amount of risky tokens deposited /// @param delStable Amount of stable tokens deposited - event Remove(address indexed from, bytes32 indexed poolId, uint256 delRisky, uint256 delStable); + /// @param delLiquidity Amount of liquidity decreased from `from` + event Remove( + address indexed from, + bytes32 indexed poolId, + uint256 delRisky, + uint256 delStable, + uint256 delLiquidity + ); // ===== Swaps ===== From b4c8495e8bb888eb285bf9c0e5ddd91dce1cadc9 Mon Sep 17 00:00:00 2001 From: alexangelj Date: Sun, 30 Jan 2022 14:31:49 -0800 Subject: [PATCH 2/2] fix(#275): updates natspec of all interfaces --- .../engine/IPrimitiveEngineActions.sol | 24 +++++++++---------- .../engine/IPrimitiveEngineErrors.sol | 13 ++++++---- .../engine/IPrimitiveEngineEvents.sol | 18 +++++++------- .../engine/IPrimitiveEngineView.sol | 22 ++++++++--------- 4 files changed, 40 insertions(+), 37 deletions(-) diff --git a/contracts/interfaces/engine/IPrimitiveEngineActions.sol b/contracts/interfaces/engine/IPrimitiveEngineActions.sol index 0e51a166..07fb4951 100644 --- a/contracts/interfaces/engine/IPrimitiveEngineActions.sol +++ b/contracts/interfaces/engine/IPrimitiveEngineActions.sol @@ -7,19 +7,19 @@ interface IPrimitiveEngineActions { // ===== Pool Updates ===== /// @notice Updates the time until expiry of the pool by setting its last timestamp value - /// @param poolId Pool Identifier + /// @param poolId Keccak256 hash of engine address, strike, sigma, maturity, and gamma /// @return lastTimestamp Timestamp loaded into the state of the pool's Calibration.lastTimestamp function updateLastTimestamp(bytes32 poolId) external returns (uint32 lastTimestamp); - /// @notice Initializes a curve with parameters in the `settings` storage mapping in the Engine - /// @param strike Strike price of the pool to calibrate to, with the same decimals as the stable token - /// @param sigma Implied Volatility to calibrate to as an unsigned 32-bit integer w/ precision of 1e4, 10000 = 100% - /// @param maturity Maturity timestamp of the pool, in seconds - /// @param gamma Multiplied against swap in amounts to apply fee, equal to 1 - fee %, an unsigned 32-bit integer, w/ precision of 1e4, 10000 = 100% - /// @param riskyPerLp Risky reserve per liq. with risky decimals, = 1 - N(d1), d1 = (ln(S/K)+(r*sigma^2/2))/sigma*sqrt(tau) - /// @param delLiquidity Amount of liquidity to allocate to the curve, wei value with 18 decimals of precision + /// @notice Initializes a curve with parameters in the `calibrations` storage mapping in the Engine + /// @param strike Marginal price of the pool's risky token at maturity, with the same decimals as the stable token, valid [0, 2^128-1] + /// @param sigma AKA Implied Volatility in basis points, determines the price impact of swaps, valid for (1, 10_000_000) + /// @param maturity Timestamp which starts the BUFFER countdown until swaps will cease, in seconds, valid for (block.timestamp, 2^32-1] + /// @param gamma Multiplied against swap in amounts to apply fee, equal to 1 - fee % but units are in basis points, valid for (9_000, 10_000) + /// @param riskyPerLp Risky reserve per liq. with risky decimals, = 1 - N(d1), d1 = (ln(S/K)+(r*σ^2/2))/σ√τ, valid for [0, 1e^(risky token decimals)) + /// @param delLiquidity Amount of liquidity units to allocate to the curve, wei value with 18 decimals of precision /// @param data Arbitrary data that is passed to the createCallback function - /// @return poolId Pool Identifier + /// @return poolId Keccak256 hash of engine address, strike, sigma, maturity, and gamma /// @return delRisky Total amount of risky tokens provided to reserves /// @return delStable Total amount of stable tokens provided to reserves function create( @@ -65,7 +65,7 @@ interface IPrimitiveEngineActions { // ===== Liquidity ===== /// @notice Allocates risky and stable tokens to a specific curve with `poolId` - /// @param poolId Pool Identifier + /// @param poolId Keccak256 hash of engine address, strike, sigma, maturity, and gamma /// @param recipient Address to give the allocated liquidity to /// @param delRisky Amount of risky tokens to add /// @param delStable Amount of stable tokens to add @@ -82,7 +82,7 @@ interface IPrimitiveEngineActions { ) external returns (uint256 delLiquidity); /// @notice Unallocates risky and stable tokens from a specific curve with `poolId` - /// @param poolId Pool Identifier + /// @param poolId Keccak256 hash of engine address, strike, sigma, maturity, and gamma /// @param delLiquidity Amount of liquidity to remove /// @return delRisky Amount of risky tokens received from removed liquidity /// @return delStable Amount of stable tokens received from removed liquidity @@ -92,7 +92,7 @@ interface IPrimitiveEngineActions { /// @notice Swaps between `risky` and `stable` tokens /// @param recipient Address that receives output token `deltaOut` amount - /// @param poolId Pool Identifier + /// @param poolId Keccak256 hash of engine address, strike, sigma, maturity, and gamma /// @param riskyForStable If true, swap risky to stable, else swap stable to risky /// @param deltaIn Amount of tokens to swap in /// @param deltaOut Amount of tokens to swap out diff --git a/contracts/interfaces/engine/IPrimitiveEngineErrors.sol b/contracts/interfaces/engine/IPrimitiveEngineErrors.sol index ca61004f..5d660458 100644 --- a/contracts/interfaces/engine/IPrimitiveEngineErrors.sol +++ b/contracts/interfaces/engine/IPrimitiveEngineErrors.sol @@ -3,14 +3,16 @@ pragma solidity >=0.8.4; /// @title Errors for the Primitive Engine contract /// @author Primitive +/// @notice Custom errors are encoded with their selector and arguments +/// @dev Peripheral smart contracts should try catch and check if data matches another custom error interface IPrimitiveEngineErrors { - /// @notice Thrown when a callback function calls the engine __again__ + /// @notice Thrown on attempted re-entrancy on a function with a re-entrancy guard error LockedError(); /// @notice Thrown when the balanceOf function is not successful and does not return data error BalanceError(); - /// @notice Thrown when a pool with poolId already exists + /// @notice Thrown in create when a pool with computed poolId already exists error PoolDuplicateError(); /// @notice Thrown when calling an expired pool, where block.timestamp > maturity, + BUFFER if swap @@ -19,7 +21,7 @@ interface IPrimitiveEngineErrors { /// @notice Thrown when liquidity is lower than or equal to the minimum amount of liquidity error MinLiquidityError(uint256 value); - /// @notice Thrown when riskyPerLp is outside the range of acceptable values, 0 < riskyPerLp < 1eRiskyDecimals + /// @notice Thrown when riskyPerLp is outside the range of acceptable values, 0 < riskyPerLp <= 1eRiskyDecimals error RiskyPerLpError(uint256 value); /// @notice Thrown when sigma is outside the range of acceptable values, 1 <= sigma <= 1e7 with 4 precision @@ -28,7 +30,7 @@ interface IPrimitiveEngineErrors { /// @notice Thrown when strike is not valid, i.e. equal to 0 or greater than 2^128 error StrikeError(uint256 value); - /// @notice Thrown when gamma, equal to 1 - fee %, is outside its bounds: 9000 <= gamma <= 10000; 1000 = 10% fee + /// @notice Thrown when gamma, equal to 1 - fee %, is outside its bounds: 9_000 <= gamma <= 10_000; 1_000 = 10% fee error GammaError(uint256 value); /// @notice Thrown when the parameters of a new pool are invalid, causing initial reserves to be 0 @@ -60,7 +62,8 @@ interface IPrimitiveEngineErrors { error DeltaOutError(); /// @notice Thrown when the invariant check fails + /// @dev Most important check as it verifies the validity of a desired swap /// @param invariant Pre-swap invariant updated with new tau - /// @param nextInvariant Post-swap invariant + /// @param nextInvariant Post-swap invariant after the swap amounts are applied to reserves error InvariantError(int128 invariant, int128 nextInvariant); } diff --git a/contracts/interfaces/engine/IPrimitiveEngineEvents.sol b/contracts/interfaces/engine/IPrimitiveEngineEvents.sol index 86f58087..5de8dfc8 100644 --- a/contracts/interfaces/engine/IPrimitiveEngineEvents.sol +++ b/contracts/interfaces/engine/IPrimitiveEngineEvents.sol @@ -5,12 +5,12 @@ pragma solidity >=0.5.0; /// @author Primitive interface IPrimitiveEngineEvents { /// @notice Creates a pool with liquidity - /// @dev Keccak256 hash of the engine address and the parameters is the `poolId` + /// @dev Keccak256 hash of the engine address, strike, sigma, maturity, and gamma /// @param from Calling `msg.sender` of the create function - /// @param strike Strike price of the pool, with precision of stable token - /// @param sigma Implied Volatility of the pool - /// @param maturity Maturity timestamp of the pool - /// @param gamma 1 - Fee % of the pool, as an integer with precision of 1e4 + /// @param strike Marginal price of the pool's risky token at maturity, with the same decimals as the stable token, valid [0, 2^128-1] + /// @param sigma AKA Implied Volatility in basis points, determines the price impact of swaps, valid for (1, 10_000_000) + /// @param maturity Timestamp which starts the BUFFER countdown until swaps will cease, in seconds, valid for (block.timestamp, 2^32-1] + /// @param gamma Multiplied against swap in amounts to apply fee, equal to 1 - fee % but units are in basis points, valid for (9000, 10_000) /// @param delRisky Amount of risky tokens deposited /// @param delStable Amount of stable tokens deposited /// @param delLiquidity Amount of liquidity granted to `recipient` @@ -26,7 +26,7 @@ interface IPrimitiveEngineEvents { ); /// @notice Updates the time until expiry of the pool with `poolId` - /// @param poolId Pool Identifier + /// @param poolId Keccak256 hash of the engine address, strike, sigma, maturity, and gamma event UpdateLastTimestamp(bytes32 indexed poolId); // ===== Margin ==== @@ -50,7 +50,7 @@ interface IPrimitiveEngineEvents { /// @notice Adds liquidity of risky and stable tokens to a specified `poolId` /// @param from Method caller `msg.sender` /// @param recipient Address that receives liquidity - /// @param poolId Pool Identifier + /// @param poolId Keccak256 hash of the engine address, strike, sigma, maturity, and gamma /// @param delRisky Amount of risky tokens deposited /// @param delStable Amount of stable tokens deposited /// @param delLiquidity Amount of liquidity granted to `recipient` @@ -65,7 +65,7 @@ interface IPrimitiveEngineEvents { /// @notice Adds liquidity of risky and stable tokens to a specified `poolId` /// @param from Method caller `msg.sender` - /// @param poolId Pool Identifier + /// @param poolId Keccak256 hash of the engine address, strike, sigma, maturity, and gamma /// @param delRisky Amount of risky tokens deposited /// @param delStable Amount of stable tokens deposited /// @param delLiquidity Amount of liquidity decreased from `from` @@ -82,7 +82,7 @@ interface IPrimitiveEngineEvents { /// @notice Swaps between `risky` and `stable` assets /// @param from Method caller `msg.sender` /// @param recipient Address that receives `deltaOut` amount of tokens - /// @param poolId Pool Identifier + /// @param poolId Keccak256 hash of the engine address, strike, sigma, maturity, and gamma /// @param riskyForStable If true, swaps risky to stable, else swaps stable to risky /// @param deltaIn Amount of tokens added to reserves /// @param deltaOut Amount of tokens removed from reserves diff --git a/contracts/interfaces/engine/IPrimitiveEngineView.sol b/contracts/interfaces/engine/IPrimitiveEngineView.sol index f4d283fc..3f7ef347 100644 --- a/contracts/interfaces/engine/IPrimitiveEngineView.sol +++ b/contracts/interfaces/engine/IPrimitiveEngineView.sol @@ -6,8 +6,8 @@ pragma solidity >=0.5.0; interface IPrimitiveEngineView { // ===== View ===== - /// @notice Fetches the current invariant based on risky and stable token reserves of pool with `poolId` - /// @param poolId Pool Identifier + /// @notice Fetches the current invariant, notation is usually `k`, based on risky and stable token reserves of pool with `poolId` + /// @param poolId Keccak256 hash of the engine address, strike, sigma, maturity, and gamma /// @return invariant Signed fixed point 64.64 number, invariant of `poolId` function invariantOf(bytes32 poolId) external view returns (int128 invariant); @@ -27,10 +27,10 @@ interface IPrimitiveEngineView { //// @return Factory address which deployed this engine contract function factory() external view returns (address); - //// @return Risky token address + //// @return Risky token address, a more accurate name is the underlying token function risky() external view returns (address); - /// @return Stable token address + /// @return Stable token address, a more accurate name is the quote token function stable() external view returns (address); /// @return Multiplier to scale amounts to/from, equal to 10^(18 - riskyDecimals) @@ -42,7 +42,7 @@ interface IPrimitiveEngineView { // ===== Pool State ===== /// @notice Fetches the global reserve state for a pool with `poolId` - /// @param poolId Pool Identifier + /// @param poolId Keccak256 hash of the engine address, strike, sigma, maturity, and gamma /// @return reserveRisky Risky token balance in the reserve /// @return reserveStable Stable token balance in the reserve /// @return liquidity Total supply of liquidity for the curve @@ -64,12 +64,12 @@ interface IPrimitiveEngineView { ); /// @notice Fetches `Calibration` pool parameters - /// @param poolId Pool Identifier - /// @return strike Strike price of the pool with stable token decimals - /// @return sigma Implied Volatility as an unsigned 32-bit integer constant w/ precision of 1e4, 10000 = 100% - /// @return maturity Timestamp of maturity in seconds + /// @param poolId Keccak256 hash of the engine address, strike, sigma, maturity, and gamma + /// @return strike Marginal price of the pool's risky token at maturity, with the same decimals as the stable token, valid [0, 2^128-1] + /// @return sigma AKA Implied Volatility in basis points, determines the price impact of swaps, valid for (1, 10_000_000) + /// @return maturity Timestamp which starts the BUFFER countdown until swaps will cease, in seconds, valid for (block.timestamp, 2^32-1] /// @return lastTimestamp Last timestamp used to calculate time until expiry, aka "tau" - /// @return gamma = 1 - fee %, as an unsigned 32-bit integer constant w/ precision of 1e4, 10000 = 100% + /// @return gamma Multiplied against swap in amounts to apply fee, equal to 1 - fee % but units are in basis points, valid for (9_000, 10_000) function calibrations(bytes32 poolId) external view @@ -82,7 +82,7 @@ interface IPrimitiveEngineView { ); /// @notice Fetches position liquidity an account address and poolId - /// @param poolId Pool Identifier + /// @param poolId Keccak256 hash of the engine address, strike, sigma, maturity, and gamma /// @return liquidity Liquidity owned by `account` in `poolId` function liquidity(address account, bytes32 poolId) external view returns (uint256 liquidity);