Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 50 additions & 28 deletions contracts/base/GammaPoolERC4626.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,15 @@ abstract contract GammaPoolERC4626 is GammaPoolERC20, DelegateCaller, Refunds, P
/// @dev Convert CFMM LP tokens to GS LP tokens
/// @param assets - CFMM LP tokens
/// @return shares - GS LP tokens quantity that corresponds to assets quantity provided as a parameter (CFMM LP tokens)
function convertToShares(uint256 assets) public view virtual returns (uint256) {
function convertToShares(uint256 assets) external view virtual returns (uint256) {
return _convertToShares(assets, true);
}

/// @dev Convert CFMM LP tokens to GS LP tokens
/// @param assets - CFMM LP tokens
/// @param roundUp - if true round up result else round down
/// @return shares - GS LP tokens quantity that corresponds to assets quantity provided as a parameter (CFMM LP tokens)
function _convertToShares(uint256 assets, bool roundUp) internal view virtual returns (uint256) {
if(assets == 0) {
return 0;
}
Expand All @@ -115,23 +123,35 @@ abstract contract GammaPoolERC4626 is GammaPoolERC20, DelegateCaller, Refunds, P
return assets - MIN_SHARES;
}
}

if(roundUp) {
return (assets * supply + (_totalAssets - 1))/ _totalAssets;
}
return (assets * supply) / _totalAssets;
}

/// @dev Convert GS LP tokens to GS LP tokens
/// @param shares - GS LP tokens
/// @return assets - CFMM LP tokens quantity that corresponds to shares quantity provided as a parameter (GS LP tokens)
function convertToAssets(uint256 shares) public view virtual returns (uint256) {
function convertToAssets(uint256 shares) external view virtual returns (uint256) {
return _convertToAssets(shares, false);
}

/// @dev Convert GS LP tokens to GS LP tokens
/// @param shares - GS LP tokens
/// @param roundUp - if true round up result else round down
/// @return assets - CFMM LP tokens quantity that corresponds to shares quantity provided as a parameter (GS LP tokens)
function _convertToAssets(uint256 shares, bool roundUp) internal view virtual returns (uint256) {
if(shares == 0) {
return 0;
}
(uint256 assets, uint256 supply) = _totalAssetsAndSupply();
if(supply == 0) {
if(shares <= MIN_SHARES) revert MinShares();
return shares + MIN_SHARES;
}

unchecked {
return shares - MIN_SHARES;
}
if(roundUp) {
return (shares * assets + (supply - 1)) / supply;
}
// totalAssets is total CFMM LP tokens, including accrued interest, calculated using state variables
return (shares * assets) / supply;
Expand All @@ -141,28 +161,28 @@ abstract contract GammaPoolERC4626 is GammaPoolERC20, DelegateCaller, Refunds, P
/// @param assets - CFMM LP tokens
/// @return shares - expected GS LP tokens to get from assets (CFMM LP tokens) deposited
function previewDeposit(uint256 assets) public view virtual returns (uint256) {
return convertToShares(assets);
return _convertToShares(assets, false);
}

/// @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given current on-chain conditions.
/// @param shares - GS LP tokens
/// @return assets - CFMM LP tokens needed to deposit to get the desired shares (GS LP tokens)
function previewMint(uint256 shares) public view virtual returns (uint256) {
return convertToAssets(shares);
return _convertToAssets(shares, true);
}

/// @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, given current on-chain conditions.
/// @param assets - CFMM LP tokens
/// @return shares - expected GS LP tokens needed to burn to withdraw desired assets (CFMM LP tokens)
function previewWithdraw(uint256 assets) public view virtual returns (uint256) {
return convertToShares(assets);
return _convertToShares(assets, true);
}

/// @dev Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block, given current on-chain conditions.
/// @param shares - GS LP tokens
/// @return assets - expected CFMM LP tokens withdrawn if shares (GS LP tokens) burned
function previewRedeem(uint256 shares) public view virtual returns (uint256) {
return convertToAssets(shares);
return _convertToAssets(shares, false);
}

/// @dev Returns the maximum amount of CFMM LP tokens that can be deposited into the Vault for the receiver, through a deposit call. Ignores address parameter
Expand Down Expand Up @@ -193,14 +213,14 @@ abstract contract GammaPoolERC4626 is GammaPoolERC20, DelegateCaller, Refunds, P
/// @param owner - address that owns GS LP tokens
/// @return maxAssets - maximum amount of CFMM LP tokens that can be withdrawn by owner address
function maxWithdraw(address owner) public view virtual returns (uint256) {
return maxAssets(convertToAssets(s.balanceOf[owner])); // convert owner GS LP tokens to equivalent CFMM LP tokens and check if available to withdraw
return maxAssets(_convertToAssets(s.balanceOf[owner], false)); // convert owner GS LP tokens to equivalent CFMM LP tokens and check if available to withdraw
}

/// @dev Returns the maximum amount of GS LP tokens that can be redeemed from the owner balance in the Vault, through a redeem call.
/// @param owner - address that owns GS LP tokens
/// @return maxShares - maximum amount of GS LP tokens that can be redeemed by owner address
function maxRedeem(address owner) public view virtual returns (uint256) {
return convertToShares(maxWithdraw(owner)); // get maximum amount of CFMM LP tokens that can be withdrawn and convert to equivalent GS LP token amount
return s.balanceOf[owner]; // get maximum amount of CFMM LP tokens that can be withdrawn and convert to equivalent GS LP token amount
}

/// @dev Calculate and return total CFMM LP tokens belonging to GammaPool liquidity providers using state global variables.
Expand All @@ -209,21 +229,23 @@ abstract contract GammaPoolERC4626 is GammaPoolERC20, DelegateCaller, Refunds, P
/// @return assets - current total CFMM LP tokens (real and virtual) in existence in the GammaPool, including accrued interest
/// @return supply - total supply of GS LP tokens after taking protocol revenue dilution into account
function _totalAssetsAndSupply() internal view virtual returns (uint256 assets, uint256 supply) {
IShortStrategy.VaultBalancesParams memory _params;
_params.factory = s.factory;
_params.pool = address(this);
_params.paramsStore = _params.factory;
_params.BORROWED_INVARIANT = s.BORROWED_INVARIANT;
_params.latestCfmmInvariant = _getLatestCFMMInvariant();
_params.latestCfmmTotalSupply = _getLatestCFMMTotalSupply();
_params.LAST_BLOCK_NUMBER = s.LAST_BLOCK_NUMBER;
_params.lastCFMMInvariant = s.lastCFMMInvariant;
_params.lastCFMMTotalSupply = s.lastCFMMTotalSupply;
_params.lastCFMMFeeIndex = s.lastCFMMFeeIndex;
_params.totalSupply = s.totalSupply;
_params.LP_TOKEN_BALANCE = s.LP_TOKEN_BALANCE;
_params.LP_INVARIANT = s.LP_INVARIANT;

(assets, supply) = IShortStrategy(vaultImplementation()).totalAssetsAndSupply(_params);
address _factory = s.factory;
(assets, supply) = IShortStrategy(vaultImplementation()).totalAssetsAndSupply(
IShortStrategy.VaultBalancesParams({
factory: _factory,
pool: address(this),
paramsStore: _factory,
BORROWED_INVARIANT: s.BORROWED_INVARIANT,
latestCfmmInvariant: _getLatestCFMMInvariant(),
latestCfmmTotalSupply: _getLatestCFMMTotalSupply(),
LAST_BLOCK_NUMBER: s.LAST_BLOCK_NUMBER,
lastCFMMInvariant: s.lastCFMMInvariant,
lastCFMMTotalSupply: s.lastCFMMTotalSupply,
lastCFMMFeeIndex: s.lastCFMMFeeIndex,
totalSupply: s.totalSupply,
LP_TOKEN_BALANCE: s.LP_TOKEN_BALANCE,
LP_INVARIANT: s.LP_INVARIANT
})
);
}
}
34 changes: 27 additions & 7 deletions contracts/strategies/ShortStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,12 @@ abstract contract ShortStrategy is IShortStrategy, BaseStrategy {
updateIndex();

// Convert CFMM LP tokens (`assets`) to GS LP tokens (`shares`)
shares = convertToShares(assets);
shares = convertToShares(assets, false);
// revert if request is for 0 GS LP tokens
if(shares == 0) revert ZeroShares();

// To prevent rounding errors, lock min shares in first deposit
if(s.totalSupply == 0) {
shares = shares - MIN_SHARES;
assets = assets - MIN_SHARES;
depositAssets(msg.sender, address(0), MIN_SHARES, MIN_SHARES, isDepositReserves);
}
Expand Down Expand Up @@ -209,7 +208,7 @@ abstract contract ShortStrategy is IShortStrategy, BaseStrategy {
updateIndex();

// Convert GS LP tokens (`shares`) to CFMM LP tokens (`assets`)
assets = convertToAssets(shares);
assets = convertToAssets(shares, false);
// revert if request is for 0 CFMM LP tokens
if(assets == 0) revert ZeroAssets();

Expand Down Expand Up @@ -307,17 +306,38 @@ abstract contract ShortStrategy is IShortStrategy, BaseStrategy {

/// @dev Check if `spender` has permissions to spend `amount` of GS LP tokens belonging to `owner`
/// @param assets - address that owns the GS LP tokens
function convertToShares(uint256 assets) internal view virtual returns (uint256) {
/// @param roundUp - if true round up result, else round down
function convertToShares(uint256 assets, bool roundUp) internal view virtual returns (uint256) {
if(assets == 0) {
return 0;
}
uint256 supply = s.totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.
uint256 _totalAssets = s.LP_TOKEN_BALANCE + s.LP_TOKEN_BORROWED_PLUS_INTEREST;
return supply == 0 || _totalAssets == 0 ? assets : (assets * supply / _totalAssets);
if(supply == 0 || _totalAssets == 0) {
return assets - MIN_SHARES;
}
if(roundUp) {
return (assets * supply + (_totalAssets - 1)) / _totalAssets;
}
return (assets * supply / _totalAssets);
}

/// @dev Check if `spender` has permissions to spend `amount` of GS LP tokens belonging to `owner`
/// @param shares - address that owns the GS LP tokens
function convertToAssets(uint256 shares) internal view virtual returns (uint256) {
/// @param roundUp - if true round up result, else round down
function convertToAssets(uint256 shares, bool roundUp) internal view virtual returns (uint256) {
if(shares == 0) {
return 0;
}
uint256 supply = s.totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.
return supply == 0 ? shares : (shares * (s.LP_TOKEN_BALANCE + s.LP_TOKEN_BORROWED_PLUS_INTEREST) / supply);
if(supply == 0) {
return shares + MIN_SHARES;
}
uint256 _totalAssets = s.LP_TOKEN_BALANCE + s.LP_TOKEN_BORROWED_PLUS_INTEREST;
if(roundUp) {
return (shares * _totalAssets + (supply - 1)) / supply;
}
return (shares * _totalAssets) / supply;
}

// INTERNAL HOOKS LOGIC
Expand Down
9 changes: 4 additions & 5 deletions contracts/strategies/ShortStrategyERC4626.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ abstract contract ShortStrategyERC4626 is ShortStrategy {
updateIndex();

// Convert CFMM LP tokens to GS LP tokens
shares = convertToShares(assets);
shares = convertToShares(assets, false);

// Revert if redeeming 0 GS LP tokens
if(shares == 0) revert ZeroShares();
Expand All @@ -30,7 +30,7 @@ abstract contract ShortStrategyERC4626 is ShortStrategy {
updateIndex();

// Convert GS LP tokens to CFMM LP tokens
assets = convertToAssets(shares);
assets = convertToAssets(shares, true);

// Revert if withdrawing 0 CFMM LP tokens
if(assets == 0) revert ZeroAssets();
Expand All @@ -48,7 +48,7 @@ abstract contract ShortStrategyERC4626 is ShortStrategy {
if(assets > s.LP_TOKEN_BALANCE) revert ExcessiveWithdrawal();

// Convert CFMM LP tokens to GS LP tokens
shares = convertToShares(assets);
shares = convertToShares(assets, true);

// Revert if redeeming 0 GS LP tokens
if(shares == 0) revert ZeroShares();
Expand All @@ -63,7 +63,7 @@ abstract contract ShortStrategyERC4626 is ShortStrategy {
updateIndex();

// Convert GS LP tokens to CFMM LP tokens
assets = convertToAssets(shares);
assets = convertToAssets(shares, false);
if(assets == 0) revert ZeroAssets(); // revert if withdrawing 0 CFMM LP tokens

// Revert if not enough CFMM LP tokens to withdraw
Expand All @@ -84,7 +84,6 @@ abstract contract ShortStrategyERC4626 is ShortStrategy {

// To prevent rounding errors, lock min shares in first deposit
if(s.totalSupply == 0) {
shares = shares - MIN_SHARES;
assets = assets - MIN_SHARES;
depositAssets(caller, address(0), MIN_SHARES, MIN_SHARES, false);
}
Expand Down
4 changes: 2 additions & 2 deletions contracts/strategies/base/BaseStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ abstract contract BaseStrategy is AppStorage, AbstractRateModel {
/// @param borrowedInvariant - liquidity invariant borrowed in the GammaPool
/// @param lastFeeIndex - interest accrued to loans in GammaPool
/// @return newBorrowedInvariant - borrowed invariant with accrued interest
function accrueBorrowedInvariant(uint256 borrowedInvariant, uint256 lastFeeIndex) internal virtual pure returns(uint256) {
return borrowedInvariant * lastFeeIndex / 1e18;
function accrueBorrowedInvariant(uint256 borrowedInvariant, uint256 lastFeeIndex) internal virtual view returns(uint256) {
return borrowedInvariant * lastFeeIndex / 1e18;
}

/// @notice Convert CFMM LP tokens into liquidity invariant units.
Expand Down
10 changes: 7 additions & 3 deletions contracts/test/strategies/base/TestBaseShortStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ abstract contract TestBaseShortStrategy is ShortStrategy {

function depositLPTokens(address to) public virtual {
uint256 assets = IERC20(s.cfmm).balanceOf(address(this)) - s.LP_TOKEN_BALANCE;
uint256 shares = convertToShares(assets);
uint256 shares = convertToShares(assets, false);
_mint(to, shares);
s.LP_TOKEN_BALANCE = IERC20(s.cfmm).balanceOf(address(this));
}
Expand Down Expand Up @@ -138,11 +138,15 @@ abstract contract TestBaseShortStrategy is ShortStrategy {
}

function _convertToShares(uint256 assets) public view virtual returns(uint256) {
return convertToShares(assets);
return convertToShares(assets, true);
}

function _convertToAssets(uint256 shares) public view virtual returns(uint256) {
return convertToAssets(shares);
return convertToAssets(shares, false);
}

function _convertToAssets2(uint256 shares, bool roundUp) public view virtual returns(uint256) {
return convertToAssets(shares, roundUp);
}

function calcBorrowRate(uint256 lpInvariant, uint256 borrowedInvariant, address paramsStore, address pool) public virtual
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gammaswap/v1-core",
"version": "1.2.11",
"version": "1.2.12",
"description": "Core smart contracts for the GammaSwap V1 protocol",
"homepage": "https://gammaswap.com",
"scripts": {
Expand Down
Loading