From 95bb311925a8883390d6d86d44adc8a18bbac8ec Mon Sep 17 00:00:00 2001 From: Ian Lucas Date: Thu, 17 Oct 2024 20:03:56 -0400 Subject: [PATCH] Update Liquid Deploy and Load script to load data around cut-off times --- packages/contracts/resource/local.toml | 2 ++ .../script/DeployLiquidMultiTokenVault.s.sol | 17 ++++++---- ...uidContinuousMultiTokenVaultUtilTest.t.sol | 5 ++- .../DeployAndLoadLiquidMultiTokenVault.s.sol | 31 +++++++++++++++---- ...ployAndLoadLiquidMultiTokenVaultTest.t.sol | 27 ++++++++++++++++ .../test/token/ERC1155/TestParamSet.t.sol | 2 +- ...uidContinuousMultiTokenVaultTestBase.t.sol | 9 ++++-- 7 files changed, 74 insertions(+), 19 deletions(-) create mode 100644 packages/contracts/test/test/script/DeployAndLoadLiquidMultiTokenVaultTest.t.sol diff --git a/packages/contracts/resource/local.toml b/packages/contracts/resource/local.toml index 624c10d8..8a8db470 100644 --- a/packages/contracts/resource/local.toml +++ b/packages/contracts/resource/local.toml @@ -24,6 +24,8 @@ asset_manager = "0x976EA74026E726554dB657fA54763abd0C3a0aa9" full_rate_bps = 10_00 # rate in basis points, e.g. 5.5% = 550 bps reduced_rate_bps = 5_50 +# January 1, 2024 2:00:00 PM UTC = 1704117600 +vault_start_timestamp = 1704117600 [evm.contracts.upside_vault] # 2 decimal place percentage (meaining value divided by 100) as integer. diff --git a/packages/contracts/script/DeployLiquidMultiTokenVault.s.sol b/packages/contracts/script/DeployLiquidMultiTokenVault.s.sol index a4f57a92..7f9e647b 100644 --- a/packages/contracts/script/DeployLiquidMultiTokenVault.s.sol +++ b/packages/contracts/script/DeployLiquidMultiTokenVault.s.sol @@ -28,9 +28,10 @@ contract DeployLiquidMultiTokenVault is TomlConfig { using stdToml for string; string private _tomlConfig; - LiquidContinuousMultiTokenVault.VaultAuth public _vaultAuth; + LiquidContinuousMultiTokenVault.VaultAuth internal _vaultAuth; uint256 public constant NOTICE_PERIOD = 1; + string public constant CONTRACT_TOML_KEY = ".evm.contracts.liquid_continuous_multi_token_vault"; constructor() { _tomlConfig = loadTomlConfiguration(); @@ -103,11 +104,9 @@ contract DeployLiquidMultiTokenVault is TomlConfig { IYieldStrategy yieldStrategy, IRedeemOptimizer redeemOptimizer ) public view returns (LiquidContinuousMultiTokenVault.VaultParams memory vaultParams_) { - string memory contractKey = ".evm.contracts.liquid_continuous_multi_token_vault"; - uint256 fullRateBasisPoints = _tomlConfig.readUint(string.concat(contractKey, ".full_rate_bps")); - uint256 reducedRateBasisPoints = _tomlConfig.readUint(string.concat(contractKey, ".reduced_rate_bps")); - uint256 startTimestamp = - _readUintWithDefault(_tomlConfig, string.concat(contractKey, ".vault_start_timestamp"), block.timestamp); + uint256 fullRateBasisPoints = _tomlConfig.readUint(string.concat(CONTRACT_TOML_KEY, ".full_rate_bps")); + uint256 reducedRateBasisPoints = _tomlConfig.readUint(string.concat(CONTRACT_TOML_KEY, ".reduced_rate_bps")); + uint256 startTimestamp = _startTimestamp(); uint256 scale = 10 ** asset.decimals(); @@ -135,6 +134,12 @@ contract DeployLiquidMultiTokenVault is TomlConfig { return vaultParams; } + function _startTimestamp() internal view virtual returns (uint256 startTimestamp_) { + return _readUintWithDefault( + _tomlConfig, string.concat(CONTRACT_TOML_KEY, ".vault_start_timestamp"), block.timestamp + ); + } + function _usdcOrDeployMock(address contractOwner) internal returns (IERC20Metadata asset) { bool shouldDeployMocks = _readBoolWithDefault(_tomlConfig, ".evm.deploy_mocks", false); diff --git a/packages/contracts/test/src/yield/LiquidContinuousMultiTokenVaultUtilTest.t.sol b/packages/contracts/test/src/yield/LiquidContinuousMultiTokenVaultUtilTest.t.sol index f2a1c0d6..495df2af 100644 --- a/packages/contracts/test/src/yield/LiquidContinuousMultiTokenVaultUtilTest.t.sol +++ b/packages/contracts/test/src/yield/LiquidContinuousMultiTokenVaultUtilTest.t.sol @@ -17,7 +17,7 @@ import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.so import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; -// Tets relation to the Utility / operational aspects of the LiquidContinuousMultiTokenVault +// Tests related to the Utility / operational aspects of the LiquidContinuousMultiTokenVault contract LiquidContinuousMultiTokenVaultUtilTest is LiquidContinuousMultiTokenVaultTestBase { function test__LiquidContinuousMultiTokenVaultUtil__Upgradeability() public { LiquidContinuousMultiTokenVaultMock vaultImpl = new LiquidContinuousMultiTokenVaultMock(); @@ -212,14 +212,13 @@ contract LiquidContinuousMultiTokenVaultUtilTest is LiquidContinuousMultiTokenVa _setPeriodAndAssert(_liquidVault, 10); } - // vm.startPrank(_vaultAuth.operator); function _setPeriodAndAssert(LiquidContinuousMultiTokenVault vault, uint256 newPeriod) internal { assertTrue( Timer.timestamp() >= (vault._vaultStartTimestamp() - newPeriod * 24 hours), "trying to set period before block.timestamp" ); - _setPeriod(vault, newPeriod); + _setPeriod(_vaultAuth.operator, vault, newPeriod); assertEq(newPeriod, (block.timestamp - vault._vaultStartTimestamp()) / 24 hours, "timestamp not set correctly"); assertEq(newPeriod, vault.currentPeriod(), "period not set correctly"); diff --git a/packages/contracts/test/test/script/DeployAndLoadLiquidMultiTokenVault.s.sol b/packages/contracts/test/test/script/DeployAndLoadLiquidMultiTokenVault.s.sol index c80292dc..a05516a8 100644 --- a/packages/contracts/test/test/script/DeployAndLoadLiquidMultiTokenVault.s.sol +++ b/packages/contracts/test/test/script/DeployAndLoadLiquidMultiTokenVault.s.sol @@ -60,9 +60,9 @@ contract DeployAndLoadLiquidMultiTokenVault is DeployLiquidMultiTokenVault { } // --------------------- load deposits --------------------- - _loadDepositsAndRequestSells(vault, _alice, 10); - _loadDepositsAndRequestSells(vault, _bob, 1); - _loadDepositsAndRequestSells(vault, _charlie, 2); + _loadDepositsAndRequestSells(vault, _alice, 10, 0); + _loadDepositsAndRequestSells(vault, _bob, 1, 1); + _loadDepositsAndRequestSells(vault, _charlie, 2, -1); return vault; } @@ -70,7 +70,8 @@ contract DeployAndLoadLiquidMultiTokenVault is DeployLiquidMultiTokenVault { function _loadDepositsAndRequestSells( LiquidContinuousMultiTokenVault vault, AnvilWallet userWallet, - uint256 userDepositMultiplier + uint256 userDepositMultiplier, + int256 userOffsetInSeconds // exercise deposits/redeems around cut-off times ) internal { IERC20 asset = IERC20(vault.asset()); uint256 scale = 10 ** IERC20Metadata(vault.asset()).decimals(); @@ -92,7 +93,7 @@ contract DeployAndLoadLiquidMultiTokenVault is DeployLiquidMultiTokenVault { for (uint256 depositPeriod = 0; depositPeriod <= vault.TENOR(); ++depositPeriod) { // first set the start time / period as operator - _setPeriod(vault, depositPeriod); + _setPeriod(vault, depositPeriod, userOffsetInSeconds); if (depositPeriod % 7 == 0) { // skip deposits every 7th day @@ -119,9 +120,19 @@ contract DeployAndLoadLiquidMultiTokenVault is DeployLiquidMultiTokenVault { console2.log("VaultSupply after deposits %s -> %s", prevSupply, vault.totalSupply()); } - function _setPeriod(LiquidContinuousMultiTokenVault vault, uint256 newPeriod) public { + function _setPeriod(LiquidContinuousMultiTokenVault vault, uint256 newPeriod, int256 offsetInSeconds) public { uint256 prevPeriod = vault.currentPeriod(); + uint256 newPeriodInSeconds = newPeriod * 1 days; + + // add (or subtract) an offset number of seconds from the newPeriod + if (offsetInSeconds >= 0) { + newPeriodInSeconds += uint256(offsetInSeconds); + } else { + // if newPeriod is 0 and offset is negative, just stay at 0 + newPeriodInSeconds -= newPeriod == 0 ? 0 : uint256(int256(-offsetInSeconds)); + } + uint256 currentTime = Timer.timestamp(); uint256 newStartTime = @@ -133,6 +144,14 @@ contract DeployAndLoadLiquidMultiTokenVault is DeployLiquidMultiTokenVault { console2.log("VaultCurrentPeriod updated %s -> %s", prevPeriod, vault.currentPeriod()); } + + function startTimestamp() public view virtual returns (uint256 startTimestamp_) { + return _startTimestamp(); + } + + function auth() public view virtual returns (LiquidContinuousMultiTokenVault.VaultAuth memory auth_) { + return _vaultAuth; + } } //Anvil Accounts diff --git a/packages/contracts/test/test/script/DeployAndLoadLiquidMultiTokenVaultTest.t.sol b/packages/contracts/test/test/script/DeployAndLoadLiquidMultiTokenVaultTest.t.sol new file mode 100644 index 00000000..4667459d --- /dev/null +++ b/packages/contracts/test/test/script/DeployAndLoadLiquidMultiTokenVaultTest.t.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import { LiquidContinuousMultiTokenVault } from "@credbull/yield/LiquidContinuousMultiTokenVault.sol"; +import { LiquidContinuousMultiTokenVaultTestBase } from "@test/test/yield/LiquidContinuousMultiTokenVaultTestBase.t.sol"; +import { DeployAndLoadLiquidMultiTokenVault } from "./DeployAndLoadLiquidMultiTokenVault.s.sol"; + +contract DeployAndLoadLiquidMultiTokenVaultTest is LiquidContinuousMultiTokenVaultTestBase { + DeployAndLoadLiquidMultiTokenVault internal _deployVault; + + function setUp() public override { + _deployVault = new DeployAndLoadLiquidMultiTokenVault(); + + uint256 vaultStartTimestamp = _deployVault.startTimestamp(); + vm.warp(vaultStartTimestamp); // warp to a "real time" time rather than block.timestamp=1 + + _liquidVault = _deployVault.run(); + } + + /// @dev - this SHOULD work, but will have knock-off effects to yield/returns and pending requests + function test__DeployAndLoadLiquidMultiTokenVaultTest__VerifyCutoffs() public { + LiquidContinuousMultiTokenVault.VaultAuth memory vaultAuth = _deployVault.auth(); + + _setPeriod(vaultAuth.operator, _liquidVault, 0); + _setPeriod(vaultAuth.operator, _liquidVault, 30); + } +} diff --git a/packages/contracts/test/test/token/ERC1155/TestParamSet.t.sol b/packages/contracts/test/test/token/ERC1155/TestParamSet.t.sol index 79c345a0..7d7c7811 100644 --- a/packages/contracts/test/test/token/ERC1155/TestParamSet.t.sol +++ b/packages/contracts/test/test/token/ERC1155/TestParamSet.t.sol @@ -37,7 +37,7 @@ library TestParamSet { } // Calculate the total principal across all TestParams - function latestRedeemPeriod(TestParam[] memory self) internal pure returns (uint256 latestRedeemPeriod) { + function latestRedeemPeriod(TestParam[] memory self) internal pure returns (uint256 latestRedeemPeriod_) { uint256 _latestRedeemPeriod = 0; for (uint256 i = 0; i < self.length; i++) { uint256 redeemPeriod = self[i].redeemPeriod; diff --git a/packages/contracts/test/test/yield/LiquidContinuousMultiTokenVaultTestBase.t.sol b/packages/contracts/test/test/yield/LiquidContinuousMultiTokenVaultTestBase.t.sol index 340add29..545c41ed 100644 --- a/packages/contracts/test/test/yield/LiquidContinuousMultiTokenVaultTestBase.t.sol +++ b/packages/contracts/test/test/yield/LiquidContinuousMultiTokenVaultTestBase.t.sol @@ -36,10 +36,13 @@ abstract contract LiquidContinuousMultiTokenVaultTestBase is IMultiTokenVaultTes address internal alice = makeAddr("alice"); address internal bob = makeAddr("bob"); - function setUp() public { + function setUp() public virtual { DeployLiquidMultiTokenVault _deployVault = new DeployLiquidMultiTokenVault(); _liquidVault = _deployVault.run(_vaultAuth); + // warp to a "real time" time rather than block.timestamp=1 + vm.warp(_liquidVault._vaultStartTimestamp() + 1); + _asset = IERC20Metadata(_liquidVault.asset()); _scale = 10 ** _asset.decimals(); @@ -224,14 +227,14 @@ abstract contract LiquidContinuousMultiTokenVaultTestBase is IMultiTokenVaultTes vm.warp(warpToTimeInSeconds); } - function _setPeriod(LiquidContinuousMultiTokenVault vault, uint256 newPeriod) public { + function _setPeriod(address operator, LiquidContinuousMultiTokenVault vault, uint256 newPeriod) public { uint256 newPeriodInSeconds = newPeriod * 1 days; uint256 currentTime = Timer.timestamp(); uint256 newStartTime = currentTime > newPeriodInSeconds ? (currentTime - newPeriodInSeconds) : (newPeriodInSeconds - currentTime); - vm.prank(_vaultAuth.operator); + vm.prank(operator); vault.setVaultStartTimestamp(newStartTime); }