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 plain pool migration #935

Merged
merged 2 commits into from
Apr 26, 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
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ COLLATERAL_TOKEN_ADDRESS="0x5f98805A4E8be255a32880FDeC7F6728C6568bA0"

# Collateral token price feed address from chainlink.
# By default set to LUSD/USD price feed deployed on ethereum mainnet.
# This price feed is used in 2 cases:
# 1) To calculate collateral price in USD
# 2) To calculate Dollar price in USD
# Since collateral token (LUSD) is the same one used in Curve's plain pool (LUSD-Dollar)
# we share the same price feed in:
# 1) `LibUbiquityPool.setCollateralChainLinkPriceFeed()` (to calculate collateral price in USD)
# 2) `LibUbiquityPool.setStableUsdChainLinkPriceFeed()` (to calculate Dollar price in USD)
# - mainnet: uses already deployed LUSD/USD chainlink price feed
# - testnet/anvil: deploys LUSD/USD chainlink price feed from scratch
COLLATERAL_TOKEN_CHAINLINK_PRICE_FEED_ADDRESS="0x3D7aE7E594f2f2091Ad8798313450130d0Aba3a0"
Expand All @@ -110,7 +117,7 @@ CURVE_GOVERNANCE_WETH_POOL_ADDRESS="0xaCDc85AFCD8B83Eb171AFFCbe29FaD204F6ae45C"
# - testnet/anvil: deploys ETH/USD chainlink price feed from scratch
ETH_USD_CHAINLINK_PRICE_FEED_ADDRESS="0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419"

# Dollar amount in wei minted initially to provide liquidity to the Dollar-3CRV metapool
# Dollar amount in wei minted initially to owner to provide liquidity to the Curve LUSD-Dollar plain pool
# By default set to 25k Dollar tokens
INITIAL_DOLLAR_MINT_AMOUNT_WEI="25000000000000000000000"

Expand Down
9 changes: 8 additions & 1 deletion packages/contracts/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ COLLATERAL_TOKEN_ADDRESS="0x5f98805A4E8be255a32880FDeC7F6728C6568bA0"

# Collateral token price feed address from chainlink.
# By default set to LUSD/USD price feed deployed on ethereum mainnet.
# This price feed is used in 2 cases:
# 1) To calculate collateral price in USD
# 2) To calculate Dollar price in USD
# Since collateral token (LUSD) is the same one used in Curve's plain pool (LUSD-Dollar)
# we share the same price feed in:
# 1) `LibUbiquityPool.setCollateralChainLinkPriceFeed()` (to calculate collateral price in USD)
# 2) `LibUbiquityPool.setStableUsdChainLinkPriceFeed()` (to calculate Dollar price in USD)
# - mainnet: uses already deployed LUSD/USD chainlink price feed
# - testnet/anvil: deploys LUSD/USD chainlink price feed from scratch
COLLATERAL_TOKEN_CHAINLINK_PRICE_FEED_ADDRESS="0x3D7aE7E594f2f2091Ad8798313450130d0Aba3a0"
Expand All @@ -29,7 +36,7 @@ CURVE_GOVERNANCE_WETH_POOL_ADDRESS="0xaCDc85AFCD8B83Eb171AFFCbe29FaD204F6ae45C"
# - testnet/anvil: deploys ETH/USD chainlink price feed from scratch
ETH_USD_CHAINLINK_PRICE_FEED_ADDRESS="0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419"

# Dollar amount in wei minted initially to provide liquidity to the Dollar-3CRV metapool
# Dollar amount in wei minted initially to owner to provide liquidity to the Curve LUSD-Dollar plain pool
# By default set to 25k Dollar tokens
INITIAL_DOLLAR_MINT_AMOUNT_WEI="25000000000000000000000"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {DiamondLoupeFacet} from "../../src/dollar/facets/DiamondLoupeFacet.sol";
import {ManagerFacet} from "../../src/dollar/facets/ManagerFacet.sol";
import {OwnershipFacet} from "../../src/dollar/facets/OwnershipFacet.sol";
import {UbiquityPoolFacet} from "../../src/dollar/facets/UbiquityPoolFacet.sol";
import {ICurveStableSwapMetaNG} from "../../src/dollar/interfaces/ICurveStableSwapMetaNG.sol";
import {ICurveStableSwapNG} from "../../src/dollar/interfaces/ICurveStableSwapNG.sol";
import {ICurveTwocryptoOptimized} from "../../src/dollar/interfaces/ICurveTwocryptoOptimized.sol";
import {IDiamondCut} from "../../src/dollar/interfaces/IDiamondCut.sol";
import {IDiamondLoupe} from "../../src/dollar/interfaces/IDiamondLoupe.sol";
Expand All @@ -26,7 +26,7 @@ import {LibAccessControl} from "../../src/dollar/libraries/LibAccessControl.sol"
import {AppStorage, LibAppStorage, Modifiers} from "../../src/dollar/libraries/LibAppStorage.sol";
import {LibDiamond} from "../../src/dollar/libraries/LibDiamond.sol";
import {MockChainLinkFeed} from "../../src/dollar/mocks/MockChainLinkFeed.sol";
import {MockCurveStableSwapMetaNG} from "../../src/dollar/mocks/MockCurveStableSwapMetaNG.sol";
import {MockCurveStableSwapNG} from "../../src/dollar/mocks/MockCurveStableSwapNG.sol";
import {MockCurveTwocryptoOptimized} from "../../src/dollar/mocks/MockCurveTwocryptoOptimized.sol";
import {MockERC20} from "../../src/dollar/mocks/MockERC20.sol";
import {DiamondTestHelper} from "../../test/helpers/DiamondTestHelper.sol";
Expand Down Expand Up @@ -129,8 +129,7 @@ contract Deploy001_Diamond_Dollar_Governance is Script, DiamondTestHelper {
// oracle related contracts
AggregatorV3Interface chainLinkPriceFeedEth; // chainlink ETH/USD price feed
AggregatorV3Interface chainLinkPriceFeedLusd; // chainlink LUSD/USD price feed
IERC20 curveTriPoolLpToken; // Curve's 3CRV-LP token
ICurveStableSwapMetaNG curveDollarMetaPool; // Curve's Dollar-3CRVLP metapool
ICurveStableSwapNG curveStableDollarPlainPool; // Curve's LUSD-Dollar plain pool
ICurveTwocryptoOptimized curveGovernanceEthPool; // Curve's Governance-WETH crypto pool

// collateral ERC20 token used in UbiquityPoolFacet
Expand Down Expand Up @@ -408,22 +407,22 @@ contract Deploy001_Diamond_Dollar_Governance is Script, DiamondTestHelper {
* - oracle related contracts
* - Governance token related contracts
*
* @dev Ubiquity protocol supports 4 oracles:
* 1. Curve's Dollar-3CRVLP metapool to fetch Dollar prices
* 2. Chainlink's price feed (used in UbiquityPool) to fetch collateral token prices in USD
* 3. Chainlink's price feed (used in UbiquityPool) to fetch ETH/USD price
* 4. Curve's Governance-WETH crypto pool to fetch Governance/ETH price
* @dev Ubiquity protocol supports 5 oracles:
* 1. Curve's LUSD-Dollar plain pool to fetch Dollar prices
* 2. Chainlink's price feed (used in UbiquityPool) to fetch LUSD/USD price (for getting Dollar price in USD)
* 3. Chainlink's price feed (used in UbiquityPool) to fetch collateral token prices in USD (for getting collateral price in USD)
* 4. Chainlink's price feed (used in UbiquityPool) to fetch ETH/USD price
* 5. Curve's Governance-WETH crypto pool to fetch Governance/ETH price
*
* There are 2 migrations (deployment scripts):
* 1. Development (for usage in testnet and local anvil instance)
* 2. Mainnet (for production usage in mainnet)
*
* Development migration deploys (for ease of debugging) mocks of:
* - Chainlink collateral price feed contract
* - Chainlink ETH/USD price feed contract
* - 3CRVLP ERC20 token
* - Chainlink LUSD/USD price feed contract (for getting Dollar and collateral prices in USD)
* - WETH token
* - Curve's Dollar-3CRVLP metapool contract
* - Curve's LUSD-Dollar plain pool contract
* - Curve's Governance-WETH crypto pool contract
*/
function afterRun() public virtual {
Expand Down Expand Up @@ -464,7 +463,7 @@ contract Deploy001_Diamond_Dollar_Governance is Script, DiamondTestHelper {
1 // answered in round
);

// set price feed address and threshold in seconds
// set collateral price feed address and threshold in seconds
ubiquityPoolFacet.setCollateralChainLinkPriceFeed(
address(collateralToken), // collateral token address
address(chainLinkPriceFeedLusd), // price feed address
Expand All @@ -474,41 +473,45 @@ contract Deploy001_Diamond_Dollar_Governance is Script, DiamondTestHelper {
// fetch latest prices from chainlink for collateral with index 0
ubiquityPoolFacet.updateChainLinkCollateralPrice(0);

// set Stable/USD price feed address and threshold in seconds
ubiquityPoolFacet.setStableUsdChainLinkPriceFeed(
address(chainLinkPriceFeedLusd), // price feed address
CHAINLINK_PRICE_FEED_THRESHOLD // price feed staleness threshold in seconds
);

// stop sending admin transactions
vm.stopBroadcast();

//=========================================
// Curve's Dollar-3CRVLP metapool deploy
// Curve's LUSD-Dollar plain pool deploy
//=========================================

// start sending owner transactions
vm.startBroadcast(ownerPrivateKey);

// deploy mock 3CRV-LP token
curveTriPoolLpToken = new MockERC20(
"Curve.fi DAI/USDC/USDT",
"3Crv",
18
);

// deploy mock Curve's Dollar-3CRVLP metapool
curveDollarMetaPool = new MockCurveStableSwapMetaNG(
address(dollarToken),
address(curveTriPoolLpToken)
// Deploy mock Curve's LUSD-Dollar plain pool.
// Since we're using LUSD both as collateral and Dollar token pair
// in Curve's plain pool we don't deploy another mock of the "stable" coin
// paired to Dollar and simply use collateral token (i.e. LUSD).
curveStableDollarPlainPool = new MockCurveStableSwapNG(
address(collateralToken),
address(dollarToken)
);

// stop sending owner transactions
vm.stopBroadcast();

//========================================
// Curve's Dollar-3CRVLP metapool setup
// Curve's LUSD-Dollar plain pool setup
//========================================

// start sending admin transactions
vm.startBroadcast(adminPrivateKey);

// set curve's metapool in manager facet
managerFacet.setStableSwapMetaPoolAddress(address(curveDollarMetaPool));
// set curve's plain pool in manager facet
managerFacet.setStableSwapPlainPoolAddress(
address(curveStableDollarPlainPool)
);

// stop sending admin transactions
vm.stopBroadcast();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,20 @@ contract Deploy001_Diamond_Dollar_Governance is
* we need to use already deployed contracts while `Deploy001_Diamond_Dollar_Governance_Development`
* deploys all oracle and Governance token related contracts from scratch for ease of debugging.
*
* @dev Ubiquity protocol supports 4 oracles:
* 1. Curve's Dollar-3CRVLP metapool to fetch Dollar prices
* 2. Chainlink's price feed (used in UbiquityPool) to fetch collateral token prices in USD
* 3. Chainlink's price feed (used in UbiquityPool) to fetch ETH/USD price
* 4. Curve's Governance-WETH crypto pool to fetch Governance/ETH price
* @dev Ubiquity protocol supports 5 oracles:
* 1. Curve's LUSD-Dollar plain pool to fetch Dollar prices
* 2. Chainlink's price feed (used in UbiquityPool) to fetch LUSD/USD price (for getting Dollar price in USD)
* 3. Chainlink's price feed (used in UbiquityPool) to fetch collateral token prices in USD (for getting collateral price in USD)
* 4. Chainlink's price feed (used in UbiquityPool) to fetch ETH/USD price
* 5. Curve's Governance-WETH crypto pool to fetch Governance/ETH price
*
* There are 2 migrations (deployment scripts):
* 1. Development (for usage in testnet and local anvil instance)
* 2. Mainnet (for production usage in mainnet)
*
* Mainnet (i.e. production) migration uses already deployed contracts for:
* - Chainlink collateral price feed contract
* - Chainlink Stable/USD price feed contract (here "Stable" refers to the LUSD token from Curve's LUSD-Dollar plain pool)
* - UbiquityAlgorithmicDollarManager contract
* - UbiquityGovernance token contract
* - Chainlink ETH/USD price feed
Expand Down Expand Up @@ -104,7 +106,7 @@ contract Deploy001_Diamond_Dollar_Governance is
chainlinkPriceFeedAddressLusd
);

// set price feed
// set collateral price feed
ubiquityPoolFacet.setCollateralChainLinkPriceFeed(
address(collateralToken), // collateral token address
address(chainLinkPriceFeedLusd), // price feed address
Expand All @@ -114,46 +116,68 @@ contract Deploy001_Diamond_Dollar_Governance is
// fetch latest prices from chainlink for collateral with index 0
ubiquityPoolFacet.updateChainLinkCollateralPrice(0);

// set Stable/Dollar price feed
ubiquityPoolFacet.setStableUsdChainLinkPriceFeed(
address(chainLinkPriceFeedLusd), // price feed address
CHAINLINK_PRICE_FEED_THRESHOLD // price feed staleness threshold in seconds
);

// stop sending admin transactions
vm.stopBroadcast();

//=========================================
// Curve's Dollar-3CRVLP metapool deploy
// Curve's LUSD-Dollar plain pool deploy
//=========================================

// start sending owner transactions
vm.startBroadcast(ownerPrivateKey);

// deploy Curve Dollar-3CRV metapool
address curveDollarMetaPoolAddress = ICurveStableSwapFactoryNG(
// prepare parameters
address[] memory plainPoolCoins = new address[](2);
plainPoolCoins[0] = address(collateralToken);
plainPoolCoins[1] = address(dollarToken);

uint8[] memory plainPoolAssetTypes = new uint8[](2);
plainPoolAssetTypes[0] = 0;
plainPoolAssetTypes[1] = 0;

bytes4[] memory plainPoolMethodIds = new bytes4[](2);
plainPoolMethodIds[0] = bytes4("");
plainPoolMethodIds[1] = bytes4("");

address[] memory plainPoolTokenOracleAddresses = new address[](2);
plainPoolTokenOracleAddresses[0] = address(0);
plainPoolTokenOracleAddresses[1] = address(0);

// deploy Curve LUSD-Dollar plain pool
address curveDollarPlainPoolAddress = ICurveStableSwapFactoryNG(
0x6A8cbed756804B16E05E741eDaBd5cB544AE21bf
).deploy_metapool(
0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7, // Curve 3pool (DAI-USDT-USDC) address
"Dollar/3CRV", // pool name
"Dollar3CRV", // LP token symbol
address(dollarToken), // main token
).deploy_plain_pool(
"LUSD/Dollar", // pool name
"LUSDDollar", // LP token symbol
plainPoolCoins, // coins used in the pool
100, // amplification coefficient
40000000, // trade fee, 0.04%
4000000, // trade fee, 0.04%
20000000000, // off-peg fee multiplier
2597, // moving average time value, 2597 = 1800 seconds
0, // metapool implementation index
0, // asset type
"", // method id for oracle asset type (not applicable for Dollar)
address(0) // token oracle address (not applicable for Dollar)
0, // plain pool implementation index
plainPoolAssetTypes, // asset types
plainPoolMethodIds, // method ids for oracle asset type (not applicable for Dollar)
plainPoolTokenOracleAddresses // token oracle addresses (not applicable for Dollar)
);

// stop sending owner transactions
vm.stopBroadcast();

//========================================
// Curve's Dollar-3CRVLP metapool setup
// Curve's LUSD-Dollar plain pool setup
//========================================

// start sending admin transactions
vm.startBroadcast(adminPrivateKey);

// set curve's metapool in manager facet
managerFacet.setStableSwapMetaPoolAddress(curveDollarMetaPoolAddress);
// set curve's plain pool in manager facet
managerFacet.setStableSwapPlainPoolAddress(curveDollarPlainPoolAddress);

// stop sending admin transactions
vm.stopBroadcast();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ interface ICurveStableSwapFactoryNG {
* @param _A Amplification coefficient. If set to 0 then bonding curve acts like Uniswap. Any >0 value
* makes the bonding curve to swap at 1:1 constant price, the more `_A` the longer the constant price period.
* Curve recommends set it to 100 for crypto collateralizard stablecoins. This parameter can be updated later.
* @param _fee Trade fee, given as an integer with 1e10 precision, ex: 40000000 = 0.04% fee
* @param _fee Trade fee, given as an integer with 1e10 precision, ex: 4000000 = 0.04% fee
* @param _offpeg_fee_multiplier Off-peg multiplier. Curve recommends set it to `20000000000`. This parameter can be updated
* later. More info: https://docs.curve.fi/stableswap-exchange/stableswap-ng/pools/overview/#dynamic-fees
* @param _ma_exp_time MA time; set as time_in_seconds / ln(2), ex: 866 = 600 seconds, 2597 = 1800 seconds.
Expand Down Expand Up @@ -54,4 +54,47 @@ interface ICurveStableSwapFactoryNG {
bytes4 _method_id,
address _oracle
) external returns (address);

/**
* @notice Deploys a new plain pool
* @param _name Name of the new plain pool, ex: "LUSD/Dollar"
* @param _symbol Symbol for the new pool's LP token, ex: "LUSDDollar"
* @param _coins Array of addresses of the coins being used in the pool
* @param _A Amplification coefficient. If set to 0 then bonding curve acts like Uniswap. Any >0 value
* makes the bonding curve to swap at 1:1 constant price, the more `_A` the longer the constant price period.
* Curve recommends set it to 100 for crypto collateralizard stablecoins. This parameter can be updated later.
* @param _fee Trade fee, given as an integer with 1e10 precision, ex: 4000000 = 0.04% fee
* @param _offpeg_fee_multiplier Off-peg multiplier. Curve recommends set it to `20000000000`. This parameter can be updated
* later. More info: https://docs.curve.fi/stableswap-exchange/stableswap-ng/pools/overview/#dynamic-fees
* @param _ma_exp_time MA time; set as time_in_seconds / ln(2), ex: 866 = 600 seconds, 2597 = 1800 seconds.
* This parameter can be updated later.
* @param _implementation_idx Index of the plain pool implementation to use. Can be retrieved
* via `ICurveStableSwapFactoryNG.pool_implementations()`. There is only 1 plain pool implementation right now
* so use index `0`.
* @param _asset_types Asset types of the pool tokens as an integer. Available asset type indexes:
* - 0: Standard ERC20 token with no additional features
* - 1: Oracle - token with rate oracle (e.g. wstETH)
* - 2: Rebasing - token with rebase (e.g. stETH)
* - 3: ERC4626 - token with convertToAssets method (e.g. sDAI)
* Both Dollar and LUSD are standard ERC20 tokens so we should use asset types with index `0`.
* @param _method_ids Array of first four bytes of the Keccak-256 hash of the function signatures of
* the oracle addresses that give rate oracles. This is applied only to asset type `1` (Oracle).
* For Dollar token deployment set empty.
* @param _oracles Array of rate oracle addresses. This is applied only to asset type `1` (Oracle).
* For Dollar token deployment set empty address.
* @return Deployed plain pool address
*/
function deploy_plain_pool(
string memory _name,
string memory _symbol,
address[] memory _coins,
uint256 _A,
uint256 _fee,
uint256 _offpeg_fee_multiplier,
uint256 _ma_exp_time,
uint256 _implementation_idx,
uint8[] memory _asset_types,
bytes4[] memory _method_ids,
address[] memory _oracles
) external returns (address);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,10 @@ import {ICurveStableSwapMetaNG} from "./ICurveStableSwapMetaNG.sol";
/**
* @notice Curve's interface for plain pool which contains only USD pegged assets
*/
interface ICurveStableSwapNG is ICurveStableSwapMetaNG {}
interface ICurveStableSwapNG is ICurveStableSwapMetaNG {
function add_liquidity(
uint256[] memory _amounts,
uint256 _min_mint_amount,
address _receiver
) external returns (uint256);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ contract MockCurveStableSwapMetaNG is ICurveStableSwapMetaNG, MockERC20 {
uint256[2] memory _amounts,
uint256 _min_mint_amount,
address _receiver
) external returns (uint256 result) {
) public returns (uint256 result) {
mint(
_receiver,
_min_mint_amount == 0
Expand Down
Loading
Loading