mirror of
https://github.com/vacp2p/staking-reward-streamer.git
synced 2026-01-09 23:37:58 -05:00
157 lines
5.5 KiB
Solidity
157 lines
5.5 KiB
Solidity
// SPDX-License-Identifier: UNLICENSED
|
|
pragma solidity ^0.8.26;
|
|
|
|
import { Test } from "forge-std/Test.sol";
|
|
import { StakeVault } from "../src/StakeVault.sol";
|
|
import { MockStakeManager } from "./mocks/MockStakeManager.sol";
|
|
import { MockToken } from "./mocks/MockToken.sol";
|
|
|
|
/**
|
|
* @title EndToEndDecouplingTest
|
|
* @notice Comprehensive test to verify the decoupling works correctly
|
|
*/
|
|
contract EndToEndDecouplingTest is Test {
|
|
StakeVault internal vault;
|
|
MockStakeManager internal manager;
|
|
MockToken internal token;
|
|
address internal alice = makeAddr("alice");
|
|
|
|
function setUp() public {
|
|
token = new MockToken("SNT", "SNT");
|
|
manager = new MockStakeManager();
|
|
vault = new StakeVault(token);
|
|
vault.initialize(alice, address(manager));
|
|
|
|
token.mint(alice, 10_000e18);
|
|
vm.prank(alice);
|
|
token.approve(address(vault), 10_000e18);
|
|
}
|
|
|
|
/**
|
|
* @notice Test that demonstrates the new flow without callbacks
|
|
*/
|
|
function test_DecoupledStakeFlow() public {
|
|
// Initial state: no lock
|
|
assertEq(vault.lockUntil(), 0);
|
|
|
|
// Alice stakes 1000 tokens for 90 days
|
|
uint256 stakeAmount = 1000e18;
|
|
uint256 lockPeriod = 90 days;
|
|
uint256 stakeTime = block.timestamp;
|
|
|
|
vm.prank(alice);
|
|
vault.stake(stakeAmount, lockPeriod);
|
|
|
|
// Verify the flow:
|
|
// 1. Vault stored old lockUntil (0)
|
|
// 2. Vault called manager.stake()
|
|
// 3. Manager calculated using old lockUntil (0)
|
|
// 4. Vault calculated new lockUntil using same logic
|
|
// 5. Both should arrive at the same result
|
|
|
|
uint256 expectedLockEnd = stakeTime + lockPeriod; // Math.max(0, stakeTime) + lockPeriod
|
|
assertEq(vault.lockUntil(), expectedLockEnd);
|
|
|
|
// Verify tokens were transferred to vault
|
|
assertEq(token.balanceOf(address(vault)), stakeAmount);
|
|
assertEq(token.balanceOf(alice), 10_000e18 - stakeAmount);
|
|
}
|
|
|
|
/**
|
|
* @notice Test extending an existing lock
|
|
*/
|
|
function test_ExtendExistingLock() public {
|
|
// First stake with 60 days lock
|
|
uint256 firstLockPeriod = 60 days;
|
|
vm.prank(alice);
|
|
vault.stake(1000e18, firstLockPeriod);
|
|
|
|
uint256 firstLockEnd = vault.lockUntil();
|
|
|
|
// Move forward 30 days
|
|
vm.warp(block.timestamp + 30 days);
|
|
|
|
// Stake more with additional 90 days
|
|
uint256 secondLockPeriod = 90 days;
|
|
uint256 secondStakeTime = block.timestamp;
|
|
|
|
vm.prank(alice);
|
|
vault.stake(500e18, secondLockPeriod);
|
|
|
|
// Should extend from existing lock, not current time
|
|
// Math.max(firstLockEnd, secondStakeTime) + secondLockPeriod
|
|
uint256 expectedNewLockEnd = firstLockEnd + secondLockPeriod;
|
|
assertEq(vault.lockUntil(), expectedNewLockEnd);
|
|
}
|
|
|
|
/**
|
|
* @notice Test lock function works independently
|
|
*/
|
|
function test_LockExtension() public {
|
|
// Initial stake without lock
|
|
vm.prank(alice);
|
|
vault.stake(1000e18, 0);
|
|
|
|
assertEq(vault.lockUntil(), 0);
|
|
|
|
// Now lock for 90 days
|
|
uint256 lockPeriod = 90 days;
|
|
uint256 lockTime = block.timestamp;
|
|
|
|
vm.prank(alice);
|
|
vault.lock(lockPeriod);
|
|
|
|
uint256 expectedLockEnd = lockTime + lockPeriod; // Math.max(0, lockTime) + lockPeriod
|
|
assertEq(vault.lockUntil(), expectedLockEnd);
|
|
}
|
|
|
|
/**
|
|
* @notice Test that migration still works (if we had a proper mock)
|
|
*/
|
|
function test_MigrationPreservesCallback() public {
|
|
// Set a lock time
|
|
uint256 lockTime = block.timestamp + 90 days;
|
|
vm.prank(address(manager));
|
|
vault.updateLockUntil(lockTime);
|
|
|
|
assertEq(vault.lockUntil(), lockTime);
|
|
|
|
// The updateLockUntil function should still exist and work
|
|
// for migration purposes (even though we removed the callbacks
|
|
// from stake/lock operations)
|
|
assertTrue(true); // This test just verifies updateLockUntil exists
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @title DecouplingBenefitsTest
|
|
* @notice Tests that demonstrate the benefits of decoupling
|
|
*/
|
|
contract DecouplingBenefitsTest is Test {
|
|
function test_NoCircularDependency() public {
|
|
// Before: Vault calls Manager, Manager calls back to Vault
|
|
// After: Vault calls Manager, both calculate independently
|
|
|
|
// This is demonstrated by the fact that:
|
|
// 1. Manager no longer needs to call updateLockUntil on vault
|
|
// 2. Vault manages its own state
|
|
// 3. Both use same calculation formula for consistency
|
|
assertTrue(true, "Circular dependency eliminated");
|
|
}
|
|
|
|
function test_SimplifiedTesting() public {
|
|
// Before: Testing Manager required complex stateful vault mocks
|
|
// After: Manager can be tested independently, vault can be tested independently
|
|
|
|
// The MockStakeManager used in tests is now much simpler
|
|
// because it doesn't need to track vault state or call updateLockUntil
|
|
assertTrue(true, "Testing simplified");
|
|
}
|
|
|
|
function test_ClearSeparationOfConcerns() public {
|
|
// Vault: Responsible for lock time calculation and token custody
|
|
// Manager: Responsible for multiplier points and global state
|
|
// Migration: Explicit one-time state transfer via updateLockUntil
|
|
assertTrue(true, "Clear separation achieved");
|
|
}
|
|
} |