diff --git a/README.md b/README.md index 6818a09..752531e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # Lucidly DeFi Vault Protocol -We're change onchain vault experiences as you see it today. This is the working repo. +We're changing onchain vault experiences as you see it today. This is the working repo. diff --git a/audits/PAG-July.pdf b/audits/PAG-July.pdf new file mode 100644 index 0000000..d92e115 Binary files /dev/null and b/audits/PAG-July.pdf differ diff --git a/audits/PAG-May.pdf b/audits/PAG-May.pdf new file mode 100644 index 0000000..327c9c5 Binary files /dev/null and b/audits/PAG-May.pdf differ diff --git a/script/DeployRingsVault.s.sol b/script/DeployRingsVault.s.sol new file mode 100644 index 0000000..a96cd89 --- /dev/null +++ b/script/DeployRingsVault.s.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {Script} from "forge-std/Script.sol"; + +import {Pool} from "../src/Pool.sol"; +import {PoolToken} from "../src/PoolToken.sol"; +import {Vault} from "../src/Vault.sol"; +import {MockToken} from "../src/Mocks/MockToken.sol"; +import {IRateProvider} from "../src/RateProvider/IRateProvider.sol"; +import {RingsVaultRateProvider} from "../src/RateProvider/sonic-rings/RingsVaultRateProvider.sol"; +import {PoolOwner} from "../src/PoolOwner.sol"; + +contract RingsVaultDeploymentScript is Script { + PoolToken poolToken; + Pool pool; + Vault vault; + PoolOwner ownerContract; + IRateProvider rateProvider; + + address private ADMIN_ADDRESS = 0x1b514df3413DA9931eB31f2Ab72e32c0A507Cad5; + + address private constant USDC_BRIDGED = 0x29219dd400f2Bf60E5a23d13Be72B486D4038894; + address private constant SCUSD = 0xd3DCe716f3eF535C5Ff8d041c1A41C3bd89b97aE; + address private constant SCUSD_USDC_REDSTONE_FEED = 0xb81131B6368b3F0a83af09dB4E39Ac23DA96C2Db; + + MockToken token0 = MockToken(USDC_BRIDGED); + MockToken token1 = MockToken(SCUSD); + + uint256 private PRECISION = 1e18; + + function run() public { + uint256 adminPk = vm.envUint("PRIVATE_KEY_1"); + vm.startBroadcast(adminPk); + + rateProvider = new RingsVaultRateProvider(); + + address[] memory tokens = new address[](2); + uint256[] memory weights = new uint256[](2); + address[] memory rateProviders = new address[](2); + + // tokens + tokens[0] = address(token0); + tokens[1] = address(token1); + + // set weights + weights[0] = 40 * PRECISION / 100; + weights[1] = 60 * PRECISION / 100; + + // set rateProviders + rateProviders[0] = address(rateProvider); + rateProviders[1] = address(rateProvider); + + address admin = vm.addr(adminPk); + poolToken = new PoolToken("**", "**", 18, admin); + pool = new Pool(address(poolToken), 450 * PRECISION, tokens, rateProviders, weights, admin); + vault = new Vault(address(poolToken), "lucidly rings vault share", "lcdRingsUSD", 100, admin, admin); + ownerContract = new PoolOwner(address(pool)); + + poolToken.setPool(address(pool)); + pool.setVaultAddress(address(vault)); + pool.setSwapFeeRate(3 * PRECISION / 10_000); // 3bps + vault.setDepositFeeInBps(100); + vault.setProtocolFeeAddress(admin); + + vm.stopBroadcast(); + } +} + +contract RingsVaultSeedingScript is Script { + PoolToken poolToken = PoolToken(0xa93C9411f8FeCF5E6aCd81ECd99a71C165d48c4D); + Pool pool = Pool(0xc8291D518fE771B5612Ecc0D6A99D5DC03db3DD8); + Vault vault = Vault(0xedEa2647CfE580c9B6f2148C270f9aaE6B08bcA5); + PoolOwner ownerContract = PoolOwner(0x2210A9357D51fF909EAa43570b3F1275E76cB6d6); + IRateProvider rateProvider = IRateProvider(0xa633C15E09cA2a8DBB6CD52aae915a3b379dEEb3); + + address private ADMIN_ADDRESS = 0x1b514df3413DA9931eB31f2Ab72e32c0A507Cad5; + + address private constant USDC_BRIDGED = 0x29219dd400f2Bf60E5a23d13Be72B486D4038894; + address private constant SCUSD = 0xd3DCe716f3eF535C5Ff8d041c1A41C3bd89b97aE; + address private constant SCUSD_USDC_REDSTONE_FEED = 0xb81131B6368b3F0a83af09dB4E39Ac23DA96C2Db; + + MockToken token0 = MockToken(USDC_BRIDGED); + MockToken token1 = MockToken(SCUSD); + + uint256 private PRECISION = 1e18; + + function run() public { + uint256 adminPk = vm.envUint("PRIVATE_KEY_1"); + vm.startBroadcast(adminPk); + address admin = vm.addr(adminPk); + + uint256[] memory amounts = new uint256[](2); + amounts[0] = 4 * 10 ** (token0.decimals()); + amounts[1] = 6 * 10 ** (token1.decimals()); + + require(token0.approve(address(pool), type(uint256).max), "pool cannot spend USDC.e"); + require(token1.approve(address(pool), type(uint256).max), "pool cannot spend scUSD"); + uint256 lp = pool.addLiquidity(amounts, 0, admin); + require(poolToken.approve(address(vault), type(uint256).max), "vault cannot spend poolToken"); + vault.deposit(lp, admin); + + vm.stopBroadcast(); + } +} diff --git a/src/Aggregator.sol b/src/Aggregator.sol index b551051..848c65d 100644 --- a/src/Aggregator.sol +++ b/src/Aggregator.sol @@ -6,7 +6,7 @@ import {LibSort} from "solady/utils/LibSort.sol"; import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol"; import {FixedPointMathLib} from "solady/utils/FixedPointMathLib.sol"; -import {Pool} from "../src/Pool.sol"; +import {Pool} from "../src/Poolv2.sol"; import {PoolToken} from "../src/PoolToken.sol"; import {Vault} from "../src/Vault.sol"; import {MockToken} from "../src/Mocks/MockToken.sol"; @@ -36,7 +36,7 @@ contract Aggregator { shares = Vault(vaultAddress).deposit(lpReceived, receiver); } - function depositFor( + function depositFromRouter( address[] calldata tokens, uint256[] calldata tokenAmounts, address receiver, @@ -46,16 +46,85 @@ contract Aggregator { require(tokens.length == tokenAmounts.length, "tokens and tokenAmounts should be of same length"); for (uint256 i = 0; i < tokenAmounts.length; i++) { - // SafeTransferLib.safeTransferFrom(tokens[i], msg.sender, address(this), tokenAmounts[i]); ERC20(tokens[i]).approve(poolAddress, tokenAmounts[i]); } + address vaultAddress = Pool(poolAddress).vaultAddress(); + uint256 lpReceived = Pool(poolAddress).addLiquidity(tokenAmounts, minLpAmount, address(this)); + PoolToken(Pool(poolAddress).tokenAddress()).approve(vaultAddress, lpReceived); + shares = Vault(vaultAddress).deposit(lpReceived, receiver); + } + + function depositSingle( + uint256 tokenIndex, + uint256 tokenAmount, + address receiver, + uint256 minLpAmount, + address poolAddress + ) external returns (uint256 shares) { + address token = Pool(poolAddress).tokens(tokenIndex); + SafeTransferLib.safeTransferFrom(token, msg.sender, address(this), tokenAmount); + ERC20(token).approve(poolAddress, tokenAmount); + + uint256 numTokens = Pool(poolAddress).numTokens(); + uint256[] memory addLiquidityAmounts = new uint256[](numTokens); + addLiquidityAmounts[tokenIndex] = tokenAmount; + address vaultAddress = Pool(poolAddress).vaultAddress(); + uint256 lpReceived = Pool(poolAddress).addLiquidity(addLiquidityAmounts, minLpAmount, address(this)); + PoolToken(Pool(poolAddress).tokenAddress()).approve(vaultAddress, lpReceived); + shares = Vault(vaultAddress).deposit(lpReceived, receiver); + } + + function depositSingleFromRouter( + uint256 tokenIndex, + uint256 tokenAmount, + address receiver, + uint256 minLpAmount, + address poolAddress + ) external returns (uint256 shares) { + address token = Pool(poolAddress).tokens(tokenIndex); + ERC20(token).approve(poolAddress, tokenAmount); + + uint256 numTokens = Pool(poolAddress).numTokens(); + uint256[] memory addLiquidityAmounts = new uint256[](numTokens); + addLiquidityAmounts[tokenIndex] = tokenAmount; + address vaultAddress = Pool(poolAddress).vaultAddress(); + uint256 lpReceived = Pool(poolAddress).addLiquidity(addLiquidityAmounts, minLpAmount, address(this)); + PoolToken(Pool(poolAddress).tokenAddress()).approve(vaultAddress, lpReceived); + shares = Vault(vaultAddress).deposit(lpReceived, receiver); + } + + function depositFor( + address[] calldata tokens, + uint256[] calldata tokenAmounts, + address receiver, + uint256 minLpAmount, + address poolAddress + ) external returns (uint256 shares) { + require(tokens.length == tokenAmounts.length, "tokens and tokenAmounts should be of same length"); address vaultAddress = Pool(poolAddress).vaultAddress(); uint256 lpReceived = Pool(poolAddress).addLiquidityFor(tokenAmounts, minLpAmount, msg.sender, address(this)); PoolToken(Pool(poolAddress).tokenAddress()).approve(vaultAddress, lpReceived); shares = Vault(vaultAddress).deposit(lpReceived, receiver); } + function depositForSingle( + uint256 tokenIndex, + uint256 tokenAmount, + address receiver, + uint256 minLpAmount, + address poolAddress + ) external returns (uint256 shares) { + address vaultAddress = Pool(poolAddress).vaultAddress(); + uint256 numTokens = Pool(poolAddress).numTokens(); + uint256[] memory addLiquidityAmounts = new uint256[](numTokens); + addLiquidityAmounts[tokenIndex] = tokenAmount; + uint256 lpReceived = + Pool(poolAddress).addLiquidityFor(addLiquidityAmounts, minLpAmount, msg.sender, address(this)); + PoolToken(Pool(poolAddress).tokenAddress()).approve(vaultAddress, lpReceived); + shares = Vault(vaultAddress).deposit(lpReceived, receiver); + } + function redeemBalanced( address poolAddress, uint256 sharesToBurn, diff --git a/src/Poolv2.sol b/src/Poolv2.sol index 9e481d1..e60f47a 100644 --- a/src/Poolv2.sol +++ b/src/Poolv2.sol @@ -482,6 +482,7 @@ contract PoolV2 is OwnableRoles, ReentrancyGuard { /// @notice deposit tokens into the pool /// @param amounts_ array of the amount for each token to take from caller /// @param minLpAmount_ minimum amount of lp tokens to mint + /// @param owner_ address from which to add liquidity from /// @param receiver_ account to receive the lp tokens /// @return amount of LP tokens minted function addLiquidityFor(uint256[] calldata amounts_, uint256 minLpAmount_, address owner_, address receiver_) diff --git a/src/RateProvider/sonic-rings/RingsVaultRateProvider.sol b/src/RateProvider/sonic-rings/RingsVaultRateProvider.sol new file mode 100644 index 0000000..c729d4a --- /dev/null +++ b/src/RateProvider/sonic-rings/RingsVaultRateProvider.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity >0.8.0; + +import {IRateProvider} from "../IRateProvider.sol"; +import {FixedPointMathLib} from "../../../lib/solady/src/utils/FixedPointMathLib.sol"; +import {AggregatorV3Interface, RedstoneDataFeedLib} from "../libraries/RedstoneDataFeedLib.sol"; + +contract RingsVaultRateProvider is IRateProvider { + using RedstoneDataFeedLib for AggregatorV3Interface; + using FixedPointMathLib for uint256; + + error RateProvider__InvalidParam(); + + uint256 private constant PRECISION = 1e18; + + address private constant USDC_BRIDGED = 0x29219dd400f2Bf60E5a23d13Be72B486D4038894; + address private constant SCUSD = 0xd3DCe716f3eF535C5Ff8d041c1A41C3bd89b97aE; + address private constant SCUSD_USDC_REDSTONE_FEED = 0xb81131B6368b3F0a83af09dB4E39Ac23DA96C2Db; + + /// @dev hardcode price of usdc.e to PRECISION + function rate(address token) external view returns (uint256) { + if (token == USDC_BRIDGED) { + return PRECISION; + } else if (token == SCUSD) { + AggregatorV3Interface feed = AggregatorV3Interface(SCUSD_USDC_REDSTONE_FEED); + uint256 priceInUsdc = feed.getPrice(); + uint256 decimals = feed.getDecimals(); + return priceInUsdc.mulWad(10 ** (36 - decimals)); + } else { + revert RateProvider__InvalidParam(); + } + } +} diff --git a/tests/Aggregator.t.sol b/tests/Aggregator.t.sol index eb02cc4..ad4f697 100644 --- a/tests/Aggregator.t.sol +++ b/tests/Aggregator.t.sol @@ -134,9 +134,14 @@ contract AggregatorTest is Test { vm.stopPrank(); uint256 unadjustedRate = IRateProvider(rateProvider).rate(token); // price of the asset scaled to 18 precision - uint256 amount = - (total * weights[i] * 1e18 * 1e10) / (unadjustedRate * (10 ** (36 - ERC20(token).decimals()))); - amounts[i] = amount; + + // uint256 amount = + // (total * weights[i] * 1e18 * 1e10) / (unadjustedRate * (10 ** (36 - ERC20(token).decimals()))); + // amounts[i] = amount; + + amounts[i] = FixedPointMathLib.divUp( + FixedPointMathLib.mulDiv(total, weights[i], unadjustedRate), (10 ** (18 - ERC20(token).decimals())) + ); } return amounts; } @@ -146,7 +151,7 @@ contract AggregatorTest is Test { uint256 numTokens = pool.numTokens(); uint256[] memory amounts1 = new uint256[](numTokens); - uint256 total1 = 100 * 1e8; + uint256 total1 = 100 * 1e18; amounts1 = _calculateSeedAmounts(total1); @@ -163,7 +168,7 @@ contract AggregatorTest is Test { function test__deposit() public { uint256 numTokens = pool.numTokens(); uint256[] memory amounts = new uint256[](numTokens); - uint256 total1 = 100 * 1e8; + uint256 total1 = 100 * 1e18; amounts = _calculateSeedAmounts(total1); // approve agg as spender @@ -183,10 +188,46 @@ contract AggregatorTest is Test { assert(shares == (vault.balanceOf(alice) - sharesOfAlice)); } + function test__depositSingle() public { + uint256 numTokens = pool.numTokens(); + uint256[] memory amounts = new uint256[](numTokens); + uint256[] memory amountsEstimated = new uint256[](numTokens); + uint256 total1 = 100 * 1e18; + amounts = _calculateSeedAmounts(total1); + amountsEstimated[0] = amounts[0]; + amounts[1] = 0; + amounts[2] = 0; + amountsEstimated[1] = 0; + amountsEstimated[2] = 0; + + uint256 ss = vm.snapshotState(); + + vm.startPrank(alice); + uint256 lpTokens = pool.addLiquidity(amountsEstimated, 0, alice); + poolToken.approve(address(vault), lpTokens); + uint256 sharesEstimated = vault.deposit(lpTokens, alice); + vm.stopPrank(); + + vm.revertToState(ss); + + vm.startPrank(alice); + require(ERC20(pool.tokens(0)).approve(address(agg), type(uint256).max), "could not approve"); + vm.stopPrank(); + + uint256 sharesOfAlice = vault.balanceOf(alice); + + vm.startPrank(alice); + uint256 shares = agg.depositSingle(0, amounts[0], alice, 0, address(pool)); + vm.stopPrank(); + + assert(shares == (vault.balanceOf(alice) - sharesOfAlice)); + assert(sharesEstimated == shares); + } + function test__depositFor() public { uint256 numTokens = pool.numTokens(); uint256[] memory amounts = new uint256[](numTokens); - uint256 total1 = 100 * 1e8; + uint256 total1 = 100 * 1e18; amounts = _calculateSeedAmounts(total1); // approve agg as spender @@ -197,6 +238,9 @@ contract AggregatorTest is Test { vm.stopPrank(); } + vm.startPrank(alice); + require(ERC20(pool.tokens(0)).approve(address(agg), type(uint256).max), "could not approve"); + vm.stopPrank(); uint256 sharesOfAlice = vault.balanceOf(alice); vm.startPrank(alice); @@ -206,6 +250,46 @@ contract AggregatorTest is Test { assert(shares == (vault.balanceOf(alice) - sharesOfAlice)); } + function test__depositForSingle() public { + uint256 numTokens = pool.numTokens(); + uint256[] memory amounts = new uint256[](numTokens); + uint256[] memory amountsEstimated = new uint256[](numTokens); + uint256 total1 = 100 * 1e18; + amounts = _calculateSeedAmounts(total1); + amountsEstimated[0] = amounts[0]; + amounts[1] = 0; + amounts[2] = 0; + amountsEstimated[1] = 0; + amountsEstimated[2] = 0; + + uint256 ss = vm.snapshotState(); + + vm.startPrank(alice); + uint256 lpTokens = pool.addLiquidityFor(amountsEstimated, 0, alice, alice); + poolToken.approve(address(vault), lpTokens); + uint256 sharesEstimated = vault.deposit(lpTokens, alice); + vm.stopPrank(); + + vm.revertToState(ss); + + // approve agg as spender + for (uint256 i = 0; i < numTokens; i++) { + address token = tokens[i]; + vm.startPrank(alice); + require(ERC20(token).approve(address(agg), type(uint256).max), "could not approve"); + vm.stopPrank(); + } + + uint256 sharesOfAlice = vault.balanceOf(alice); + + vm.startPrank(alice); + uint256 shares = agg.depositForSingle(0, amounts[0], alice, 0, address(pool)); + vm.stopPrank(); + + assert(shares == (vault.balanceOf(alice) - sharesOfAlice)); + assert(sharesEstimated == shares); + } + function test__redeemBalanced() public { PoolEstimator estimator = new PoolEstimator(address(pool)); uint256 aliceShares = vault.balanceOf(alice); diff --git a/tests/PoolSeedingTest.t.sol b/tests/PoolSeedingTest.t.sol index dfe37a7..16d2ada 100644 --- a/tests/PoolSeedingTest.t.sol +++ b/tests/PoolSeedingTest.t.sol @@ -5,6 +5,7 @@ import {console} from "../lib/forge-std/src/console.sol"; import {Test} from "../lib/forge-std/src/Test.sol"; import {ERC20} from "../lib/solady/src/tokens/ERC20.sol"; +import {ERC4626} from "../lib/solady/src/tokens/ERC4626.sol"; import {SafeTransferLib} from "../lib/solady/src/utils/SafeTransferLib.sol"; import {FixedPointMathLib} from "../lib/solady/src/utils/FixedPointMathLib.sol"; @@ -23,34 +24,164 @@ import {LogExpMath} from "../src/BalancerLibCode/LogExpMath.sol"; contract PoolAdd is Test { Pool pool; PoolToken poolToken; - Vault staking; + Vault vault; IRateProvider rp; uint256 public constant PRECISION = 1e18; uint256 public constant MAX_NUM_TOKENS = 32; uint256 public amplification; - uint256 private decimals = 8; + uint256 private decimals = 18; address public poolOwner; - address private SWBTCWBTC_CURVE = 0x73e4BeC1A111869F395cBB24F6676826BF86d905; - address private SWBTC = 0x8DB2350D78aBc13f5673A411D4700BCF87864dDE; - address private GAUNTLET_WBTC_CORE = 0x443df5eEE3196e9b2Dd77CaBd3eA76C3dee8f9b2; + address private ADMIN_ADDRESS = 0x49b3cF9E95566FC769eA22Bc7633906878794c86; + // 0x1b514df3413DA9931eB31f2Ab72e32c0A507Cad5; + address private constant SUSDE = 0x9D39A5DE30e57443BfF2A8307A4256c8797A3497; + address private constant SDAISUSDE_CURVE = 0x167478921b907422F8E88B43C4Af2B8BEa278d3A; + address private constant YPTSUSDE = 0x57fC2D9809F777Cd5c8C433442264B6E8bE7Fce4; + address private constant GAUNTLET_USDC_PRIME = 0xdd0f28e19C1780eb6396170735D45153D261490d; - MockToken public token0 = MockToken(SWBTCWBTC_CURVE); - MockToken public token1 = MockToken(SWBTC); - MockToken public token2 = MockToken(GAUNTLET_WBTC_CORE); + address private constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + address private constant USDE = 0x4c9EDD5852cd905f086C759E8383e09bff1E68B3; + address private constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address private constant SDAI = 0x83F20F44975D03b1b09e64809B757c47f942BEeA; - address[] public tokens = new address[](3); - uint256[] public weights = new uint256[](3); - address[] rateProviders = new address[](3); + MockToken public token0 = MockToken(SUSDE); + MockToken public token1 = MockToken(SDAISUSDE_CURVE); + MockToken public token2 = MockToken(YPTSUSDE); + MockToken public token3 = MockToken(GAUNTLET_USDC_PRIME); - uint256[] public seedAmounts = new uint256[](3); + address[] public tokens = new address[](4); + uint256[] public weights = new uint256[](4); + address[] rateProviders = new address[](4); + + uint256[] public seedAmounts = new uint256[](4); - address jake = makeAddr("jake"); // pool and staking owner address alice = makeAddr("alice"); // first LP address bob = makeAddr("bob"); // second LP + // function setUp() public { + // vm.createSelectFork(vm.rpcUrl("http://127.0.0.1:8545")); + // poolToken = PoolToken(0x37da1F0AADe11970F6c9B770a05D65D880ba36d3); + // pool = Pool(0xec970a39fc83A492103Ed707a290e050E2DA375c); + // vault = Vault(0xEf1BCC329081f04059b766F04C4A617AdF462934); + // rp = IRateProvider(0x2F6ac41126575B74eD71e7d0F299b9dEDd9D2287); + // } + + // function test__seedPoolAndSetUpVault() public { + // deal(DAI, ADMIN_ADDRESS, 50_000_000e18); + // deal(USDE, ADMIN_ADDRESS, 50_000_000e18); + // deal(USDC, ADMIN_ADDRESS, 50_000_000e6); + + // seedAmounts = _calculateSeedAmounts(50_000e18); + + // vm.startPrank(ADMIN_ADDRESS); + // uint256 poolTokensMinted = pool.addLiquidity(seedAmounts1, 49_000e18, ADMIN_ADDRESS); + // poolToken.approve(address(vault), type(uint256).max); + // uint256 vaultSharesMinted = vault.deposit(poolTokensMinted, ADMIN_ADDRESS); + // vm.stopPrank(); + // } + + // function _mintMorphoShares(uint256 mintAmounts) internal returns (uint256) { + // vm.startPrank(ADMIN_ADDRESS); + + // // approve Morpho Vault to spend USDC + // (bool success, bytes memory data) = USDC.call( + // abi.encodeWithSelector( + // bytes4(keccak256("approve(address,uint256)")), GAUNTLET_USDC_PRIME, type(uint256).max + // ) + // ); + // require(success, "could not approve Morpho Vault contract to spend USDC."); + // uint256 usdcDeposited = ERC4626(GAUNTLET_USDC_PRIME).mint(mintAmounts, ADMIN_ADDRESS); + // console.log("usdcDeposited:", usdcDeposited); + // vm.stopPrank(); + // } + + // function _mintYptsusde(uint256 mintAmount) internal returns (uint256 sharesMinted) { + // vm.startPrank(ADMIN_ADDRESS); + + // // approve sUSDe to spend USDe + // (bool success, bytes memory data) = + // USDE.call(abi.encodeWithSelector(bytes4(keccak256("approve(address,uint256)")), SUSDE, type(uint256).max)); + // require(success, "could not approve sUSDe contract to spend USDe."); + + // uint256 susdeAmount = ERC4626(YPTSUSDE).previewMint(mintAmount); + // uint256 usdeAmount = ERC4626(SUSDE).previewMint(susdeAmount); + + // // deposit USDE into SUSDE + // (success, data) = + // SUSDE.call(abi.encodeWithSelector(bytes4(keccak256("deposit(uint256,address)")), usdeAmount, ADMIN_ADDRESS)); + // require(success, "could not deposit USDe into sUSDe contract."); + // uint256 susdeBalance = abi.decode(data, (uint256)); + // (success, data) = SUSDE.call( + // abi.encodeWithSelector(bytes4(keccak256("approve(address,uint256)")), YPTSUSDE, type(uint256).max) + // ); + // uint256 susdeDeposited = ERC4626(YPTSUSDE).mint(mintAmount, ADMIN_ADDRESS); + // console.log("susde deposited:", susdeDeposited); + // vm.stopPrank(); + // } + + // function _addLiquidityToCurve(uint256 usdeAmount) internal returns (uint256 lpMinted) { + // vm.startPrank(ADMIN_ADDRESS); + + // (bool success, bytes memory data) = + // USDE.call(abi.encodeWithSelector(bytes4(keccak256("approve(address,uint256)")), SUSDE, type(uint256).max)); + // require(success, "could not approve sUSDe contract to spend USDe."); + + // // deposit USDE into SUSDE + // (success, data) = + // SUSDE.call(abi.encodeWithSelector(bytes4(keccak256("deposit(uint256,address)")), usdeAmount, ADMIN_ADDRESS)); + // require(success, "could not deposit USDe into sUSDe contract."); + // uint256 susdeBalance = abi.decode(data, (uint256)); + // uint256[] memory lpAmount = new uint256[](2); + // lpAmount[1] = susdeBalance; + // (success, data) = SUSDE.call( + // abi.encodeWithSelector(bytes4(keccak256("approve(address,uint256)")), SDAISUSDE_CURVE, type(uint256).max) + // ); + // require(success, "could not approve SDAISUSDE_CURVE contract to spend sUSDe."); + + // // add liquidity to curve pool + // (success, data) = SDAISUSDE_CURVE.call( + // abi.encodeWithSelector( + // bytes4(keccak256("add_liquidity(uint256[],uint256,address)")), lpAmount, 0, ADMIN_ADDRESS + // ) + // ); + + // console.log("susde added:", susdeBalance); + + // lpMinted = abi.decode(data, (uint256)); + // vm.stopPrank(); + // } + + // function _mintSusde(uint256 mintAmount) internal { + // vm.startPrank(ADMIN_ADDRESS); + // require(ERC20(USDE).approve(SUSDE, type(uint256).max)); + // uint256 usdeDeposited = ERC4626(SUSDE).mint(mintAmount, ADMIN_ADDRESS); + // console.log("USDE deposited:", usdeDeposited); + // vm.stopPrank(); + // } + + // /// @param totalAmount total amount of lp tokens to be minted by seeding the pool + // function _calculateSeedAmounts(uint256 totalAmount) internal returns (uint256[] memory) { + // uint256 n = pool.numTokens(); + // uint256[] memory amounts = new uint256[](n); + // for (uint256 i = 0; i < n; i++) { + // address token = pool.tokens(i); + // address rateProvider = pool.rateProviders(i); + // (uint256 weight,,,) = pool.weight(i); + + // // vm.startPrank(ADMIN_ADDRESS); + // // require(ERC20(token).approve(address(pool), type(uint256).max), "could not approve"); + // // vm.stopPrank(); + // uint256 unadjustedRate = IRateProvider(rateProvider).rate(token); + // // amount = (total * weight) / rate + // amounts[i] = FixedPointMathLib.divUp( + // FixedPointMathLib.mulDiv(totalAmount, weight, unadjustedRate), (10 ** (18 - ERC20(token).decimals())) + // ); + // } + // return amounts; + // } + // function setUp() public { // vm.createSelectFork(vm.rpcUrl("http://127.0.0.1:8545"));