Copy
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;
import "forge-std/Test.sol";
import {FirelightVault} from "../src/FirelightVault.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MockERC20 is ERC20 {
constructor() ERC20("Mock Token", "MOCK") {
_mint(msg.sender, 1000000 * 10**18);
}
function mint(address to, uint256 amount) external {
_mint(to, amount);
}
}
contract FirelightVaultTest is Test {
FirelightVault public vault;
MockERC20 public asset;
address public admin = address(1);
address public limitUpdater = address(2);
address public blocklister = address(3);
address public pauser = address(4);
address public periodConfigUpdater = address(5);
address public user = address(6);
address public userB = address(7);
address public userC = address(8);
uint256 internal constant ONE = 1e18;
uint256 internal constant PERIOD = 7 days;
function setUp() public {
// Deploy mock asset
asset = new MockERC20();
// Deploy implementation
FirelightVault implementation = new FirelightVault();
// Prepare init params
FirelightVault.InitParams memory initParams = FirelightVault.InitParams({
defaultAdmin: admin,
limitUpdater: limitUpdater,
blocklister: blocklister,
pauser: pauser,
periodConfigurationUpdater: periodConfigUpdater,
depositLimit: 1000000 * 10**18,
periodConfigurationDuration: 7 days
});
// Encode initialize call
bytes memory initData = abi.encodeWithSelector(
FirelightVault.initialize.selector,
IERC20(address(asset)),
"Firelight Vault Token",
"fVault",
abi.encode(initParams)
);
// Deploy proxy
ERC1967Proxy proxy = new ERC1967Proxy(
address(implementation),
initData
);
// Wrap proxy in vault interface
vault = FirelightVault(address(proxy));
// mint tokens to users
asset.mint(user, 100000 * 10**18);
asset.mint(userB, 100000 * 10**18);
asset.mint(userC, 100000 * 10**18);
}
function test_PeriodAtTimestamp_IgnoresArgument() public {
// @audit Ensure some baseline activity/time
_deposit(user, 10 * ONE);
uint256 current = vault.currentPeriod();
uint256 tsFuture = block.timestamp + 3 * PERIOD;
uint256 expected = current + 3;
// @audit If correct, periodAtTimestamp(tsFuture) should be current+3.
// @audit but current behavior returns "current" timestamp period
uint256 reported = vault.periodAtTimestamp(uint48(tsFuture));
assertTrue(reported != expected, "Expected misreport due to using block.timestamp internally");
}
function _deposit(address who, uint256 assets) internal returns (uint256 shares) {
vm.startPrank(who);
asset.approve(address(vault), type(uint256).max);
shares = vault.deposit(assets, who);
vm.stopPrank();
}
function _requestWithdraw(address who, uint256 assets, address receiver) internal returns (uint256 sharesBurned) {
vm.startPrank(who);
vault.approve(address(vault), type(uint256).max);
sharesBurned = vault.withdraw(assets, receiver, who);
vm.stopPrank();
}
function _advanceAtLeast(uint256 secs) internal {
vm.warp(block.timestamp + secs);
}
function _advancePastNextClaimable() internal {
_advanceAtLeast(15 days);
}
}