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: use CurveStableSwapMetaNG contract #893

Merged
merged 9 commits into from
Feb 6, 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
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,18 @@ import {DiamondCutFacet} from "../../src/dollar/facets/DiamondCutFacet.sol";
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 {TWAPOracleDollar3poolFacet} from "../../src/dollar/facets/TWAPOracleDollar3poolFacet.sol";
import {UbiquityPoolFacet} from "../../src/dollar/facets/UbiquityPoolFacet.sol";
import {ICurveStableSwapMetaNG} from "../../src/dollar/interfaces/ICurveStableSwapMetaNG.sol";
import {IDiamondCut} from "../../src/dollar/interfaces/IDiamondCut.sol";
import {IDiamondLoupe} from "../../src/dollar/interfaces/IDiamondLoupe.sol";
import {IERC173} from "../../src/dollar/interfaces/IERC173.sol";
import {IMetaPool} from "../../src/dollar/interfaces/IMetaPool.sol";
import {DEFAULT_ADMIN_ROLE, DOLLAR_TOKEN_MINTER_ROLE, DOLLAR_TOKEN_BURNER_ROLE, PAUSER_ROLE} from "../../src/dollar/libraries/Constants.sol";
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 {MockERC20} from "../../src/dollar/mocks/MockERC20.sol";
import {MockMetaPool} from "../../src/dollar/mocks/MockMetaPool.sol";
import {DiamondTestHelper} from "../../test/helpers/DiamondTestHelper.sol";

/**
Expand Down Expand Up @@ -117,21 +116,19 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
DiamondLoupeFacet diamondLoupeFacetImplementation;
ManagerFacet managerFacetImplementation;
OwnershipFacet ownershipFacetImplementation;
TWAPOracleDollar3poolFacet twapOracleDollar3PoolFacetImplementation;
UbiquityPoolFacet ubiquityPoolFacetImplementation;

// oracle related contracts
AggregatorV3Interface chainLinkPriceFeedLusd; // chainlink LUSD/USD price feed
IERC20 curveTriPoolLpToken; // Curve's 3CRV-LP token
IMetaPool curveDollarMetaPool; // Curve's Dollar-3CRVLP metapool
ICurveStableSwapMetaNG curveDollarMetaPool; // Curve's Dollar-3CRVLP metapool

// selectors for all of the facets
bytes4[] selectorsOfAccessControlFacet;
bytes4[] selectorsOfDiamondCutFacet;
bytes4[] selectorsOfDiamondLoupeFacet;
bytes4[] selectorsOfManagerFacet;
bytes4[] selectorsOfOwnershipFacet;
bytes4[] selectorsOfTWAPOracleDollar3poolFacet;
bytes4[] selectorsOfUbiquityPoolFacet;

function run() public virtual {
Expand Down Expand Up @@ -166,9 +163,6 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
selectorsOfOwnershipFacet = getSelectorsFromAbi(
"/out/OwnershipFacet.sol/OwnershipFacet.json"
);
selectorsOfTWAPOracleDollar3poolFacet = getSelectorsFromAbi(
"/out/TWAPOracleDollar3poolFacet.sol/TWAPOracleDollar3poolFacet.json"
);
selectorsOfUbiquityPoolFacet = getSelectorsFromAbi(
"/out/UbiquityPoolFacet.sol/UbiquityPoolFacet.json"
);
Expand All @@ -179,7 +173,6 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
diamondLoupeFacetImplementation = new DiamondLoupeFacet();
managerFacetImplementation = new ManagerFacet();
ownershipFacetImplementation = new OwnershipFacet();
twapOracleDollar3PoolFacetImplementation = new TWAPOracleDollar3poolFacet();
ubiquityPoolFacetImplementation = new UbiquityPoolFacet();

// prepare DiamondInit args
Expand All @@ -198,7 +191,7 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
});

// prepare facet cuts
FacetCut[] memory cuts = new FacetCut[](7);
FacetCut[] memory cuts = new FacetCut[](6);
cuts[0] = (
FacetCut({
facetAddress: address(accessControlFacetImplementation),
Expand Down Expand Up @@ -235,13 +228,6 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
})
);
cuts[5] = (
FacetCut({
facetAddress: address(twapOracleDollar3PoolFacetImplementation),
action: FacetCutAction.Add,
functionSelectors: selectorsOfTWAPOracleDollar3poolFacet
})
);
cuts[6] = (
FacetCut({
facetAddress: address(ubiquityPoolFacetImplementation),
action: FacetCutAction.Add,
Expand Down Expand Up @@ -438,7 +424,7 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
);

// deploy mock Curve's Dollar-3CRVLP metapool
curveDollarMetaPool = new MockMetaPool(
curveDollarMetaPool = new MockCurveStableSwapMetaNG(
address(dollarToken),
address(curveTriPoolLpToken)
);
Expand All @@ -450,23 +436,15 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
// Curve's Dollar-3CRVLP metapool setup
//========================================

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

TWAPOracleDollar3poolFacet twapOracleDollar3PoolFacet = TWAPOracleDollar3poolFacet(
address(diamond)
);
// start sending admin transactions
vm.startBroadcast(adminPrivateKey);

// set Curve Dollar-3CRVLP pool in the diamond storage
twapOracleDollar3PoolFacet.setPool(
address(curveDollarMetaPool),
address(curveTriPoolLpToken)
);
ManagerFacet managerFacet = ManagerFacet(address(diamond));

// fetch latest Dollar price from Curve's Dollar-3CRVLP metapool
twapOracleDollar3PoolFacet.update();
// set curve's metapool in manager facet
managerFacet.setStableSwapMetaPoolAddress(address(curveDollarMetaPool));

// stop sending owner transactions
// stop sending admin transactions
vm.stopBroadcast();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ pragma solidity 0.8.19;
import {AggregatorV3Interface} from "@chainlink/interfaces/AggregatorV3Interface.sol";
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {Deploy001_Diamond_Dollar as Deploy001_Diamond_Dollar_Development} from "../development/Deploy001_Diamond_Dollar.s.sol";
import {TWAPOracleDollar3poolFacet} from "../../src/dollar/facets/TWAPOracleDollar3poolFacet.sol";
import {ManagerFacet} from "../../src/dollar/facets/ManagerFacet.sol";
import {UbiquityPoolFacet} from "../../src/dollar/facets/UbiquityPoolFacet.sol";
import {IMetaPool} from "../../src/dollar/interfaces/IMetaPool.sol";
import {ICurveStableSwapMetaNG} from "../../src/dollar/interfaces/ICurveStableSwapMetaNG.sol";

/// @notice Migration contract
contract Deploy001_Diamond_Dollar is Deploy001_Diamond_Dollar_Development {
Expand Down Expand Up @@ -82,31 +82,22 @@ contract Deploy001_Diamond_Dollar is Deploy001_Diamond_Dollar_Development {
// Curve's Dollar-3CRVLP metapool setup
//========================================

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

// init 3CRV token
curveTriPoolLpToken = IERC20(token3CrvAddress);

// init Dollar-3CRVLP Curve metapool
curveDollarMetaPool = IMetaPool(curveDollarMetapoolAddress);

/*
TODO: uncomment when we redeploy Curve's Dollar-3CRV metapool with the new Dollar token

TWAPOracleDollar3poolFacet twapOracleDollar3PoolFacet = TWAPOracleDollar3poolFacet(address(diamond));

// set Curve Dollar-3CRVLP pool in the diamond storage
twapOracleDollar3PoolFacet.setPool(
address(curveDollarMetaPool),
address(curveTriPoolLpToken)
curveDollarMetaPool = ICurveStableSwapMetaNG(
curveDollarMetapoolAddress
);

// fetch latest Dollar price from Curve's Dollar-3CRVLP metapool
twapOracleDollar3PoolFacet.update();
*/
// set curve's metapool in manager facet
ManagerFacet managerFacet = ManagerFacet(address(diamond));
managerFacet.setStableSwapMetaPoolAddress(address(curveDollarMetaPool));

// stop sending owner transactions
// stop sending admin transactions
vm.stopBroadcast();
}
}
2 changes: 1 addition & 1 deletion packages/contracts/src/deprecated/TWAPOracle.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.3;

import "../dollar/interfaces/IMetaPool.sol";
import "./interfaces/IMetaPool.sol";

contract TWAPOracle {
address public immutable pool;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "./interfaces/IMetaPool.sol";
import "./interfaces/IUbiquityAlgorithmicDollar.sol";
import "../dollar/interfaces/ICurveFactory.sol";
import "../dollar/interfaces/IMetaPool.sol";

import "./TWAPOracle.sol";

Expand Down
10 changes: 6 additions & 4 deletions packages/contracts/src/dollar/facets/ManagerFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "../../dollar/interfaces/IUbiquityDollarToken.sol";
import "../../dollar/interfaces/ICurveFactory.sol";
import "../../dollar/interfaces/IMetaPool.sol";
import "../../dollar/interfaces/ICurveStableSwapMetaNG.sol";
import "../libraries/LibAccessControl.sol";

/**
Expand Down Expand Up @@ -246,8 +246,10 @@ contract ManagerFacet is Modifiers {

// coin at index 0 is Dollar and index 1 is 3CRV
require(
IMetaPool(metaPool).coins(0) == store.dollarTokenAddress &&
IMetaPool(metaPool).coins(1) == _crv3PoolTokenAddress,
ICurveStableSwapMetaNG(metaPool).coins(0) ==
store.dollarTokenAddress &&
ICurveStableSwapMetaNG(metaPool).coins(1) ==
_crv3PoolTokenAddress,
"MGR: COIN_ORDER_MISMATCH"
);
// Add the initial liquidity to the StableSwap meta pool
Expand All @@ -257,7 +259,7 @@ contract ManagerFacet is Modifiers {
];
// set curve 3Pool address
store.curve3PoolTokenAddress = _crv3PoolTokenAddress;
IMetaPool(metaPool).add_liquidity(amounts, 0, msg.sender);
ICurveStableSwapMetaNG(metaPool).add_liquidity(amounts, 0, msg.sender);
}

/**
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";

/**
* @notice Curve MetaPool interface
*
* @notice **What is Curve MetaPool**
* @notice The pool that consists of 2 tokens: stable coin and 3CRV LP token.
* For example the pool may contain Ubiquity Dollar and 3CRV LP token.
* This allows users to trade between Ubiquity Dollar and any of the tokens
* from the Curve 3Pool (DAI, USDC, USDT). When user adds liquidity to the pool
* then he is rewarded with MetaPool LP tokens. 1 Dollar3CRV LP token != 1 stable coin token.
* @notice Add liquidity example:
* 1. User sends 100 Ubiquity Dollars to the pool
* 2. User gets 100 Dollar3CRV LP tokens of the pool
* @notice Remove liquidity example:
* 1. User sends 100 Dollar3CRV LP tokens to the pool
* 2. User gets 100 Dollar/DAI/USDC/USDT (may choose any) tokens
*
* @dev Source: https://github.com/curvefi/stableswap-ng/blob/bff1522b30819b7b240af17ccfb72b0effbf6c47/contracts/main/CurveStableSwapMetaNG.vy
* @dev Docs: https://docs.curve.fi/stableswap-exchange/stableswap-ng/pools/metapool/
*/
interface ICurveStableSwapMetaNG is IERC20 {
/**
* @notice Deposits coins into to the pool and mints new LP tokens
* @param _amounts List of amounts of underlying coins to deposit.
* Amounts correspond to the tokens at the same index locations within `coins`.
* @param _min_mint_amount Minimum amount of LP tokens to mint from the deposit
* @param _receiver Optional address that receives the LP tokens. If not specified, they are sent to the caller.
* @return The amount of LP tokens that were minted in the deposit
*/
function add_liquidity(
uint256[2] memory _amounts,
uint256 _min_mint_amount,
address _receiver
) external returns (uint256);

/**
* @notice Estimates the amount of LP tokens minted or burned based on a deposit or withdrawal
*
* @notice This calculation accounts for slippage, but not fees. It should be used as a basis for
* determining expected amounts when calling `add_liquidity()` or `remove_liquidity_imbalance()`,
* but should not be considered to be precise!
*
* @param _amounts Amount of each coin being deposited. Amounts correspond to the tokens at the
* same index locations within `coins()`.
* @param _is_deposit Set `True` for deposits, `False` for withdrawals
* @return The expected amount of LP tokens minted or burned
*/
function calc_token_amount(
uint256[2] memory _amounts,
bool _is_deposit
) external view returns (uint256);

/**
* @notice Returns token address by the provided `arg0` index
* @param arg0 Token index
* @return Token address
*/
function coins(uint256 arg0) external view returns (address);

/**
* @notice Performs an exchange between two tokens. Index values can be found
* using the `coins()` public getter method, or `get_coins()` within the factory contract.
* @param i Index value of the token to send
* @param j Index value of the token to receive
* @param dx The amount of `i` being exchanged
* @param min_dy The minimum amount of `j` to receive. If the swap would result in less, the transaction will revert.
* @return The amount of `j` received in the exchange
*/
function exchange(
int128 i,
int128 j,
uint256 dx,
uint256 min_dy
) external returns (uint256);

/**
* @notice Function to calculate the exponential moving average (ema) price for the coin at index value `i`
* @param i Index value of coin
* @return Price oracle
*/
function price_oracle(uint256 i) external view returns (uint256);

/**
* @notice Withdraws a single asset from the pool
* @param _burn_amount Amount of LP tokens to burn in the withdrawal
* @param i Index value of the coin to withdraw. Can be found using the `coins()` getter method.
* @param _min_received Minimum amount of the coin to receive
* @return The amount of the coin received in the withdrawal
*/
function remove_liquidity_one_coin(
uint256 _burn_amount,
int128 i,
uint256 _min_received
) external returns (uint256);
}
Loading
Loading