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();
}
}

View file

@ -1,6 +1,6 @@
scalar Bytes
scalar BigInt
scalar BigDecimal
# scalar Bytes
# scalar BigInt
# scalar BigDecimal
type Stats @entity {
id: Bytes!
@ -25,7 +25,7 @@ type Position @entity {
status: PositionStatus!
}
type Query {
stats: [Stats]
positions: [Position]
}
# type Query {
# stats: [Stats!]
# positions: [Position!]
#}

View file

@ -8,9 +8,9 @@ dataSources:
name: Harb
network: sepolia
source:
address: "0xcd02666582a2057085edabc55c5120155ba4e93c"
address: "0xcA85847c540a9706359E74155288Ab8e6b2475C7"
abi: Harb
startBlock: 5510934
startBlock: 5677168
mapping:
kind: ethereum/events
apiVersion: 0.0.7
@ -32,9 +32,9 @@ dataSources:
name: Stake
network: sepolia
source:
address: "0x4256777543814d66f9f66390f6bb33c55a24c331"
address: "0x22c264Ecf8D4E49D1E3CabD8DD39b7C4Ab51C1B8"
abi: Stake
startBlock: 5510935
startBlock: 5677168
mapping:
kind: ethereum/events
apiVersion: 0.0.7