Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/fractional pool #922

Merged
merged 7 commits into from
Apr 6, 2024
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
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()
gitcoindev marked this conversation as resolved.
Show resolved Hide resolved
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()
gitcoindev marked this conversation as resolved.
Show resolved Hide resolved
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
Loading