add tax rate adjustment

This commit is contained in:
JulesCrown 2024-04-15 07:08:13 +02:00
parent 4845129fe3
commit 3225be1084
4 changed files with 33 additions and 17 deletions

View file

@ -30,6 +30,7 @@ contract Stake is IStake {
error PositionNotFound();
event PositionCreated(uint256 indexed positionId, address indexed owner, uint256 share, uint32 creationTime, uint32 taxRate);
event TaxPaid(uint256 indexed positionId, address indexed owner, uint256 taxAmount);
event PositionRemoved(uint256 indexed positionId, uint256 share, uint32 lastTaxTime);
struct StakingPosition {
@ -123,7 +124,7 @@ contract Stake is IStake {
}
// dissolve position
// TODO: what if someone calls payTax and exitPosition in the same transaction?
_payTax(pos, 0);
_payTax(positionsToSnatch[i], pos, 0);
_exitPosition(positionsToSnatch[i], pos);
// TODO: exit positions partially, if needed
// TODO: avoid greeving where more positions are freed than needed.
@ -151,20 +152,31 @@ contract Stake is IStake {
emit PositionCreated(positionId, sp.owner, sp.share, sp.creationTime, sp.taxRate);
}
function changeTax(uint256 positionID, uint32 taxRate) public {
StakingPosition storage pos = positions[positionID];
if (pos.owner != msg.sender) {
revert NoPermission(msg.sender, pos.owner);
}
// to prevent snatch-and-change grieving attack, pay TAX_FLOOR_DURATION
require(taxRate > pos.taxRate);
_payTax(positionID, pos, TAX_FLOOR_DURATION);
pos.taxRate = taxRate;
}
function exitPosition(uint256 positionId) public {
StakingPosition storage pos = positions[positionId];
if (pos.owner != msg.sender) {
revert NoPermission(msg.sender, pos.owner);
}
// to prevent snatch-and-exit grieving attack, pay TAX_FLOOR_DURATION
_payTax(pos, TAX_FLOOR_DURATION);
_payTax(positionId, pos, TAX_FLOOR_DURATION);
_exitPosition(positionId, pos);
}
function payTax(uint256 positionID) public {
StakingPosition storage pos = positions[positionID];
// TODO: what if someone calls payTax and exitPosition in the same transaction?
_payTax(pos, 0);
_payTax(positionID, pos, 0);
}
function taxDue(uint256 positionID, uint256 taxFloorDuration) public view returns (uint256 amountDue) {
@ -178,7 +190,7 @@ contract Stake is IStake {
amountDue = assetsBefore * pos.taxRate * elapsedTime / (365 * 24 * 60 * 60) / TAX_RATE_BASE;
}
function _payTax(StakingPosition storage pos, uint256 taxFloorDuration) private {
function _payTax(uint256 positionID, StakingPosition storage pos, uint256 taxFloorDuration) private {
// ihet = Implied Holding Expiry Timestamp
uint256 ihet = (block.timestamp - pos.creationTime < taxFloorDuration)
? pos.creationTime + taxFloorDuration
@ -191,6 +203,7 @@ contract Stake is IStake {
taxAmountDue = assetsBefore;
}
SafeERC20.safeTransfer(tokenContract, taxPool, taxAmountDue);
emit TaxPaid(positionID, pos.owner, taxAmountDue);
if (assetsBefore - taxAmountDue > 0) {
// if something left over, update storage
pos.share = assetsToShares(assetsBefore - taxAmountDue, Math.Rounding.Down);
@ -199,6 +212,7 @@ contract Stake is IStake {
// if nothing left over, liquidate position
// TODO: emit event
outstandingStake -= pos.share;
emit PositionRemoved(positionID, pos.share, pos.lastTaxTime);
delete pos.owner;
delete pos.creationTime;
}

View file

@ -74,7 +74,10 @@ contract BaseLineLPTest is Test {
harb.setLiquidityManager(address(liquidityManager));
}
function testLP(address account, uint256 amount) public {
function testLP(address account) public {
vm.assume(account != address(0));
vm.assume(account != address(1)); // TWAB sponsorship address
vm.assume(account != address(2)); // tax pool address
vm.deal(account, 10 ether);
vm.prank(account);
(bool sent, ) = address(liquidityManager).call{value: 10 ether}("");
@ -83,7 +86,6 @@ contract BaseLineLPTest is Test {
vm.expectRevert();
liquidityManager.shift();
int24 startTick = (address(weth) < address(harb)) ? int24(128219) : int24(-128219); //initialize at 1 cent
liquidityManager.slide();
}
}