Skip to content

Commit 447ec1d

Browse files
authored
Merge pull request ubiquity#935 from rndquu/feat/migration-curve-plain
feat: add plain pool migration
2 parents db2a5d0 + de86212 commit 447ec1d

8 files changed

+154
-55
lines changed

README.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ COLLATERAL_TOKEN_ADDRESS="0x5f98805A4E8be255a32880FDeC7F6728C6568bA0"
9292

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

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

packages/contracts/.env.example

+8-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ COLLATERAL_TOKEN_ADDRESS="0x5f98805A4E8be255a32880FDeC7F6728C6568bA0"
1111

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

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

packages/contracts/migrations/development/Deploy001_Diamond_Dollar_Governance.s.sol

+31-28
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {DiamondLoupeFacet} from "../../src/dollar/facets/DiamondLoupeFacet.sol";
1616
import {ManagerFacet} from "../../src/dollar/facets/ManagerFacet.sol";
1717
import {OwnershipFacet} from "../../src/dollar/facets/OwnershipFacet.sol";
1818
import {UbiquityPoolFacet} from "../../src/dollar/facets/UbiquityPoolFacet.sol";
19-
import {ICurveStableSwapMetaNG} from "../../src/dollar/interfaces/ICurveStableSwapMetaNG.sol";
19+
import {ICurveStableSwapNG} from "../../src/dollar/interfaces/ICurveStableSwapNG.sol";
2020
import {ICurveTwocryptoOptimized} from "../../src/dollar/interfaces/ICurveTwocryptoOptimized.sol";
2121
import {IDiamondCut} from "../../src/dollar/interfaces/IDiamondCut.sol";
2222
import {IDiamondLoupe} from "../../src/dollar/interfaces/IDiamondLoupe.sol";
@@ -26,7 +26,7 @@ import {LibAccessControl} from "../../src/dollar/libraries/LibAccessControl.sol"
2626
import {AppStorage, LibAppStorage, Modifiers} from "../../src/dollar/libraries/LibAppStorage.sol";
2727
import {LibDiamond} from "../../src/dollar/libraries/LibDiamond.sol";
2828
import {MockChainLinkFeed} from "../../src/dollar/mocks/MockChainLinkFeed.sol";
29-
import {MockCurveStableSwapMetaNG} from "../../src/dollar/mocks/MockCurveStableSwapMetaNG.sol";
29+
import {MockCurveStableSwapNG} from "../../src/dollar/mocks/MockCurveStableSwapNG.sol";
3030
import {MockCurveTwocryptoOptimized} from "../../src/dollar/mocks/MockCurveTwocryptoOptimized.sol";
3131
import {MockERC20} from "../../src/dollar/mocks/MockERC20.sol";
3232
import {DiamondTestHelper} from "../../test/helpers/DiamondTestHelper.sol";
@@ -129,8 +129,7 @@ contract Deploy001_Diamond_Dollar_Governance is Script, DiamondTestHelper {
129129
// oracle related contracts
130130
AggregatorV3Interface chainLinkPriceFeedEth; // chainlink ETH/USD price feed
131131
AggregatorV3Interface chainLinkPriceFeedLusd; // chainlink LUSD/USD price feed
132-
IERC20 curveTriPoolLpToken; // Curve's 3CRV-LP token
133-
ICurveStableSwapMetaNG curveDollarMetaPool; // Curve's Dollar-3CRVLP metapool
132+
ICurveStableSwapNG curveStableDollarPlainPool; // Curve's LUSD-Dollar plain pool
134133
ICurveTwocryptoOptimized curveGovernanceEthPool; // Curve's Governance-WETH crypto pool
135134

136135
// collateral ERC20 token used in UbiquityPoolFacet
@@ -408,22 +407,22 @@ contract Deploy001_Diamond_Dollar_Governance is Script, DiamondTestHelper {
408407
* - oracle related contracts
409408
* - Governance token related contracts
410409
*
411-
* @dev Ubiquity protocol supports 4 oracles:
412-
* 1. Curve's Dollar-3CRVLP metapool to fetch Dollar prices
413-
* 2. Chainlink's price feed (used in UbiquityPool) to fetch collateral token prices in USD
414-
* 3. Chainlink's price feed (used in UbiquityPool) to fetch ETH/USD price
415-
* 4. Curve's Governance-WETH crypto pool to fetch Governance/ETH price
410+
* @dev Ubiquity protocol supports 5 oracles:
411+
* 1. Curve's LUSD-Dollar plain pool to fetch Dollar prices
412+
* 2. Chainlink's price feed (used in UbiquityPool) to fetch LUSD/USD price (for getting Dollar price in USD)
413+
* 3. Chainlink's price feed (used in UbiquityPool) to fetch collateral token prices in USD (for getting collateral price in USD)
414+
* 4. Chainlink's price feed (used in UbiquityPool) to fetch ETH/USD price
415+
* 5. Curve's Governance-WETH crypto pool to fetch Governance/ETH price
416416
*
417417
* There are 2 migrations (deployment scripts):
418418
* 1. Development (for usage in testnet and local anvil instance)
419419
* 2. Mainnet (for production usage in mainnet)
420420
*
421421
* Development migration deploys (for ease of debugging) mocks of:
422-
* - Chainlink collateral price feed contract
423422
* - Chainlink ETH/USD price feed contract
424-
* - 3CRVLP ERC20 token
423+
* - Chainlink LUSD/USD price feed contract (for getting Dollar and collateral prices in USD)
425424
* - WETH token
426-
* - Curve's Dollar-3CRVLP metapool contract
425+
* - Curve's LUSD-Dollar plain pool contract
427426
* - Curve's Governance-WETH crypto pool contract
428427
*/
429428
function afterRun() public virtual {
@@ -464,7 +463,7 @@ contract Deploy001_Diamond_Dollar_Governance is Script, DiamondTestHelper {
464463
1 // answered in round
465464
);
466465

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

476+
// set Stable/USD price feed address and threshold in seconds
477+
ubiquityPoolFacet.setStableUsdChainLinkPriceFeed(
478+
address(chainLinkPriceFeedLusd), // price feed address
479+
CHAINLINK_PRICE_FEED_THRESHOLD // price feed staleness threshold in seconds
480+
);
481+
477482
// stop sending admin transactions
478483
vm.stopBroadcast();
479484

480485
//=========================================
481-
// Curve's Dollar-3CRVLP metapool deploy
486+
// Curve's LUSD-Dollar plain pool deploy
482487
//=========================================
483488

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

487-
// deploy mock 3CRV-LP token
488-
curveTriPoolLpToken = new MockERC20(
489-
"Curve.fi DAI/USDC/USDT",
490-
"3Crv",
491-
18
492-
);
493-
494-
// deploy mock Curve's Dollar-3CRVLP metapool
495-
curveDollarMetaPool = new MockCurveStableSwapMetaNG(
496-
address(dollarToken),
497-
address(curveTriPoolLpToken)
492+
// Deploy mock Curve's LUSD-Dollar plain pool.
493+
// Since we're using LUSD both as collateral and Dollar token pair
494+
// in Curve's plain pool we don't deploy another mock of the "stable" coin
495+
// paired to Dollar and simply use collateral token (i.e. LUSD).
496+
curveStableDollarPlainPool = new MockCurveStableSwapNG(
497+
address(collateralToken),
498+
address(dollarToken)
498499
);
499500

500501
// stop sending owner transactions
501502
vm.stopBroadcast();
502503

503504
//========================================
504-
// Curve's Dollar-3CRVLP metapool setup
505+
// Curve's LUSD-Dollar plain pool setup
505506
//========================================
506507

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

510-
// set curve's metapool in manager facet
511-
managerFacet.setStableSwapMetaPoolAddress(address(curveDollarMetaPool));
511+
// set curve's plain pool in manager facet
512+
managerFacet.setStableSwapPlainPoolAddress(
513+
address(curveStableDollarPlainPool)
514+
);
512515

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

packages/contracts/migrations/mainnet/Deploy001_Diamond_Dollar_Governance.s.sol

+46-22
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,20 @@ contract Deploy001_Diamond_Dollar_Governance is
5555
* we need to use already deployed contracts while `Deploy001_Diamond_Dollar_Governance_Development`
5656
* deploys all oracle and Governance token related contracts from scratch for ease of debugging.
5757
*
58-
* @dev Ubiquity protocol supports 4 oracles:
59-
* 1. Curve's Dollar-3CRVLP metapool to fetch Dollar prices
60-
* 2. Chainlink's price feed (used in UbiquityPool) to fetch collateral token prices in USD
61-
* 3. Chainlink's price feed (used in UbiquityPool) to fetch ETH/USD price
62-
* 4. Curve's Governance-WETH crypto pool to fetch Governance/ETH price
58+
* @dev Ubiquity protocol supports 5 oracles:
59+
* 1. Curve's LUSD-Dollar plain pool to fetch Dollar prices
60+
* 2. Chainlink's price feed (used in UbiquityPool) to fetch LUSD/USD price (for getting Dollar price in USD)
61+
* 3. Chainlink's price feed (used in UbiquityPool) to fetch collateral token prices in USD (for getting collateral price in USD)
62+
* 4. Chainlink's price feed (used in UbiquityPool) to fetch ETH/USD price
63+
* 5. Curve's Governance-WETH crypto pool to fetch Governance/ETH price
6364
*
6465
* There are 2 migrations (deployment scripts):
6566
* 1. Development (for usage in testnet and local anvil instance)
6667
* 2. Mainnet (for production usage in mainnet)
6768
*
6869
* Mainnet (i.e. production) migration uses already deployed contracts for:
6970
* - Chainlink collateral price feed contract
71+
* - Chainlink Stable/USD price feed contract (here "Stable" refers to the LUSD token from Curve's LUSD-Dollar plain pool)
7072
* - UbiquityAlgorithmicDollarManager contract
7173
* - UbiquityGovernance token contract
7274
* - Chainlink ETH/USD price feed
@@ -104,7 +106,7 @@ contract Deploy001_Diamond_Dollar_Governance is
104106
chainlinkPriceFeedAddressLusd
105107
);
106108

107-
// set price feed
109+
// set collateral price feed
108110
ubiquityPoolFacet.setCollateralChainLinkPriceFeed(
109111
address(collateralToken), // collateral token address
110112
address(chainLinkPriceFeedLusd), // price feed address
@@ -114,46 +116,68 @@ contract Deploy001_Diamond_Dollar_Governance is
114116
// fetch latest prices from chainlink for collateral with index 0
115117
ubiquityPoolFacet.updateChainLinkCollateralPrice(0);
116118

119+
// set Stable/Dollar price feed
120+
ubiquityPoolFacet.setStableUsdChainLinkPriceFeed(
121+
address(chainLinkPriceFeedLusd), // price feed address
122+
CHAINLINK_PRICE_FEED_THRESHOLD // price feed staleness threshold in seconds
123+
);
124+
117125
// stop sending admin transactions
118126
vm.stopBroadcast();
119127

120128
//=========================================
121-
// Curve's Dollar-3CRVLP metapool deploy
129+
// Curve's LUSD-Dollar plain pool deploy
122130
//=========================================
123131

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

127-
// deploy Curve Dollar-3CRV metapool
128-
address curveDollarMetaPoolAddress = ICurveStableSwapFactoryNG(
135+
// prepare parameters
136+
address[] memory plainPoolCoins = new address[](2);
137+
plainPoolCoins[0] = address(collateralToken);
138+
plainPoolCoins[1] = address(dollarToken);
139+
140+
uint8[] memory plainPoolAssetTypes = new uint8[](2);
141+
plainPoolAssetTypes[0] = 0;
142+
plainPoolAssetTypes[1] = 0;
143+
144+
bytes4[] memory plainPoolMethodIds = new bytes4[](2);
145+
plainPoolMethodIds[0] = bytes4("");
146+
plainPoolMethodIds[1] = bytes4("");
147+
148+
address[] memory plainPoolTokenOracleAddresses = new address[](2);
149+
plainPoolTokenOracleAddresses[0] = address(0);
150+
plainPoolTokenOracleAddresses[1] = address(0);
151+
152+
// deploy Curve LUSD-Dollar plain pool
153+
address curveDollarPlainPoolAddress = ICurveStableSwapFactoryNG(
129154
0x6A8cbed756804B16E05E741eDaBd5cB544AE21bf
130-
).deploy_metapool(
131-
0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7, // Curve 3pool (DAI-USDT-USDC) address
132-
"Dollar/3CRV", // pool name
133-
"Dollar3CRV", // LP token symbol
134-
address(dollarToken), // main token
155+
).deploy_plain_pool(
156+
"LUSD/Dollar", // pool name
157+
"LUSDDollar", // LP token symbol
158+
plainPoolCoins, // coins used in the pool
135159
100, // amplification coefficient
136-
40000000, // trade fee, 0.04%
160+
4000000, // trade fee, 0.04%
137161
20000000000, // off-peg fee multiplier
138162
2597, // moving average time value, 2597 = 1800 seconds
139-
0, // metapool implementation index
140-
0, // asset type
141-
"", // method id for oracle asset type (not applicable for Dollar)
142-
address(0) // token oracle address (not applicable for Dollar)
163+
0, // plain pool implementation index
164+
plainPoolAssetTypes, // asset types
165+
plainPoolMethodIds, // method ids for oracle asset type (not applicable for Dollar)
166+
plainPoolTokenOracleAddresses // token oracle addresses (not applicable for Dollar)
143167
);
144168

145169
// stop sending owner transactions
146170
vm.stopBroadcast();
147171

148172
//========================================
149-
// Curve's Dollar-3CRVLP metapool setup
173+
// Curve's LUSD-Dollar plain pool setup
150174
//========================================
151175

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

155-
// set curve's metapool in manager facet
156-
managerFacet.setStableSwapMetaPoolAddress(curveDollarMetaPoolAddress);
179+
// set curve's plain pool in manager facet
180+
managerFacet.setStableSwapPlainPoolAddress(curveDollarPlainPoolAddress);
157181

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

packages/contracts/src/dollar/interfaces/ICurveStableSwapFactoryNG.sol

+44-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ interface ICurveStableSwapFactoryNG {
1919
* @param _A Amplification coefficient. If set to 0 then bonding curve acts like Uniswap. Any >0 value
2020
* makes the bonding curve to swap at 1:1 constant price, the more `_A` the longer the constant price period.
2121
* Curve recommends set it to 100 for crypto collateralizard stablecoins. This parameter can be updated later.
22-
* @param _fee Trade fee, given as an integer with 1e10 precision, ex: 40000000 = 0.04% fee
22+
* @param _fee Trade fee, given as an integer with 1e10 precision, ex: 4000000 = 0.04% fee
2323
* @param _offpeg_fee_multiplier Off-peg multiplier. Curve recommends set it to `20000000000`. This parameter can be updated
2424
* later. More info: https://docs.curve.fi/stableswap-exchange/stableswap-ng/pools/overview/#dynamic-fees
2525
* @param _ma_exp_time MA time; set as time_in_seconds / ln(2), ex: 866 = 600 seconds, 2597 = 1800 seconds.
@@ -54,4 +54,47 @@ interface ICurveStableSwapFactoryNG {
5454
bytes4 _method_id,
5555
address _oracle
5656
) external returns (address);
57+
58+
/**
59+
* @notice Deploys a new plain pool
60+
* @param _name Name of the new plain pool, ex: "LUSD/Dollar"
61+
* @param _symbol Symbol for the new pool's LP token, ex: "LUSDDollar"
62+
* @param _coins Array of addresses of the coins being used in the pool
63+
* @param _A Amplification coefficient. If set to 0 then bonding curve acts like Uniswap. Any >0 value
64+
* makes the bonding curve to swap at 1:1 constant price, the more `_A` the longer the constant price period.
65+
* Curve recommends set it to 100 for crypto collateralizard stablecoins. This parameter can be updated later.
66+
* @param _fee Trade fee, given as an integer with 1e10 precision, ex: 4000000 = 0.04% fee
67+
* @param _offpeg_fee_multiplier Off-peg multiplier. Curve recommends set it to `20000000000`. This parameter can be updated
68+
* later. More info: https://docs.curve.fi/stableswap-exchange/stableswap-ng/pools/overview/#dynamic-fees
69+
* @param _ma_exp_time MA time; set as time_in_seconds / ln(2), ex: 866 = 600 seconds, 2597 = 1800 seconds.
70+
* This parameter can be updated later.
71+
* @param _implementation_idx Index of the plain pool implementation to use. Can be retrieved
72+
* via `ICurveStableSwapFactoryNG.pool_implementations()`. There is only 1 plain pool implementation right now
73+
* so use index `0`.
74+
* @param _asset_types Asset types of the pool tokens as an integer. Available asset type indexes:
75+
* - 0: Standard ERC20 token with no additional features
76+
* - 1: Oracle - token with rate oracle (e.g. wstETH)
77+
* - 2: Rebasing - token with rebase (e.g. stETH)
78+
* - 3: ERC4626 - token with convertToAssets method (e.g. sDAI)
79+
* Both Dollar and LUSD are standard ERC20 tokens so we should use asset types with index `0`.
80+
* @param _method_ids Array of first four bytes of the Keccak-256 hash of the function signatures of
81+
* the oracle addresses that give rate oracles. This is applied only to asset type `1` (Oracle).
82+
* For Dollar token deployment set empty.
83+
* @param _oracles Array of rate oracle addresses. This is applied only to asset type `1` (Oracle).
84+
* For Dollar token deployment set empty address.
85+
* @return Deployed plain pool address
86+
*/
87+
function deploy_plain_pool(
88+
string memory _name,
89+
string memory _symbol,
90+
address[] memory _coins,
91+
uint256 _A,
92+
uint256 _fee,
93+
uint256 _offpeg_fee_multiplier,
94+
uint256 _ma_exp_time,
95+
uint256 _implementation_idx,
96+
uint8[] memory _asset_types,
97+
bytes4[] memory _method_ids,
98+
address[] memory _oracles
99+
) external returns (address);
57100
}

packages/contracts/src/dollar/interfaces/ICurveStableSwapNG.sol

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,10 @@ import {ICurveStableSwapMetaNG} from "./ICurveStableSwapMetaNG.sol";
66
/**
77
* @notice Curve's interface for plain pool which contains only USD pegged assets
88
*/
9-
interface ICurveStableSwapNG is ICurveStableSwapMetaNG {}
9+
interface ICurveStableSwapNG is ICurveStableSwapMetaNG {
10+
function add_liquidity(
11+
uint256[] memory _amounts,
12+
uint256 _min_mint_amount,
13+
address _receiver
14+
) external returns (uint256);
15+
}

packages/contracts/src/dollar/mocks/MockCurveStableSwapMetaNG.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ contract MockCurveStableSwapMetaNG is ICurveStableSwapMetaNG, MockERC20 {
1919
uint256[2] memory _amounts,
2020
uint256 _min_mint_amount,
2121
address _receiver
22-
) external returns (uint256 result) {
22+
) public returns (uint256 result) {
2323
mint(
2424
_receiver,
2525
_min_mint_amount == 0

0 commit comments

Comments
 (0)