diff --git a/src/TimelockedAsyncRedeem.sol b/src/TimelockedAsyncRedeem.sol index 4f4691a..cb3a600 100644 --- a/src/TimelockedAsyncRedeem.sol +++ b/src/TimelockedAsyncRedeem.sol @@ -14,15 +14,15 @@ import {ERC20} from "solmate/tokens/ERC20.sol"; * * This Vault has the following properties: * - yield for the underlying asset is assumed to be transferred directly into the vault by some arbitrary mechanism - * - async redemptions are subject to a 3 day delay - * - new redemptions restart the 3 day delay even if the prior redemption is claimable. + * - async redemptions are subject to a timelock + * - new redemptions restart the timelock even if the prior redemption is claimable. * This can be resolved by using a more sophisticated algorithm for storing multiple requests. * - the redemption exchange rate is locked in immediately upon request. */ abstract contract BaseTimelockedAsyncRedeem is BaseERC7540, IERC7540Redeem { using FixedPointMathLib for uint256; - uint32 public constant TIMELOCK = 3 days; + uint32 public timelock; uint256 internal _totalPendingRedeemAssets; mapping(address => RedemptionRequest) internal _pendingRedemption; @@ -33,6 +33,14 @@ abstract contract BaseTimelockedAsyncRedeem is BaseERC7540, IERC7540Redeem { uint32 claimableTimestamp; } + constructor(uint32 timelock_) { + timelock = timelock_; + } + + function setTimelock(uint32 timelock_) public onlyOwner { + timelock = timelock_; + } + function totalAssets() public view virtual override returns (uint256) { return ERC20(asset).balanceOf(address(this)) - _totalPendingRedeemAssets; } @@ -51,7 +59,7 @@ abstract contract BaseTimelockedAsyncRedeem is BaseERC7540, IERC7540Redeem { SafeTransferLib.safeTransferFrom(this, owner, address(this), shares); _pendingRedemption[controller] = - RedemptionRequest({assets: assets, shares: shares, claimableTimestamp: uint32(block.timestamp) + TIMELOCK}); + RedemptionRequest({assets: assets, shares: shares, claimableTimestamp: uint32(block.timestamp) + timelock}); _totalPendingRedeemAssets += assets; @@ -166,5 +174,8 @@ abstract contract BaseTimelockedAsyncRedeem is BaseERC7540, IERC7540Redeem { } contract TimelockedAsyncRedeem is BaseTimelockedAsyncRedeem { - constructor(ERC20 _asset, string memory _name, string memory _symbol) BaseERC7540(_asset, _name, _symbol) {} + constructor(uint32 timelock_, ERC20 _asset, string memory _name, string memory _symbol) + BaseTimelockedAsyncRedeem(timelock_) + BaseERC7540(_asset, _name, _symbol) + {} } diff --git a/test/TestInterfaceFunctionSelectors.t.sol b/test/TestInterfaceFunctionSelectors.t.sol index 65fb2fe..4d34e5d 100644 --- a/test/TestInterfaceFunctionSelectors.t.sol +++ b/test/TestInterfaceFunctionSelectors.t.sol @@ -27,7 +27,7 @@ contract TestInterfaceFunctionSelectors is Test { ERC20 asset = new USDC(); ControlledAsyncDeposit depositExample = new ControlledAsyncDeposit(asset, "Vault Share", "TEST"); - TimelockedAsyncRedeem redeemExample = new TimelockedAsyncRedeem(asset, "Vault Share", "TEST"); + TimelockedAsyncRedeem redeemExample = new TimelockedAsyncRedeem(3 days, asset, "Vault Share", "TEST"); assertTrue(depositExample.supportsInterface(erc7575Vault)); assertTrue(depositExample.supportsInterface(erc7540Operator)); diff --git a/test/TimelockedAsyncRedeem.t.sol b/test/TimelockedAsyncRedeem.t.sol index 1cb2226..83c70f0 100644 --- a/test/TimelockedAsyncRedeem.t.sol +++ b/test/TimelockedAsyncRedeem.t.sol @@ -24,7 +24,7 @@ contract TimelockedAsyncRedeemTest is Test { deal(address(asset), user, initialAssetBalance); // Deploy the vault - vault = new TimelockedAsyncRedeem(asset, "Vault Share", "TEST"); + vault = new TimelockedAsyncRedeem(3 days, asset, "Vault Share", "TEST"); shareToken = ERC20(address(vault)); // Deposit assets to the vault