2024-06-13 08:28:42 +02:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
pragma solidity ^0.8.19;
|
|
|
|
|
|
|
|
|
|
import "forge-std/Test.sol";
|
|
|
|
|
import "forge-std/console.sol";
|
|
|
|
|
import {TwabController} from "pt-v5-twab-controller/TwabController.sol";
|
|
|
|
|
import "../src/Harb.sol";
|
2024-06-19 10:33:28 +02:00
|
|
|
import "../src/Stake.sol";
|
2024-06-13 08:28:42 +02:00
|
|
|
|
|
|
|
|
contract StakeTest is Test {
|
2024-06-19 10:33:28 +02:00
|
|
|
TwabController tc;
|
2024-06-13 08:28:42 +02:00
|
|
|
Harb harb;
|
2024-06-19 10:33:28 +02:00
|
|
|
Stake stakingPool;
|
|
|
|
|
address liquidityPool;
|
|
|
|
|
address liquidityManager;
|
|
|
|
|
address taxPool;
|
|
|
|
|
|
|
|
|
|
event PositionCreated(uint256 indexed positionId, address indexed owner, uint256 share, uint32 creationTime, uint32 taxRate);
|
|
|
|
|
event PositionRemoved(uint256 indexed positionId, uint256 share, uint32 lastTaxTime);
|
2024-06-13 08:28:42 +02:00
|
|
|
|
|
|
|
|
function setUp() public {
|
2024-06-19 10:33:28 +02:00
|
|
|
tc = new TwabController(60 * 60, uint32(block.timestamp));
|
|
|
|
|
harb = new Harb("HARB", "HARB", tc);
|
|
|
|
|
taxPool = harb.TAX_POOL();
|
|
|
|
|
stakingPool = new Stake(address(harb));
|
|
|
|
|
harb.setStakingPool(address(stakingPool));
|
|
|
|
|
liquidityPool = makeAddr("liquidityPool");
|
|
|
|
|
harb.setLiquidityPool(liquidityPool);
|
|
|
|
|
liquidityManager = makeAddr("liquidityManager");
|
|
|
|
|
harb.setLiquidityManager(liquidityManager);
|
|
|
|
|
}
|
2024-06-13 08:28:42 +02:00
|
|
|
|
|
|
|
|
|
2024-06-19 10:33:28 +02:00
|
|
|
function testBasicStaking() public {
|
|
|
|
|
// Setup
|
|
|
|
|
uint256 stakeAmount = 1 ether;
|
|
|
|
|
address staker = makeAddr("staker");
|
2024-06-13 08:28:42 +02:00
|
|
|
|
2024-06-19 10:33:28 +02:00
|
|
|
vm.startPrank(liquidityManager);
|
|
|
|
|
harb.mint(stakeAmount * 5);
|
|
|
|
|
harb.transfer(staker, stakeAmount);
|
|
|
|
|
vm.stopPrank();
|
|
|
|
|
|
|
|
|
|
vm.startPrank(staker);
|
|
|
|
|
|
|
|
|
|
// Approve and stake
|
|
|
|
|
harb.approve(address(stakingPool), stakeAmount);
|
|
|
|
|
uint256[] memory empty;
|
|
|
|
|
uint256 sharesExpected = stakingPool.assetsToShares(stakeAmount);
|
|
|
|
|
vm.expectEmit(address(stakingPool));
|
|
|
|
|
emit PositionCreated(654321, staker, sharesExpected, uint32(block.timestamp), 1);
|
|
|
|
|
uint256 positionId = stakingPool.snatch(stakeAmount, staker, 1, empty);
|
|
|
|
|
|
|
|
|
|
// Check results
|
|
|
|
|
assertEq(stakingPool.outstandingStake(), stakingPool.assetsToShares(stakeAmount), "Outstanding stake did not update correctly");
|
|
|
|
|
(uint256 share, address owner, uint32 creationTime, , uint32 taxRate) = stakingPool.positions(positionId);
|
|
|
|
|
assertEq(stakingPool.sharesToAssets(share), stakeAmount, "Stake amount in position is incorrect");
|
|
|
|
|
assertEq(owner, staker, "Stake owner is incorrect");
|
|
|
|
|
assertEq(creationTime, uint32(block.timestamp), "Creation time is incorrect");
|
|
|
|
|
assertEq(taxRate, 1, "Tax rate should be initialized to 1");
|
|
|
|
|
|
|
|
|
|
vm.stopPrank();
|
2024-06-13 08:28:42 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-19 10:33:28 +02:00
|
|
|
function testUnstaking() public {
|
|
|
|
|
// Setup: Create a staking position first
|
|
|
|
|
uint256 stakeAmount = 1 ether;
|
|
|
|
|
address staker = makeAddr("staker");
|
|
|
|
|
|
|
|
|
|
vm.startPrank(liquidityManager);
|
|
|
|
|
harb.mint(stakeAmount * 5); // Ensuring the staker has enough balance
|
|
|
|
|
harb.transfer(staker, stakeAmount);
|
|
|
|
|
vm.stopPrank();
|
|
|
|
|
|
|
|
|
|
// Staker stakes tokens
|
|
|
|
|
vm.startPrank(staker);
|
|
|
|
|
harb.approve(address(stakingPool), stakeAmount);
|
2024-06-13 08:28:42 +02:00
|
|
|
uint256[] memory empty;
|
2024-06-19 10:33:28 +02:00
|
|
|
uint256 positionId = stakingPool.snatch(stakeAmount, staker, 1, empty);
|
|
|
|
|
|
|
|
|
|
// Simulate time passage to accumulate tax liability
|
|
|
|
|
vm.warp(block.timestamp + 3 days);
|
|
|
|
|
|
|
|
|
|
// Calculate expected tax due at the moment of unstaking
|
|
|
|
|
uint256 taxAmount = stakingPool.taxDue(positionId, 0);
|
|
|
|
|
uint256 assetsAfterTax = stakeAmount - taxAmount;
|
|
|
|
|
|
|
|
|
|
// Expect the PositionRemoved event with the expected parameters
|
|
|
|
|
vm.expectEmit(true, true, true, true);
|
|
|
|
|
emit PositionRemoved(positionId, stakingPool.assetsToShares(stakeAmount - taxAmount), uint32(block.timestamp));
|
|
|
|
|
|
|
|
|
|
// Perform unstaking
|
|
|
|
|
stakingPool.exitPosition(positionId);
|
|
|
|
|
|
|
|
|
|
// Check results after unstaking
|
|
|
|
|
assertEq(harb.balanceOf(staker), assetsAfterTax, "Assets after tax not returned correctly");
|
|
|
|
|
assertEq(stakingPool.outstandingStake(), 0, "Outstanding stake not updated correctly");
|
2024-06-13 08:28:42 +02:00
|
|
|
|
2024-06-19 10:33:28 +02:00
|
|
|
// Ensure the position is cleared
|
|
|
|
|
(, address owner, uint32 time, , ) = stakingPool.positions(positionId);
|
|
|
|
|
assertEq(time, 0, "Position time not cleared");
|
|
|
|
|
assertEq(owner, address(0), "Position owner not cleared");
|
2024-06-13 08:28:42 +02:00
|
|
|
|
2024-06-19 10:33:28 +02:00
|
|
|
vm.stopPrank();
|
2024-06-13 08:28:42 +02:00
|
|
|
}
|
|
|
|
|
}
|