Skip to content

Commit

Permalink
feat: add ICurveStableSwapNG (#933)
Browse files Browse the repository at this point in the history
* feat: add ICurveStableSwapNG

* feat: add plain pool setter

* feat: add stable/ETH setter

* feat: fetch Dollar price

* feat: add Stable/USD setter
  • Loading branch information
rndquu committed Apr 24, 2024
1 parent ca2ec33 commit 8aaa03c
Show file tree
Hide file tree
Showing 9 changed files with 307 additions and 38 deletions.
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
1 change: 1 addition & 0 deletions packages/contracts/src/dollar/libraries/LibAppStorage.sol
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

0 comments on commit 8aaa03c

Please sign in to comment.