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
31 changes: 31 additions & 0 deletions contracts/interfaces/cpmm/ICPMMGammaPool.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

/// @title Interface for Constant Product Market Maker version of GammaPool
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
interface ICPMMGammaPool {

/// @dev _maxTotalAPY - new maximum total APY charged to Borrowers
event SetMaxTotalAPY(uint256 _maxTotalAPY);

/// @dev initialization parameters passed to CPMMGammaPool constructor
struct InitializationParams {
uint16 protocolId;
address factory;
address borrowStrategy;
address repayStrategy;
address rebalanceStrategy;
address shortStrategy;
address liquidationStrategy;
address batchLiquidationStrategy;
address viewer;
address externalRebalanceStrategy;
address externalLiquidationStrategy;
address cfmmFactory;
bytes32 cfmmInitCodeHash;
}

/// @dev set maximum total APY charged by GammaPool to borrowers
/// @param _maxTotalAPY - new maximum total APY charged to GammaPool borrowers
function setMaxTotalAPY(uint256 _maxTotalAPY) external;
}
14 changes: 14 additions & 0 deletions contracts/interfaces/cpmm/strategies/ICPMMRebalanceStrategy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

/// @title Interface for Rebalance Strategy of Constant Product Market Maker version of GammaPool
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
interface ICPMMRebalanceStrategy {

/// @dev _maxTotalAPY - new maximum total APY charged to Borrowers
event SetMaxTotalAPY(uint256 _maxTotalAPY);

/// @dev set maximum total APY charged by GammaPool to borrowers
/// @param _maxTotalAPY - new maximum total APY charged to GammaPool borrowers
function _setMaxTotalAPY(uint256 _maxTotalAPY) external;
}
23 changes: 23 additions & 0 deletions contracts/interfaces/vault/IVaultGammaPool.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

/// @title Interface for Vault GammaPool smart contract
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev Used as template for building other Vault GammaPool contract implementations
interface IVaultGammaPool {

/// @dev enum indices for storage fields saved for Vault GammaPool
enum StorageIndexes { RESERVED_BORROWED_INVARIANT, RESERVED_LP_TOKENS }

/// @dev reserve LP tokens for future borrowing (prevents others from borrowing) or free reserved LP tokens so others can borrow them.
/// @param tokenId - tokenId of loan used to reserve or free reserved LP tokens. Must be refType 3.
/// @param lpTokens - number of LP tokens that must be reserved or freed.
/// @param isReserve - if true then reserve LP tokens, if false, then free reserved LP tokens.
/// @return reservedLPTokens - LP tokens that have been reserved or freed.
function reserveLPTokens(uint256 tokenId, uint256 lpTokens, bool isReserve) external returns(uint256);

/// @dev Get borrowed invariant and LP tokens that have been reserved through refType 3 loans
/// @return reservedBorrowedInvariant - borrowed invariant that is reserved for refType 3 loans
/// @return reservedLPTokens - LP tokens reserved for future use by refType 3 loans
function getReservedBalances() external view returns(uint256 reservedBorrowedInvariant, uint256 reservedLPTokens);
}
24 changes: 24 additions & 0 deletions contracts/interfaces/vault/IVaultPoolViewer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

import "@gammaswap/v1-core/contracts/interfaces/IGammaPool.sol";

interface IVaultPoolViewer {

struct VaultPoolData {
IGammaPool.PoolData poolData;
uint256 reservedBorrowedInvariant;
uint256 reservedLPTokens;
}

/// @dev Returns vault pool storage data updated to their latest values
/// @notice Difference with getVaultPoolData() is this struct is what PoolData would return if an update of the GammaPool were to occur at the current block
/// @param pool - address of pool to get pool data for
/// @return data - struct containing all relevant global state variables and descriptive information of GammaPool. Used to avoid making multiple calls
function getLatestVaultPoolData(address pool) external view returns(VaultPoolData memory data);

/// @dev Return vault pool storage data
/// @param pool - address of pool to get pool data for
/// @return data - struct containing all relevant global state variables and descriptive information of GammaPool. Used to avoid making multiple calls
function getVaultPoolData(address pool) external view returns(VaultPoolData memory data);
}
14 changes: 14 additions & 0 deletions contracts/interfaces/vault/strategies/IVaultReserveStrategy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

/// @title Interface Vault Strategy
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @notice Used to reserve LP tokens for vault to use in a future call to borrowLiquidity().
interface IVaultReserveStrategy {
/// @dev reserve LP tokens for future borrowing (prevents others from borrowing) or free reserved LP tokens so others can borrow them.
/// @param tokenId - tokenId of loan used to reserve or free reserved LP tokens. Must be refType 3.
/// @param lpTokens - number of LP tokens that must be reserved or freed.
/// @param isReserve - if true then reserve LP tokens, if false, then free reserved LP tokens.
/// @return reservedLPTokens - LP tokens that have been reserved or freed.
function _reserveLPTokens(uint256 tokenId, uint256 lpTokens, bool isReserve) external returns(uint256);
}
47 changes: 47 additions & 0 deletions contracts/interfaces/vault/strategies/IVaultShortStrategy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

/// @title Interface Vault Short Strategy
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @notice Used to calculate total supply and assets from Short Strategy accounting for reserved borrowed liquidity
interface IVaultShortStrategy {
/// @dev Parameters used to calculate the GS LP tokens and CFMM LP tokens in the GammaPool after protocol fees and accrued interest
struct VaultReservedBalancesParams {
/// @dev address of factory contract of GammaPool
address factory;
/// @dev address of GammaPool
address pool;
/// @dev address of contract holding rate parameters for pool
address paramsStore;
/// @dev storage number of borrowed liquidity invariant in GammaPool
uint256 BORROWED_INVARIANT;
/// @dev storage number of reserved borrowed liquidity invariant in GammaPool
uint256 RESERVED_BORROWED_INVARIANT;
/// @dev current liquidity invariant in CFMM
uint256 latestCfmmInvariant;
/// @dev current total supply of CFMM LP tokens in existence
uint256 latestCfmmTotalSupply;
/// @dev last block number GammaPool was updated
uint256 LAST_BLOCK_NUMBER;
/// @dev CFMM liquidity invariant at time of last update of GammaPool
uint256 lastCFMMInvariant;
/// @dev CFMM LP Token supply at time of last update of GammaPool
uint256 lastCFMMTotalSupply;
/// @dev CFMM Fee Index at time of last update of GammaPool
uint256 lastCFMMFeeIndex;
/// @dev current total supply of GS LP tokens
uint256 totalSupply;
/// @dev current LP Tokens in GammaPool counted at time of last update
uint256 LP_TOKEN_BALANCE;
/// @dev liquidity invariant of LP tokens in GammaPool at time of last update
uint256 LP_INVARIANT;
}

/// @dev Calculate current total GS LP tokens after protocol fees and total CFMM LP tokens (real and virtual) in
/// @dev existence in the GammaPool after accrued interest. The total assets and supply numbers returned by this
/// @dev function are used in the ERC4626 implementation of the GammaPool
/// @param vaultReservedBalanceParams - parameters from GammaPool to calculate current total GS LP Tokens and CFMM LP Tokens after fees and interest
/// @return assets - total CFMM LP tokens in existence in the pool (real and virtual) including accrued interest
/// @return supply - total GS LP tokens in the pool including accrued interest
function totalReservedAssetsAndSupply(VaultReservedBalancesParams memory vaultReservedBalanceParams) external view returns(uint256 assets, uint256 supply);
}
37 changes: 25 additions & 12 deletions contracts/pools/CPMMGammaPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import "@gammaswap/v1-core/contracts/base/GammaPoolExternal.sol";
import "@gammaswap/v1-core/contracts/libraries/AddressCalculator.sol";
import "@gammaswap/v1-core/contracts/libraries/GammaSwapLibrary.sol";
import "@gammaswap/v1-core/contracts/libraries/GSMath.sol";
import "../interfaces/cpmm/strategies/ICPMMRebalanceStrategy.sol";
import "../interfaces/cpmm/ICPMMGammaPool.sol";

/// @title GammaPool implementation for Constant Product Market Maker
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev This implementation is specifically for validating UniswapV2Pair and clone contracts
contract CPMMGammaPool is GammaPool, GammaPoolExternal {
contract CPMMGammaPool is GammaPool, GammaPoolExternal, ICPMMGammaPool {

error NotContract();
error BadProtocol();
Expand All @@ -24,16 +26,14 @@ contract CPMMGammaPool is GammaPool, GammaPoolExternal {
/// @return cfmmInitCodeHash - init code hash of CFMM
bytes32 immutable public cfmmInitCodeHash;

/// @dev Initializes the contract by setting `protocolId`, `factory`, `borrowStrategy`, `repayStrategy`,
/// @dev Initializes the contract by setting `protocolId`, `factory`, `borrowStrategy`, `repayStrategy`, `rebalanceStrategy`,
/// @dev `shortStrategy`, `liquidationStrategy`, `batchLiquidationStrategy`, `cfmmFactory`, and `cfmmInitCodeHash`.
constructor(uint16 _protocolId, address _factory, address _borrowStrategy, address _repayStrategy,
address _shortStrategy, address _liquidationStrategy, address _batchLiquidationStrategy, address _viewer,
address _externalRebalanceStrategy, address _externalLiquidationStrategy, address _cfmmFactory, bytes32 _cfmmInitCodeHash)
GammaPool(_protocolId, _factory, _borrowStrategy, _repayStrategy, _borrowStrategy, _shortStrategy,
_liquidationStrategy, _batchLiquidationStrategy, _viewer)
GammaPoolExternal(_externalRebalanceStrategy, _externalLiquidationStrategy) {
cfmmFactory = _cfmmFactory;
cfmmInitCodeHash = _cfmmInitCodeHash;
constructor(InitializationParams memory params) GammaPool(params.protocolId, params.factory, params.borrowStrategy,
params.repayStrategy, params.rebalanceStrategy, params.shortStrategy, params.liquidationStrategy,
params.batchLiquidationStrategy, params.viewer) GammaPoolExternal(params.externalRebalanceStrategy,
params.externalLiquidationStrategy) {
cfmmFactory = params.cfmmFactory;
cfmmInitCodeHash = params.cfmmInitCodeHash;
}

/// @dev See {IGammaPool-createLoan}
Expand All @@ -57,7 +57,8 @@ contract CPMMGammaPool is GammaPool, GammaPoolExternal {
}

/// @dev See {IGammaPool-validateCFMM}
function validateCFMM(address[] calldata _tokens, address _cfmm, bytes calldata) external virtual override view returns(address[] memory _tokensOrdered) {
function validateCFMM(address[] calldata _tokens, address _cfmm, bytes calldata) external virtual override view
returns(address[] memory _tokensOrdered) {
if(!GammaSwapLibrary.isContract(_cfmm)) revert NotContract(); // Not a smart contract (hence not a CFMM) or not instantiated yet
if(_tokens.length != 2) revert InvalidTokensLength();

Expand All @@ -66,8 +67,20 @@ contract CPMMGammaPool is GammaPool, GammaPoolExternal {
(_tokensOrdered[0], _tokensOrdered[1]) = _tokens[0] < _tokens[1] ? (_tokens[0], _tokens[1]) : (_tokens[1], _tokens[0]);

// Verify CFMM was created by CFMM's factory contract
if(_cfmm != AddressCalculator.calcAddress(cfmmFactory,keccak256(abi.encodePacked(_tokensOrdered[0], _tokensOrdered[1])),cfmmInitCodeHash)) {
if(_cfmm != AddressCalculator.calcAddress(cfmmFactory,
keccak256(abi.encodePacked(_tokensOrdered[0], _tokensOrdered[1])),cfmmInitCodeHash)) {
revert BadProtocol();
}
}

/// @dev See {ICPMMGammaPool-setMaxTotalAPY}
function setMaxTotalAPY(uint256 _maxTotalAPY) external virtual override {
abi.decode(callStrategy(rebalanceStrategy, abi.encodeCall(ICPMMRebalanceStrategy._setMaxTotalAPY, _maxTotalAPY)), ());
}

/// @dev See {IGammaPoolExternal-liquidateExternally}
function liquidateExternally(uint256 tokenId, uint128[] calldata amounts, uint256 lpTokens, address to, bytes calldata data)
external override virtual returns(uint256 loanLiquidity, uint256[] memory refund) {
return (0, new uint256[](0));
}
}
8 changes: 2 additions & 6 deletions contracts/pools/CPMMGammaPoolMain.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,9 @@ contract CPMMGammaPoolMain is CPMMGammaPool {

using LibStorage for LibStorage.Storage;

/// @dev Initializes the contract by setting `protocolId`, `factory`, `borrowStrategy`, `repayStrategy`,
/// @dev Initializes the contract by setting `protocolId`, `factory`, `borrowStrategy`, `repayStrategy`, `rebalanceStrategy`,
/// @dev `shortStrategy`, `liquidationStrategy`, `batchLiquidationStrategy`, `cfmmFactory`, and `cfmmInitCodeHash`.
constructor(uint16 _protocolId, address _factory, address _borrowStrategy, address _repayStrategy,
address _shortStrategy, address _liquidationStrategy, address _batchLiquidationStrategy, address _viewer,
address _externalRebalanceStrategy, address _externalLiquidationStrategy, address _cfmmFactory, bytes32 _cfmmInitCodeHash)
CPMMGammaPool(_protocolId, _factory, _borrowStrategy, _repayStrategy, _shortStrategy, _liquidationStrategy,
_batchLiquidationStrategy, _viewer, _externalRebalanceStrategy, _externalLiquidationStrategy, _cfmmFactory, _cfmmInitCodeHash) {
constructor(InitializationParams memory params) CPMMGammaPool(params) {
}

/// @dev See {IGammaPool-initialize}
Expand Down
75 changes: 75 additions & 0 deletions contracts/pools/VaultGammaPool.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import "../interfaces/vault/strategies/IVaultReserveStrategy.sol";
import "../interfaces/vault/strategies/IVaultShortStrategy.sol";
import "../interfaces/vault/IVaultGammaPool.sol";
import "./CPMMGammaPool.sol";

/// @title Vault GammaPool implementation for Constant Product Market Maker
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev This implementation is specifically for validating UniswapV2Pair and clone contracts
contract VaultGammaPool is CPMMGammaPool, IVaultGammaPool {

using LibStorage for LibStorage.Storage;

/// @dev Initializes the contract by setting `protocolId`, `factory`, `borrowStrategy`, `repayStrategy`, `rebalanceStrategy`,
/// @dev `shortStrategy`, `liquidationStrategy`, `batchLiquidationStrategy`, `cfmmFactory`, and `cfmmInitCodeHash`.
constructor(InitializationParams memory params) CPMMGammaPool(params) {
}

/// @dev See {IVaultGammaPool-reserveLPTokens}
function reserveLPTokens(uint256 tokenId, uint256 lpTokens, bool isReserve) external virtual override whenNotPaused(26) returns(uint256) {
return abi.decode(callStrategy(externalRebalanceStrategy, abi.encodeCall(IVaultReserveStrategy._reserveLPTokens, (tokenId, lpTokens, isReserve))), (uint256));
}

/// @dev See {IVaultGammaPool-getReservedBalances}
function getReservedBalances() external virtual override view returns(uint256 reservedBorrowedInvariant, uint256 reservedLPTokens) {
reservedBorrowedInvariant = s.getUint256(uint256(IVaultGammaPool.StorageIndexes.RESERVED_BORROWED_INVARIANT));
reservedLPTokens = s.getUint256(uint256(IVaultGammaPool.StorageIndexes.RESERVED_LP_TOKENS));
}

/// @dev See {IGammaPool-liquidateWithLP}
function liquidateWithLP(uint256 tokenId) external virtual override returns(uint256 loanLiquidity, uint256[] memory refund) {
return (0, new uint256[](0));
}

/// @dev See {IGammaPool-batchLiquidations}
function batchLiquidations(uint256[] calldata tokenIds) external virtual override returns(uint256 totalLoanLiquidity, uint256[] memory refund) {
return (0, new uint256[](0));
}

/// @dev See {GammaPoolERC4626-maxAssets}
function maxAssets(uint256 assets) internal view virtual override returns(uint256) {
uint256 reservedLpTokenBalance = s.getUint256(uint256(IVaultGammaPool.StorageIndexes.RESERVED_LP_TOKENS));
uint256 lpTokenBalance = s.LP_TOKEN_BALANCE; // CFMM LP tokens in GammaPool that have not been borrowed
lpTokenBalance = lpTokenBalance - GSMath.min(reservedLpTokenBalance, lpTokenBalance);
if(assets < lpTokenBalance){ // limit assets available to withdraw to what has not been borrowed
return assets;
}
return lpTokenBalance;
}

/// @dev See {GammaPoolERC4626-_totalAssetsAndSupply}
function _totalAssetsAndSupply() internal view virtual override returns (uint256 assets, uint256 supply) {
address _factory = s.factory;
(assets, supply) = IVaultShortStrategy(vaultImplementation()).totalReservedAssetsAndSupply(
IVaultShortStrategy.VaultReservedBalancesParams({
factory: _factory,
pool: address(this),
paramsStore: _factory,
BORROWED_INVARIANT: s.BORROWED_INVARIANT,
RESERVED_BORROWED_INVARIANT: s.getUint256(uint256(IVaultGammaPool.StorageIndexes.RESERVED_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
})
);
}
}
26 changes: 26 additions & 0 deletions contracts/pools/VaultGammaPoolMain.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import "./VaultGammaPool.sol";

/// @title Vault GammaPool implementation for Constant Product Market Maker in mainnet Ethereum
/// @author Daniel D. Alcarraz (https://github.com/0xDanr)
/// @dev This implementation is specifically for validating UniswapV2Pair and clone contracts
/// @dev Overrides the initialize function to set params for higher network costs in mainnet Ethereum
contract VaultGammaPoolMain is VaultGammaPool {

using LibStorage for LibStorage.Storage;

/// @dev Initializes the contract by setting `protocolId`, `factory`, `borrowStrategy`, `repayStrategy`, `rebalanceStrategy`,
/// @dev `shortStrategy`, `liquidationStrategy`, `batchLiquidationStrategy`, `cfmmFactory`, and `cfmmInitCodeHash`.
constructor(InitializationParams memory params) VaultGammaPool(params) {
}

/// @dev See {IGammaPool-initialize}
function initialize(address _cfmm, address[] calldata _tokens, uint8[] calldata _decimals, uint72 _minBorrow, bytes calldata) external virtual override {
if(msg.sender != factory) revert Forbidden(); // only factory is allowed to initialize
s.initialize(factory, _cfmm, protocolId, _tokens, _decimals, _minBorrow);
s.ltvThreshold = 15; // 150 basis points
s.liquidationFee = 125; // 125 basis points
}
}
Loading
Loading