Skip to content

Commit

Permalink
Merge pull request #922 from rndquu/feat/fractional-pool
Browse files Browse the repository at this point in the history
Feat/fractional pool
  • Loading branch information
gitcoindev authored Apr 6, 2024
2 parents 9662858 + a9cd4a6 commit 92bc566
Show file tree
Hide file tree
Showing 8 changed files with 1,149 additions and 82 deletions.
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@
"twap",
"typechain",
"TYPEHASH",
"Twocrypto",
"Ubiqui",
"UbiquiStick",
"Unassigns",
Expand Down
88 changes: 83 additions & 5 deletions packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ contract UbiquityPoolFacet is IUbiquityPool, Modifiers {
return LibUbiquityPool.collateralInformation(collateralAddress);
}

/// @inheritdoc IUbiquityPool
function collateralRatio() external view returns (uint256) {
return LibUbiquityPool.collateralRatio();
}

/// @inheritdoc IUbiquityPool
function collateralUsdBalance()
external
Expand All @@ -41,6 +46,15 @@ contract UbiquityPoolFacet is IUbiquityPool, Modifiers {
return LibUbiquityPool.collateralUsdBalance();
}

/// @inheritdoc IUbiquityPool
function ethUsdPriceFeedInformation()
external
view
returns (address, uint256)
{
return LibUbiquityPool.ethUsdPriceFeedInformation();
}

/// @inheritdoc IUbiquityPool
function freeCollateralBalance(
uint256 collateralIndex
Expand Down Expand Up @@ -69,6 +83,15 @@ contract UbiquityPoolFacet is IUbiquityPool, Modifiers {
return LibUbiquityPool.getDollarPriceUsd();
}

/// @inheritdoc IUbiquityPool
function getGovernancePriceUsd()
external
view
returns (uint256 governancePriceUsd)
{
return LibUbiquityPool.getGovernancePriceUsd();
}

/// @inheritdoc IUbiquityPool
function getRedeemCollateralBalance(
address userAddress,
Expand All @@ -81,6 +104,18 @@ contract UbiquityPoolFacet is IUbiquityPool, Modifiers {
);
}

/// @inheritdoc IUbiquityPool
function getRedeemGovernanceBalance(
address userAddress
) external view returns (uint256) {
return LibUbiquityPool.getRedeemGovernanceBalance(userAddress);
}

/// @inheritdoc IUbiquityPool
function governanceEthPoolAddress() external view returns (address) {
return LibUbiquityPool.governanceEthPoolAddress();
}

//====================
// Public functions
//====================
Expand All @@ -90,39 +125,57 @@ contract UbiquityPoolFacet is IUbiquityPool, Modifiers {
uint256 collateralIndex,
uint256 dollarAmount,
uint256 dollarOutMin,
uint256 maxCollateralIn
uint256 maxCollateralIn,
uint256 maxGovernanceIn,
bool isOneToOne
)
external
nonReentrant
returns (uint256 totalDollarMint, uint256 collateralNeeded)
returns (
uint256 totalDollarMint,
uint256 collateralNeeded,
uint256 governanceNeeded
)
{
return
LibUbiquityPool.mintDollar(
collateralIndex,
dollarAmount,
dollarOutMin,
maxCollateralIn
maxCollateralIn,
maxGovernanceIn,
isOneToOne
);
}

/// @inheritdoc IUbiquityPool
function redeemDollar(
uint256 collateralIndex,
uint256 dollarAmount,
uint256 governanceOutMin,
uint256 collateralOutMin
) external nonReentrant returns (uint256 collateralOut) {
)
external
nonReentrant
returns (uint256 collateralOut, uint256 governanceOut)
{
return
LibUbiquityPool.redeemDollar(
collateralIndex,
dollarAmount,
governanceOutMin,
collateralOutMin
);
}

/// @inheritdoc IUbiquityPool
function collectRedemption(
uint256 collateralIndex
) external nonReentrant returns (uint256 collateralAmount) {
)
external
nonReentrant
returns (uint256 governanceAmount, uint256 collateralAmount)
{
return LibUbiquityPool.collectRedemption(collateralIndex);
}

Expand Down Expand Up @@ -180,6 +233,22 @@ contract UbiquityPoolFacet is IUbiquityPool, Modifiers {
);
}

/// @inheritdoc IUbiquityPool
function setCollateralRatio(uint256 newCollateralRatio) external onlyAdmin {
LibUbiquityPool.setCollateralRatio(newCollateralRatio);
}

/// @inheritdoc IUbiquityPool
function setEthUsdChainLinkPriceFeed(
address newPriceFeedAddress,
uint256 newStalenessThreshold
) external onlyAdmin {
LibUbiquityPool.setEthUsdChainLinkPriceFeed(
newPriceFeedAddress,
newStalenessThreshold
);
}

/// @inheritdoc IUbiquityPool
function setFees(
uint256 collateralIndex,
Expand All @@ -189,6 +258,15 @@ contract UbiquityPoolFacet is IUbiquityPool, Modifiers {
LibUbiquityPool.setFees(collateralIndex, newMintFee, newRedeemFee);
}

/// @inheritdoc IUbiquityPool
function setGovernanceEthPoolAddress(
address newGovernanceEthPoolAddress
) external onlyAdmin {
LibUbiquityPool.setGovernanceEthPoolAddress(
newGovernanceEthPoolAddress
);
}

/// @inheritdoc IUbiquityPool
function setPoolCeiling(
uint256 collateralIndex,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {ICurveStableSwapMetaNG} from "./ICurveStableSwapMetaNG.sol";

/**
* @notice Curve's CurveTwocryptoOptimized interface
*
* @dev Differences between Curve's crypto and stable swap meta pools (and how Ubiquity organization uses them):
* 1. They contain different tokens:
* a) Curve's stable swap metapool containts Dollar/3CRVLP pair
* b) Curve's crypto pool contains Governance/ETH pair
* 2. They use different bonding curve shapes:
* a) Curve's stable swap metapool is more straight (because underlying tokens are pegged to USD)
* b) Curve's crypto pool resembles Uniswap's bonding curve (because underlying tokens are not USD pegged)
* 3. The `price_oracle()` method works differently:
* a) Curve's stable swap metapool `price_oracle(uint256 i)` accepts coin index parameter
* b) Curve's crypto pool `price_oracle()` doesn't accept coin index parameter and always returns oracle price for coin at index 1
*
* @dev Basically `ICurveTwocryptoOptimized` has the same interface as `ICurveStableSwapMetaNG`
* but we distinguish them in the code for clarity.
*/
interface ICurveTwocryptoOptimized is ICurveStableSwapMetaNG {
/**
* @notice Getter for the oracle price of the coin at index 1 with regard to the coin at index 0.
* The price oracle is an exponential moving average with a periodicity determined by `ma_time`.
* @return Price oracle
*/
function price_oracle() external view returns (uint256);
}
112 changes: 105 additions & 7 deletions packages/contracts/src/dollar/interfaces/IUbiquityPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ interface IUbiquityPool {
view
returns (LibUbiquityPool.CollateralInformation memory returnData);

/**
* @notice Returns current collateral ratio
* @return Collateral ratio
*/
function collateralRatio() external view returns (uint256);

/**
* @notice Returns USD value of all collateral tokens held in the pool, in E18
* @return balanceTally USD value of all collateral tokens
Expand All @@ -41,6 +47,15 @@ interface IUbiquityPool {
view
returns (uint256 balanceTally);

/**
* @notice Returns chainlink price feed information for ETH/USD pair
* @return Price feed address and staleness threshold in seconds
*/
function ethUsdPriceFeedInformation()
external
view
returns (address, uint256);

/**
* @notice Returns free collateral balance (i.e. that can be borrowed by AMO minters)
* @param collateralIndex collateral token index
Expand All @@ -67,6 +82,19 @@ interface IUbiquityPool {
*/
function getDollarPriceUsd() external view returns (uint256 dollarPriceUsd);

/**
* @notice Returns Governance token price in USD (6 decimals precision)
* @dev How it works:
* 1. Fetch ETH/USD price from chainlink oracle
* 2. Fetch Governance/ETH price from Curve's oracle
* 3. Calculate Governance token price in USD
* @return governancePriceUsd Governance token price in USD
*/
function getGovernancePriceUsd()
external
view
returns (uint256 governancePriceUsd);

/**
* @notice Returns user's balance available for redemption
* @param userAddress User address
Expand All @@ -78,6 +106,21 @@ interface IUbiquityPool {
uint256 collateralIndex
) external view returns (uint256);

/**
* @notice Returns user's Governance tokens balance available for redemption
* @param userAddress User address
* @return User's Governance tokens balance available for redemption
*/
function getRedeemGovernanceBalance(
address userAddress
) external view returns (uint256);

/**
* @notice Returns pool address for Governance/ETH pair
* @return Pool address
*/
function governanceEthPoolAddress() external view returns (address);

//====================
// Public functions
//====================
Expand All @@ -88,15 +131,26 @@ interface IUbiquityPool {
* @param dollarAmount Amount of dollars to mint
* @param dollarOutMin Min amount of dollars to mint (slippage protection)
* @param maxCollateralIn Max amount of collateral to send (slippage protection)
* @param maxGovernanceIn Max amount of Governance tokens to send (slippage protection)
* @param isOneToOne Force providing only collateral without Governance tokens
* @return totalDollarMint Amount of Dollars minted
* @return collateralNeeded Amount of collateral sent to the pool
* @return governanceNeeded Amount of Governance tokens burnt from sender
*/
function mintDollar(
uint256 collateralIndex,
uint256 dollarAmount,
uint256 dollarOutMin,
uint256 maxCollateralIn
) external returns (uint256 totalDollarMint, uint256 collateralNeeded);
uint256 maxCollateralIn,
uint256 maxGovernanceIn,
bool isOneToOne
)
external
returns (
uint256 totalDollarMint,
uint256 collateralNeeded,
uint256 governanceNeeded
);

/**
* @notice Burns redeemable Ubiquity Dollars and sends back 1 USD of collateral token for every 1 Ubiquity Dollar burned
Expand All @@ -106,14 +160,16 @@ interface IUbiquityPool {
* @dev This is done in order to prevent someone using a flash loan of a collateral token to mint, redeem, and collect in a single transaction/block
* @param collateralIndex Collateral token index being withdrawn
* @param dollarAmount Amount of Ubiquity Dollars being burned
* @param governanceOutMin Minimum amount of Governance tokens that'll be withdrawn, used to set acceptable slippage
* @param collateralOutMin Minimum amount of collateral tokens that'll be withdrawn, used to set acceptable slippage
* @return collateralOut Amount of collateral tokens ready for redemption
*/
function redeemDollar(
uint256 collateralIndex,
uint256 dollarAmount,
uint256 governanceOutMin,
uint256 collateralOutMin
) external returns (uint256 collateralOut);
) external returns (uint256 collateralOut, uint256 governanceOut);

/**
* @notice Used to collect collateral tokens after redeeming/burning Ubiquity Dollars
Expand All @@ -122,11 +178,18 @@ interface IUbiquityPool {
* @dev 2. `collectRedemption()`
* @dev This is done in order to prevent someone using a flash loan of a collateral token to mint, redeem, and collect in a single transaction/block
* @param collateralIndex Collateral token index being collected
* @return governanceAmount Amount of Governance tokens redeemed
* @return collateralAmount Amount of collateral tokens redeemed
*/
function collectRedemption(
uint256 collateralIndex
) external returns (uint256 collateralAmount);
) external returns (uint256 governanceAmount, uint256 collateralAmount);

/**
* @notice Updates collateral token price in USD from ChainLink price feed
* @param collateralIndex Collateral token index
*/
function updateChainLinkCollateralPrice(uint256 collateralIndex) external;

//=========================
// AMO minters functions
Expand Down Expand Up @@ -181,10 +244,30 @@ interface IUbiquityPool {
) external;

/**
* @notice Updates collateral token price in USD from ChainLink price feed
* @param collateralIndex Collateral token index
* @notice Sets collateral ratio
* @dev How much collateral/governance tokens user should provide/get to mint/redeem Dollar tokens, 1e6 precision
*
* @dev Example (1_000_000 = 100%):
* - Mint: user provides 1 collateral token to get 1 Dollar
* - Redeem: user gets 1 collateral token for 1 Dollar
*
* @dev Example (900_000 = 90%):
* - Mint: user provides 0.9 collateral token and 0.1 Governance token to get 1 Dollar
* - Redeem: user gets 0.9 collateral token and 0.1 Governance token for 1 Dollar
*
* @param newCollateralRatio New collateral ratio
*/
function updateChainLinkCollateralPrice(uint256 collateralIndex) external;
function setCollateralRatio(uint256 newCollateralRatio) external;

/**
* @notice Sets chainlink params for ETH/USD price feed
* @param newPriceFeedAddress New chainlink price feed address for ETH/USD pair
* @param newStalenessThreshold New threshold in seconds when chainlink's ETH/USD price feed answer should be considered stale
*/
function setEthUsdChainLinkPriceFeed(
address newPriceFeedAddress,
uint256 newStalenessThreshold
) external;

/**
* @notice Sets mint and redeem fees, 1_000_000 = 100%
Expand All @@ -198,6 +281,21 @@ interface IUbiquityPool {
uint256 newRedeemFee
) external;

/**
* @notice Sets a new pool address for Governance/ETH pair
*
* @dev Based on Curve's CurveTwocryptoOptimized contract. Used for fetching Governance token USD price.
* How it works:
* 1. Fetch Governance/ETH price from CurveTwocryptoOptimized's built-in oracle
* 2. Fetch ETH/USD price from chainlink feed
* 3. Calculate Governance token price in USD
*
* @param newGovernanceEthPoolAddress New pool address for Governance/ETH pair
*/
function setGovernanceEthPoolAddress(
address newGovernanceEthPoolAddress
) external;

/**
* @notice Sets max amount of collateral for a particular collateral token
* @param collateralIndex Collateral token index
Expand Down
Loading

0 comments on commit 92bc566

Please sign in to comment.