Skip to content

Commit

Permalink
insurance pool fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
BkChoy committed Mar 20, 2024
1 parent 3b5b05b commit f35d8f1
Show file tree
Hide file tree
Showing 12 changed files with 100 additions and 5 deletions.
60 changes: 59 additions & 1 deletion contracts/core/InsurancePool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,38 @@ contract InsurancePool is StakingRewardsPool {
uint256 public maxClaimAmountBP;
bool public claimInProgress;

uint64 public withdrawalDelayDuration;
uint64 public withdrawalWindowDuration;
mapping(address => uint64) private withdrawalRequests;

event InitiateClaim();
event ExecuteClaim(uint256 amount);
event ResolveClaim();
event RequestWithdrawal(address indexed account, uint64 withdrawalStartTime);
event SetWithdrawalParams(uint64 withdrawalDelayDuration, uint64 withdrawalWindowDuration);

error SenderNotAuthorized();
error ClaimInProgress();
error ExceedsMaxClaimAmount();
error InvalidClaimAmount();
error NoClaimInProgress();
error WithdrawalWindowInactive();

function initialize(
address _lpToken,
string memory _liquidTokenName,
string memory _liquidTokenSymbol,
address _rebaseController,
uint256 _maxClaimAmountBP
uint256 _maxClaimAmountBP,
uint64 _withdrawalDelayDuration,
uint64 _withdrawalWindowDuration
) public initializer {
__StakingRewardsPool_init(_lpToken, _liquidTokenName, _liquidTokenSymbol);
rebaseController = _rebaseController;
if (_maxClaimAmountBP > 9000) revert InvalidClaimAmount();
maxClaimAmountBP = _maxClaimAmountBP;
withdrawalDelayDuration = _withdrawalDelayDuration;
withdrawalWindowDuration = _withdrawalWindowDuration;
}

modifier onlyRebaseController() {
Expand All @@ -55,9 +66,12 @@ contract InsurancePool is StakingRewardsPool {

/**
* @notice deposits tokens into the pool
* @dev will delete any active or upcoming withdrawal window
* @param _amount amount of tokens to deposit
*/
function deposit(uint256 _amount) external whileNoClaimInProgress {
if (withdrawalRequests[msg.sender] != 0) delete withdrawalRequests[msg.sender];

rewardsPool.updateReward(msg.sender);
token.safeTransferFrom(msg.sender, address(this), _amount);
_mint(msg.sender, _amount);
Expand All @@ -69,12 +83,45 @@ contract InsurancePool is StakingRewardsPool {
* @param _amount amount of tokens to withdraw
*/
function withdraw(uint256 _amount) external whileNoClaimInProgress {
if (!canWithdraw(msg.sender)) revert WithdrawalWindowInactive();

rewardsPool.updateReward(msg.sender);
_burn(msg.sender, _amount);
totalDeposits -= _amount;
token.safeTransfer(msg.sender, _amount);
}

/**
* @notice requests a withdrawal and initiates the withdrawal delay period
*/
function requestWithdrawal() external {
uint64 withdrawalStartTime = uint64(block.timestamp) + withdrawalDelayDuration;
withdrawalRequests[msg.sender] = withdrawalStartTime;
emit RequestWithdrawal(msg.sender, withdrawalStartTime);
}

/**
* @notice returns whether an account's withdrawal is active
* @param _account address of account
* @return canWithdraw whether withdrawal window is active
*/
function canWithdraw(address _account) public view returns (bool) {
if (withdrawalDelayDuration == 0) return true;
(uint64 start, uint64 end) = getWithdrawalWindow(_account);
return block.timestamp >= start && block.timestamp < end;
}

/**
* @notice returns an account's current active or upcoming withdrawal window
* @param _account address of account
* @return start time and end time of withdrawal window
*/
function getWithdrawalWindow(address _account) public view returns (uint64, uint64) {
uint64 withdrawalStartTime = withdrawalRequests[_account];
if (withdrawalDelayDuration == 0 || block.timestamp >= withdrawalStartTime + withdrawalWindowDuration) return (0, 0);
return (withdrawalStartTime, withdrawalStartTime + withdrawalWindowDuration);
}

/**
* @notice initiates the claim process
*/
Expand Down Expand Up @@ -154,6 +201,17 @@ contract InsurancePool is StakingRewardsPool {
maxClaimAmountBP = _maxClaimAmountBP;
}

/**
* @notice sets the withdrawal parameters
* @param _withdrawalDelayDuration amount of time required to wait before withdrawaing
* @param _withdrawalWindowDuration amount of time a withdrawal can be executed for after the delay has elapsed
*/
function setWithdrawalParams(uint64 _withdrawalDelayDuration, uint64 _withdrawalWindowDuration) external onlyOwner {
withdrawalDelayDuration = _withdrawalDelayDuration;
withdrawalWindowDuration = _withdrawalWindowDuration;
emit SetWithdrawalParams(_withdrawalDelayDuration, _withdrawalWindowDuration);
}

/**
* @notice returns the total amount of assets staked in the pool
* @return total staked amount
Expand Down
2 changes: 1 addition & 1 deletion contracts/core/RewardsPoolTimeBased.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ contract RewardsPoolTimeBased is RewardsPool, Ownable {

uint256 remainingRewards = timeOfLastRewardUpdate >= epochExpiry
? 0
: (epochExpiry - timeOfLastRewardUpdate) * getLastRewardPerSecond();
: ((epochExpiry - timeOfLastRewardUpdate) * epochRewardsAmount) / epochDuration;

totalRewards += _rewardsAmount;
epochRewardsAmount = remainingRewards + _rewardsAmount;
Expand Down
8 changes: 8 additions & 0 deletions contracts/core/base/StakingRewardsPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import "../tokens/base/ERC677Upgradeable.sol";
* @dev Rewards can be positive or negative (user balances can increase and decrease)
*/
abstract contract StakingRewardsPool is ERC677Upgradeable, UUPSUpgradeable, OwnableUpgradeable {
uint256 private constant DEAD_SHARES = 10**3;

IERC20Upgradeable public token;

mapping(address => uint256) private shares;
Expand Down Expand Up @@ -184,6 +186,12 @@ abstract contract StakingRewardsPool is ERC677Upgradeable, UUPSUpgradeable, Owna
function _mintShares(address _recipient, uint256 _amount) internal {
require(_recipient != address(0), "Mint to the zero address");

if (totalShares == 0) {
shares[address(0)] = DEAD_SHARES;
totalShares = DEAD_SHARES;
_amount -= DEAD_SHARES;
}

totalShares += _amount;
shares[_recipient] += _amount;
}
Expand Down
4 changes: 3 additions & 1 deletion contracts/core/tokens/base/ERC677.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ contract ERC677 is ERC20 {
string memory _tokenSymbol,
uint256 _totalSupply
) ERC20(_tokenName, _tokenSymbol) {
_mint(msg.sender, _totalSupply * (10**uint256(decimals())));
if (_totalSupply != 0) {
_mint(msg.sender, _totalSupply * (10**uint256(decimals())));
}
}

function transferAndCall(
Expand Down
4 changes: 3 additions & 1 deletion contracts/core/tokens/base/ERC677Upgradeable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ contract ERC677Upgradeable is ERC20Upgradeable {
uint256 _totalSupply
) public onlyInitializing {
__ERC20_init(_tokenName, _tokenSymbol);
_mint(msg.sender, _totalSupply * (10**uint256(decimals())));
if (_totalSupply != 0) {
_mint(msg.sender, _totalSupply * (10**uint256(decimals())));
}
}

function transferAndCall(
Expand Down
14 changes: 14 additions & 0 deletions test/core/insurance-pool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ describe('InsurancePool', () => {
'symbol',
accounts[0],
3000,
0,
0,
])) as InsurancePool

rewardsPool = (await deploy('RewardsPoolTimeBased', [
Expand All @@ -59,11 +61,13 @@ describe('InsurancePool', () => {
.connect(signers[1])
.approve(insurancePool.address, ethers.constants.MaxUint256)
await token.approve(rewardsPool.address, ethers.constants.MaxUint256)
await insurancePool.deposit(1000)
})

it('deposit should work correctly', async () => {
await insurancePool.deposit(toEther(1000))
await insurancePool.connect(signers[1]).deposit(toEther(3000))
await insurancePool.withdraw(1000)

assert.equal(fromEther(await insurancePool.balanceOf(accounts[0])), 1000)
assert.equal(fromEther(await insurancePool.balanceOf(accounts[1])), 3000)
Expand All @@ -87,8 +91,16 @@ describe('InsurancePool', () => {
})

it('withdraw should work correctly', async () => {
await insurancePool.setWithdrawalParams(10, 100)
await insurancePool.deposit(toEther(1200))
await insurancePool.connect(signers[1]).deposit(toEther(3000))

await expect(insurancePool.withdraw(toEther(200))).to.be.revertedWith(
'WithdrawalWindowInactive()'
)

await insurancePool.requestWithdrawal()
await time.increase(10)
await insurancePool.withdraw(toEther(200))

assert.equal(fromEther(await insurancePool.balanceOf(accounts[0])), 1000)
Expand All @@ -105,6 +117,8 @@ describe('InsurancePool', () => {
assert.equal(fromEther(await rewardsPool.userRewards(accounts[0])), 0)
assert.equal(fromEther(await rewardsPool.userRewards(accounts[1])), 0)

await insurancePool.connect(signers[1]).requestWithdrawal()
await time.increase(10)
await insurancePool.connect(signers[1]).withdraw(toEther(100))

assert.equal(fromEther(await rewardsPool.rewardPerToken()), 0.25)
Expand Down
5 changes: 5 additions & 0 deletions test/core/priorityPool/priority-pool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ describe('PriorityPool', () => {
for (let i = 0; i < signers.length; i++) {
await token.connect(signers[i]).approve(sq.address, ethers.constants.MaxUint256)
}

await sq.deposit(1000, false)
})

it('deposit should work correctly', async () => {
Expand Down Expand Up @@ -136,6 +138,7 @@ describe('PriorityPool', () => {

it('depositQueuedTokens should work correctly', async () => {
await sq.deposit(toEther(2000), true)
await sq.withdraw(1000, 0, 0, [], true)
await token.transfer(strategy.address, toEther(1000))
await stakingPool.updateStrategyRewards([0], '0x')
await sq.connect(signers[1]).deposit(toEther(500), true)
Expand Down Expand Up @@ -235,6 +238,7 @@ describe('PriorityPool', () => {

it('performUpkeep should work corectly', async () => {
await sq.deposit(toEther(2000), true)
await sq.withdraw(1000, 0, 0, [], true)
await token.transfer(strategy.address, toEther(1000))
await stakingPool.updateStrategyRewards([0], '0x')
await sq.connect(signers[1]).deposit(toEther(500), true)
Expand Down Expand Up @@ -594,6 +598,7 @@ describe('PriorityPool', () => {
await stakingPool.connect(signers[1]).approve(sq.address, ethers.constants.MaxUint256)
await stakingPool.connect(signers[2]).approve(sq.address, ethers.constants.MaxUint256)
await sq.deposit(toEther(1000), true)
await sq.withdraw(1000, 0, 0, [], true)
await token.transfer(strategy.address, toEther(1000))
await stakingPool.updateStrategyRewards([0], '0x')
await sq.connect(signers[1]).deposit(toEther(100), true)
Expand Down
2 changes: 2 additions & 0 deletions test/core/rebase-controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ describe('RebaseController', () => {
'symbol',
accounts[0],
3000,
10,
100,
])) as InsurancePool

rebaseController = (await deploy('RebaseController', [
Expand Down
1 change: 1 addition & 0 deletions test/core/staking-pool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ describe('StakingPool', () => {
await stakingPool.setRebaseController(accounts[0])

await token.approve(stakingPool.address, ethers.constants.MaxUint256)
await stakingPool.deposit(accounts[0], 1000)
})

it('derivative token metadata should be correct', async () => {
Expand Down
1 change: 1 addition & 0 deletions test/core/wrapped-sd-token.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ describe('WrappedSDToken', () => {
await stakingPool.setRebaseController(accounts[0])

await token.approve(stakingPool.address, ethers.constants.MaxUint256)
await stakingPool.deposit(accounts[0], 1000)
})

it('token metadata should be correct', async () => {
Expand Down
2 changes: 2 additions & 0 deletions test/linkStaking/operator-vcs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ describe('OperatorVCS', () => {
await token.approve(stakingPool.address, ethers.constants.MaxUint256)
await token.transfer(rewardsController.address, toEther(10000))
await token.transfer(pfAlertsController.address, toEther(10000))
await stakingPool.deposit(accounts[0], 1000)
})

it('should be able to add vault', async () => {
Expand Down Expand Up @@ -210,6 +211,7 @@ describe('OperatorVCS', () => {

it('updateDeposits should work correctly with reward withdrawals', async () => {
await stakingPool.deposit(accounts[0], toEther(1000))
await stakingPool.withdraw(accounts[0], accounts[0], 1000)
await rewardsController.setReward(vaults[1], toEther(5))
await rewardsController.setReward(vaults[3], toEther(7))
await rewardsController.setReward(vaults[5], toEther(8))
Expand Down
2 changes: 1 addition & 1 deletion test/liquidSDIndex/liquid-sd-index-pool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ describe('LiquidSDIndexPool', () => {
'Composition targets must sum to 100%'
)

await pool.connect(signers[1]).withdraw(toEther(3000))
await pool.connect(signers[1]).withdraw(toEther(2999))
await pool.removeLSDToken(lsd2.address, [2000, 8000])

assert.deepEqual(await pool.getLSDTokens(), [lsd1.address, lsd3.address])
Expand Down

0 comments on commit f35d8f1

Please sign in to comment.