Skip to content

Commit

Permalink
feat: add governance pool setter
Browse files Browse the repository at this point in the history
  • Loading branch information
rndquu committed Apr 4, 2024
1 parent 527db32 commit d145f3a
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 3 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
14 changes: 14 additions & 0 deletions packages/contracts/src/dollar/facets/UbiquityPoolFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ contract UbiquityPoolFacet is IUbiquityPool, Modifiers {
);
}

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

//====================
// Public functions
//====================
Expand Down Expand Up @@ -199,6 +204,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,20 @@
// 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)
*
* @dev Basically `ICurveTwocryptoOptimized` has the same interface as `ICurveStableSwapMetaNG`
* but we distinguish them in the code for clarity.
*/
interface ICurveTwocryptoOptimized 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 @@ -84,6 +84,12 @@ interface IUbiquityPool {
uint256 collateralIndex
) external view returns (uint256);

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

//====================
// Public functions
//====================
Expand Down Expand Up @@ -220,6 +226,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
37 changes: 37 additions & 0 deletions packages/contracts/src/dollar/libraries/LibUbiquityPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ library LibUbiquityPool {
bool[] isMintPaused;
// whether redeeming is paused for a particular collateral index
bool[] isRedeemPaused;
//====================================
// Governance token pricing related
//====================================
// Curve's CurveTwocryptoOptimized contract for Governance/ETH pair
address governanceEthPoolAddress;
}

/// @notice Struct used for detailed collateral information
Expand Down Expand Up @@ -150,6 +155,8 @@ library LibUbiquityPool {
uint256 newMintFee,
uint256 newRedeemFee
);
/// @notice Emitted on setting a pool for Governance/ETH pair
event GovernanceEthPoolSet(address newGovernanceEthPoolAddress);
/// @notice Emitted on toggling pause for mint/redeem/borrow
event MintRedeemBorrowToggled(uint256 collateralIndex, uint8 toggleIndex);
/// @notice Emitted when new pool ceiling (i.e. max amount of collateral) is set
Expand Down Expand Up @@ -360,6 +367,15 @@ library LibUbiquityPool {
poolStorage.redeemCollateralBalances[userAddress][collateralIndex];
}

/**
* @notice Returns pool address for Governance/ETH pair
* @return Pool address
*/
function governanceEthPoolAddress() internal view returns (address) {
UbiquityPoolStorage storage poolStorage = ubiquityPoolStorage();
return poolStorage.governanceEthPoolAddress;
}

//====================
// Public functions
//====================
Expand Down Expand Up @@ -832,6 +848,27 @@ library LibUbiquityPool {
emit FeesSet(collateralIndex, newMintFee, newRedeemFee);
}

/**
* @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
) internal {
UbiquityPoolStorage storage poolStorage = ubiquityPoolStorage();

poolStorage.governanceEthPoolAddress = newGovernanceEthPoolAddress;

emit GovernanceEthPoolSet(newGovernanceEthPoolAddress);
}

/**
* @notice Sets max amount of collateral for a particular collateral token
* @param collateralIndex Collateral token index
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

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

contract MockCurveTwocryptoOptimized is
ICurveTwocryptoOptimized,
MockCurveStableSwapMetaNG
{
constructor(
address _token0,
address _token1
) MockCurveStableSwapMetaNG(_token0, _token1) {}
}
54 changes: 51 additions & 3 deletions packages/contracts/test/diamond/facets/UbiquityPoolFacet.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {LibUbiquityPool} from "../../../src/dollar/libraries/LibUbiquityPool.sol
import {MockChainLinkFeed} from "../../../src/dollar/mocks/MockChainLinkFeed.sol";
import {MockERC20} from "../../../src/dollar/mocks/MockERC20.sol";
import {MockCurveStableSwapMetaNG} from "../../../src/dollar/mocks/MockCurveStableSwapMetaNG.sol";
import {MockCurveTwocryptoOptimized} from "../../../src/dollar/mocks/MockCurveTwocryptoOptimized.sol";

contract MockDollarAmoMinter is IDollarAmoMinter {
function collateralDollarBalance() external pure returns (uint256) {
Expand All @@ -24,7 +25,9 @@ contract UbiquityPoolFacetTest is DiamondTestSetup {
MockERC20 collateralToken;
MockChainLinkFeed collateralTokenPriceFeed;
MockCurveStableSwapMetaNG curveDollarMetaPool;
MockCurveTwocryptoOptimized curveGovernanceEthPool;
MockERC20 curveTriPoolLpToken;
MockERC20 wethToken;

address user = address(1);

Expand All @@ -44,6 +47,7 @@ contract UbiquityPoolFacetTest is DiamondTestSetup {
uint256 newMintFee,
uint256 newRedeemFee
);
event GovernanceEthPoolSet(address newGovernanceEthPoolAddress);
event MintRedeemBorrowToggled(uint256 collateralIndex, uint8 toggleIndex);
event PoolCeilingSet(uint256 collateralIndex, uint256 newCeiling);
event PriceThresholdsSet(
Expand All @@ -63,6 +67,9 @@ contract UbiquityPoolFacetTest is DiamondTestSetup {
// init collateral price feed
collateralTokenPriceFeed = new MockChainLinkFeed();

// init WETH token
wethToken = new MockERC20("WETH", "WETH", 18);

// init Curve 3CRV-LP token
curveTriPoolLpToken = new MockERC20("3CRV", "3CRV", 18);

Expand All @@ -72,6 +79,12 @@ contract UbiquityPoolFacetTest is DiamondTestSetup {
address(curveTriPoolLpToken)
);

// init Curve Governance-WETH crypto pool
curveGovernanceEthPool = new MockCurveTwocryptoOptimized(
address(governanceToken),
address(wethToken)
);

// add collateral token to the pool
uint256 poolCeiling = 50_000e18; // max 50_000 of collateral tokens is allowed
ubiquityPoolFacet.addCollateralToken(
Expand All @@ -96,9 +109,6 @@ contract UbiquityPoolFacetTest is DiamondTestSetup {
1 days // price feed staleness threshold in seconds
);

// set collateral ratio to 100%
ubiquityPoolFacet.setCollateralRatio(1_000_000);

// enable collateral at index 0
ubiquityPoolFacet.toggleCollateral(0);
// set mint and redeem fees
Expand All @@ -111,6 +121,12 @@ contract UbiquityPoolFacetTest is DiamondTestSetup {
ubiquityPoolFacet.setRedemptionDelayBlocks(2);
// set mint price threshold to $1.01 and redeem price to $0.99
ubiquityPoolFacet.setPriceThresholds(1010000, 990000);
// set collateral ratio to 100%
ubiquityPoolFacet.setCollateralRatio(1_000_000);
// set Governance-ETH pool
ubiquityPoolFacet.setGovernanceEthPoolAddress(
address(curveGovernanceEthPool)
);

// init AMO minter
dollarAmoMinter = new MockDollarAmoMinter();
Expand Down Expand Up @@ -303,6 +319,14 @@ contract UbiquityPoolFacetTest is DiamondTestSetup {
assertEq(redeemCollateralBalance, 97.02e18);
}

function testGovernanceEthPoolAddress_ShouldReturnGovernanceEthPoolAddress()
public
{
address governanceEthPoolAddress = ubiquityPoolFacet
.governanceEthPoolAddress();
assertEq(governanceEthPoolAddress, address(curveGovernanceEthPool));
}

//====================
// Public functions
//====================
Expand Down Expand Up @@ -918,6 +942,30 @@ contract UbiquityPoolFacetTest is DiamondTestSetup {
vm.stopPrank();
}

function testSetGovernanceEthPoolAddress_ShouldSetGovernanceEthPoolAddress()
public
{
vm.startPrank(admin);

address oldGovernanceEthPoolAddress = ubiquityPoolFacet
.governanceEthPoolAddress();
assertEq(oldGovernanceEthPoolAddress, address(curveGovernanceEthPool));

address newGovernanceEthPoolAddress = address(1);
vm.expectEmit(address(ubiquityPoolFacet));
emit GovernanceEthPoolSet(newGovernanceEthPoolAddress);
ubiquityPoolFacet.setGovernanceEthPoolAddress(
newGovernanceEthPoolAddress
);

assertEq(
ubiquityPoolFacet.governanceEthPoolAddress(),
newGovernanceEthPoolAddress
);

vm.stopPrank();
}

function testSetPoolCeiling_ShouldSetMaxAmountOfTokensAllowedForCollateral()
public
{
Expand Down

0 comments on commit d145f3a

Please sign in to comment.