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: add ICurveStableSwapNG #933

Merged
merged 5 commits into from
Apr 24, 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
19 changes: 19 additions & 0 deletions packages/contracts/src/dollar/facets/ManagerFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,17 @@ contract ManagerFacet is Modifiers {
store.stableSwapMetaPoolAddress = _stableSwapMetaPoolAddress;
}

/**
* @notice Sets Curve's Dollar-Stablecoin plain pool address
* @dev `_stableSwapPlainPoolAddress` is used to fetch Dollar price in USD
* @param _stableSwapPlainPoolAddress Curve's Dollar-Stablecoin plain pool address
*/
function setStableSwapPlainPoolAddress(
address _stableSwapPlainPoolAddress
) external onlyAdmin {
store.stableSwapPlainPoolAddress = _stableSwapPlainPoolAddress;
}

/**
* @notice Sets staking contract address
* @dev Staking contract participants deposit Curve LP tokens
Expand Down Expand Up @@ -385,6 +396,14 @@ contract ManagerFacet is Modifiers {
return store.stableSwapMetaPoolAddress;
}

/**
* @notice Returns Curve's plain pool address for Dollar-Stablecoin pair
* @return Curve's plain pool address for Dollar-Stablecoin pair
*/
function stableSwapPlainPoolAddress() external view returns (address) {
return store.stableSwapPlainPoolAddress;
}

/**
* @notice Returns staking address
* @return Staking address
Expand Down
20 changes: 20 additions & 0 deletions packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,15 @@ contract UbiquityPoolFacet is IUbiquityPool, Modifiers {
return LibUbiquityPool.governanceEthPoolAddress();
}

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

//====================
// Public functions
//====================
Expand Down Expand Up @@ -293,6 +302,17 @@ contract UbiquityPoolFacet is IUbiquityPool, Modifiers {
LibUbiquityPool.setRedemptionDelayBlocks(newRedemptionDelayBlocks);
}

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

/// @inheritdoc IUbiquityPool
function toggleCollateral(uint256 collateralIndex) external onlyAdmin {
LibUbiquityPool.toggleCollateral(collateralIndex);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

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

/**
* @notice Curve's interface for plain pool which contains only USD pegged assets
*/
interface ICurveStableSwapNG is ICurveStableSwapMetaNG {}
21 changes: 21 additions & 0 deletions packages/contracts/src/dollar/interfaces/IUbiquityPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,16 @@ interface IUbiquityPool {
*/
function governanceEthPoolAddress() external view returns (address);

/**
* @notice Returns chainlink price feed information for stable/USD pair
* @dev Here stable coin refers to the 1st coin in the Curve's stable/Dollar plain pool
* @return Price feed address and staleness threshold in seconds
*/
function stableUsdPriceFeedInformation()
external
view
returns (address, uint256);

//====================
// Public functions
//====================
Expand Down Expand Up @@ -328,6 +338,17 @@ interface IUbiquityPool {
uint256 newRedemptionDelayBlocks
) external;

/**
* @notice Sets chainlink params for stable/USD price feed
* @dev Here stable coin refers to the 1st coin in the Curve's stable/Dollar plain pool
* @param newPriceFeedAddress New chainlink price feed address for stable/USD pair
* @param newStalenessThreshold New threshold in seconds when chainlink's stable/USD price feed answer should be considered stale
*/
function setStableUsdChainLinkPriceFeed(
address newPriceFeedAddress,
uint256 newStalenessThreshold
) external;

/**
* @notice Toggles (i.e. enables/disables) a particular collateral token
* @param collateralIndex Collateral token index
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct AppStorage {
address stakingShareAddress;
address stakingContractAddress;
address stableSwapMetaPoolAddress;
address stableSwapPlainPoolAddress;
address curve3PoolTokenAddress; // 3CRV
address treasuryAddress;
address governanceTokenAddress;
Expand Down
88 changes: 82 additions & 6 deletions packages/contracts/src/dollar/libraries/LibUbiquityPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol";
import {ICurveStableSwapMetaNG} from "../interfaces/ICurveStableSwapMetaNG.sol";
import {ICurveStableSwapNG} from "../interfaces/ICurveStableSwapNG.sol";
import {ICurveTwocryptoOptimized} from "../interfaces/ICurveTwocryptoOptimized.sol";
import {IDollarAmoMinter} from "../interfaces/IDollarAmoMinter.sol";
import {IERC20Ubiquity} from "../interfaces/IERC20Ubiquity.sol";
Expand Down Expand Up @@ -103,6 +103,13 @@ library LibUbiquityPool {
uint256 ethUsdPriceFeedStalenessThreshold;
// Curve's CurveTwocryptoOptimized contract for Governance/ETH pair
address governanceEthPoolAddress;
//================================
// Dollar token pricing related
//================================
// chainlink price feed for stable/USD pair
address stableUsdPriceFeedAddress;
// threshold in seconds when chainlink's stable/USD price feed answer should be considered stale
uint256 stableUsdPriceFeedStalenessThreshold;
}

/// @notice Struct used for detailed collateral information
Expand Down Expand Up @@ -182,6 +189,11 @@ library LibUbiquityPool {
);
/// @notice Emitted when a new redemption delay in blocks is set
event RedemptionDelayBlocksSet(uint256 redemptionDelayBlocks);
/// @notice Emitted on setting chainlink's price feed for stable/USD pair
event StableUsdPriceFeedSet(
address newPriceFeedAddress,
uint256 newStalenessThreshold
);

//=====================
// Modifiers
Expand Down Expand Up @@ -362,23 +374,51 @@ library LibUbiquityPool {
}

/**
* @notice Returns Ubiquity Dollar token USD price (1e6 precision) from Curve Metapool (Ubiquity Dollar, Curve Tri-Pool LP)
* @notice Returns Ubiquity Dollar token USD price (1e6 precision) from Curve plain pool (Stable coin, Ubiquity Dollar)
* How it works:
* 1. Fetch Stable/USD quote from chainlink
* 2. Fetch Dollar/Stable quote from Curve's plain pool
* 3. Calculate Dollar token price in USD
* @return dollarPriceUsd USD price of Ubiquity Dollar
*/
function getDollarPriceUsd()
internal
view
returns (uint256 dollarPriceUsd)
{
// load storage shared across all libraries
AppStorage storage store = LibAppStorage.appStorage();
// get Dollar price from Curve Metapool (18 decimals)
uint256 dollarPriceUsdD18 = ICurveStableSwapMetaNG(
store.stableSwapMetaPoolAddress
UbiquityPoolStorage storage poolStorage = ubiquityPoolStorage();

// fetch Stable/USD quote from chainlink (8 decimals)
AggregatorV3Interface stableUsdPriceFeed = AggregatorV3Interface(
poolStorage.stableUsdPriceFeedAddress
);
(
,
int256 stableUsdAnswer,
,
uint256 stableUsdUpdatedAt,

) = stableUsdPriceFeed.latestRoundData();
uint256 stableUsdPriceFeedDecimals = stableUsdPriceFeed.decimals();
// validate Stable/USD chainlink response
require(stableUsdAnswer > 0, "Invalid Stable/USD price");
require(
block.timestamp - stableUsdUpdatedAt <
poolStorage.stableUsdPriceFeedStalenessThreshold,
"Stale Stable/USD data"
);

// fetch Dollar/Stable quote from Curve's plain pool (18 decimals)
uint256 dollarPriceUsdD18 = ICurveStableSwapNG(
store.stableSwapPlainPoolAddress
).price_oracle(0);

// convert to 6 decimals
dollarPriceUsd = dollarPriceUsdD18
.mul(UBIQUITY_POOL_PRICE_PRECISION)
.mul(uint256(stableUsdAnswer))
.div(10 ** stableUsdPriceFeedDecimals)
.div(1e18);
}

Expand Down Expand Up @@ -467,6 +507,23 @@ library LibUbiquityPool {
return poolStorage.governanceEthPoolAddress;
}

/**
* @notice Returns chainlink price feed information for stable/USD pair
* @dev Here stable coin refers to the 1st coin in the Curve's stable/Dollar plain pool
* @return Price feed address and staleness threshold in seconds
*/
function stableUsdPriceFeedInformation()
internal
view
returns (address, uint256)
{
UbiquityPoolStorage storage poolStorage = ubiquityPoolStorage();
return (
poolStorage.stableUsdPriceFeedAddress,
poolStorage.stableUsdPriceFeedStalenessThreshold
);
}

//====================
// Public functions
//====================
Expand Down Expand Up @@ -1124,6 +1181,25 @@ library LibUbiquityPool {
emit RedemptionDelayBlocksSet(newRedemptionDelayBlocks);
}

/**
* @notice Sets chainlink params for stable/USD price feed
* @dev Here stable coin refers to the 1st coin in the Curve's stable/Dollar plain pool
* @param newPriceFeedAddress New chainlink price feed address for stable/USD pair
* @param newStalenessThreshold New threshold in seconds when chainlink's stable/USD price feed answer should be considered stale
*/
function setStableUsdChainLinkPriceFeed(
address newPriceFeedAddress,
uint256 newStalenessThreshold
) internal {
UbiquityPoolStorage storage poolStorage = ubiquityPoolStorage();

poolStorage.stableUsdPriceFeedAddress = newPriceFeedAddress;
poolStorage
.stableUsdPriceFeedStalenessThreshold = newStalenessThreshold;

emit StableUsdPriceFeedSet(newPriceFeedAddress, newStalenessThreshold);
}

/**
* @notice Toggles (i.e. enables/disables) a particular collateral token
* @param collateralIndex Collateral token index
Expand Down
15 changes: 15 additions & 0 deletions packages/contracts/src/dollar/mocks/MockCurveStableSwapNG.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {ICurveStableSwapNG} from "../interfaces/ICurveStableSwapNG.sol";
import {MockCurveStableSwapMetaNG} from "./MockCurveStableSwapMetaNG.sol";

contract MockCurveStableSwapNG is
ICurveStableSwapNG,
MockCurveStableSwapMetaNG
{
constructor(
address _token0,
address _token1
) MockCurveStableSwapMetaNG(_token0, _token1) {}
}
8 changes: 8 additions & 0 deletions packages/contracts/test/diamond/facets/ManagerFacet.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ contract ManagerFacetTest is DiamondTestSetup {
assertEq(managerFacet.stableSwapMetaPoolAddress(), contract1);
}

function testSetStableSwapPlainPoolAddress_ShouldSucceed()
public
prankAs(admin)
{
managerFacet.setStableSwapPlainPoolAddress(contract1);
assertEq(managerFacet.stableSwapPlainPoolAddress(), contract1);
}

function testSetStakingContractAddress_ShouldSucceed()
public
prankAs(admin)
Expand Down
Loading
Loading