Compare commits
No commits in common. "ebd23d98298a35276a0488178313eb823d1a69a1" and "b8a11ee3c132af154050e85182721709078c3390" have entirely different histories.
ebd23d9829
...
b8a11ee3c1
@ -31,8 +31,6 @@ contract GhostStaking is IStaking, GhostAccessControlled {
|
|||||||
address public gatekeeper;
|
address public gatekeeper;
|
||||||
address public warmup;
|
address public warmup;
|
||||||
|
|
||||||
uint256 private _lastRebaseBlock;
|
|
||||||
|
|
||||||
mapping(address => bool) public locks;
|
mapping(address => bool) public locks;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -57,7 +55,6 @@ contract GhostStaking is IStaking, GhostAccessControlled {
|
|||||||
|
|
||||||
GhostWarmup newWarmup = new GhostWarmup(_ghst);
|
GhostWarmup newWarmup = new GhostWarmup(_ghst);
|
||||||
warmup = address(newWarmup);
|
warmup = address(newWarmup);
|
||||||
_lastRebaseBlock = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function stake(
|
function stake(
|
||||||
@ -69,7 +66,7 @@ contract GhostStaking is IStaking, GhostAccessControlled {
|
|||||||
returnAmount = amount + rebase();
|
returnAmount = amount + rebase();
|
||||||
IERC20(ftso).safeTransferFrom(msg.sender, address(this), amount);
|
IERC20(ftso).safeTransferFrom(msg.sender, address(this), amount);
|
||||||
if (isClaim && warmupPeriod == 0) {
|
if (isClaim && warmupPeriod == 0) {
|
||||||
returnAmount = _sendStnkBased(returnAmount, to, isRebase);
|
returnAmount = _send(returnAmount, to, isRebase);
|
||||||
} else {
|
} else {
|
||||||
if (locks[to] && to != msg.sender) revert ExternalDepositsLocked();
|
if (locks[to] && to != msg.sender) revert ExternalDepositsLocked();
|
||||||
uint48 expiry = epoch.number + warmupPeriod;
|
uint48 expiry = epoch.number + warmupPeriod;
|
||||||
@ -78,28 +75,20 @@ contract GhostStaking is IStaking, GhostAccessControlled {
|
|||||||
emit Staked(msg.sender, to, amount, isRebase, isClaim);
|
emit Staked(msg.sender, to, amount, isRebase, isClaim);
|
||||||
}
|
}
|
||||||
|
|
||||||
function claim(address to, bool isRebase) public override returns (uint256) {
|
function claim(address to, bool isRebase) public override returns (uint256 claimedAmount) {
|
||||||
if (locks[to] && to != msg.sender) revert ExternalDepositsLocked();
|
if (locks[to] && to != msg.sender) revert ExternalDepositsLocked();
|
||||||
uint256 claimedAmount = IGhostWarmup(warmup).claim(to, epoch.number);
|
claimedAmount = IGhostWarmup(warmup).claim(to, epoch.number);
|
||||||
return _sendGhstBased(claimedAmount, to, isRebase);
|
if (isRebase) {
|
||||||
|
claimedAmount = IGHST(ghst).balanceFrom(claimedAmount);
|
||||||
|
ISTNK(stnk).safeTransfer(to, claimedAmount);
|
||||||
|
} else {
|
||||||
|
IGHST(ghst).mint(to, claimedAmount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function claimByAmount(
|
function breakout(bytes32 receiver, uint256 amount) public override {
|
||||||
address to,
|
IGhostWarmup(warmup).breakout(msg.sender, amount);
|
||||||
uint256 amount,
|
IGatekeeper(gatekeeper).ghost(receiver, amount);
|
||||||
bool isRebase
|
|
||||||
) public override returns (uint256) {
|
|
||||||
if (locks[to] && to != msg.sender) revert ExternalDepositsLocked();
|
|
||||||
uint256 claimedAmount = IGhostWarmup(warmup).claimByAmount(to, amount, epoch.number);
|
|
||||||
return _sendGhstBased(claimedAmount, to, isRebase);
|
|
||||||
}
|
|
||||||
|
|
||||||
function breakout(
|
|
||||||
bytes32 receiver,
|
|
||||||
uint256 amount
|
|
||||||
) public override returns (uint256 claimedAmount) {
|
|
||||||
claimedAmount = IGhostWarmup(warmup).breakout(msg.sender, amount);
|
|
||||||
IGatekeeper(gatekeeper).ghost(receiver, claimedAmount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function forfeit() external override returns (uint256 deposit) {
|
function forfeit() external override returns (uint256 deposit) {
|
||||||
@ -168,7 +157,7 @@ contract GhostStaking is IStaking, GhostAccessControlled {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function rebase() public override returns (uint256 bounty) {
|
function rebase() public override returns (uint256 bounty) {
|
||||||
if (epoch.end <= block.timestamp && block.number > _lastRebaseBlock) {
|
if (epoch.end <= block.timestamp) {
|
||||||
ISTNK(stnk).rebase(epoch.distribute, epoch.number);
|
ISTNK(stnk).rebase(epoch.distribute, epoch.number);
|
||||||
|
|
||||||
unchecked {
|
unchecked {
|
||||||
@ -184,7 +173,6 @@ contract GhostStaking is IStaking, GhostAccessControlled {
|
|||||||
uint256 balance = IERC20(ftso).balanceOf(address(this));
|
uint256 balance = IERC20(ftso).balanceOf(address(this));
|
||||||
uint256 extra = ISTNK(stnk).circulatingSupply() + bounty;
|
uint256 extra = ISTNK(stnk).circulatingSupply() + bounty;
|
||||||
|
|
||||||
_lastRebaseBlock = block.number;
|
|
||||||
epoch.distribute = balance > extra ? balance - extra : 0;
|
epoch.distribute = balance > extra ? balance - extra : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,7 +213,7 @@ contract GhostStaking is IStaking, GhostAccessControlled {
|
|||||||
return (deposit, payout, expiry, lock);
|
return (deposit, payout, expiry, lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _sendStnkBased(
|
function _send(
|
||||||
uint256 amount,
|
uint256 amount,
|
||||||
address to,
|
address to,
|
||||||
bool isRebase
|
bool isRebase
|
||||||
@ -239,19 +227,4 @@ contract GhostStaking is IStaking, GhostAccessControlled {
|
|||||||
return balanceTo;
|
return balanceTo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _sendGhstBased(
|
|
||||||
uint256 amount,
|
|
||||||
address to,
|
|
||||||
bool isRebase
|
|
||||||
) internal returns (uint256) {
|
|
||||||
if (isRebase) {
|
|
||||||
uint256 convertedAmount = IGHST(ghst).balanceFrom(amount);
|
|
||||||
ISTNK(stnk).safeTransfer(to, convertedAmount);
|
|
||||||
return convertedAmount;
|
|
||||||
} else {
|
|
||||||
IGHST(ghst).mint(to, amount);
|
|
||||||
return amount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,21 +49,17 @@ contract GhostWarmup is IGhostWarmup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function claimByAmount(
|
function breakout(address who, uint256 payout) external override {
|
||||||
address who,
|
|
||||||
uint256 payout,
|
|
||||||
uint256 epochNumber
|
|
||||||
) external override returns (uint256) {
|
|
||||||
if (msg.sender != STAKING) revert NotStakingContract();
|
if (msg.sender != STAKING) revert NotStakingContract();
|
||||||
return _reduceWarmupInfo(who, payout, epochNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
function breakout(
|
Claim storage info = _warmupInfo[who];
|
||||||
address who,
|
uint256 mm = mulmod(info.deposit, payout, info.payout);
|
||||||
uint256 payout
|
uint256 depositReduction = FullMath.mulDiv(info.deposit, payout, info.payout);
|
||||||
) external override returns (uint256) {
|
if (mm > 0) depositReduction += 1;
|
||||||
if (msg.sender != STAKING) revert NotStakingContract();
|
|
||||||
return _reduceWarmupInfo(who, payout, type(uint256).max);
|
info.deposit -= depositReduction;
|
||||||
|
info.payout -= payout;
|
||||||
|
_ghstInWarmup -= payout;
|
||||||
}
|
}
|
||||||
|
|
||||||
function forfeit(address who) external override returns (uint256) {
|
function forfeit(address who) external override returns (uint256) {
|
||||||
@ -83,28 +79,4 @@ contract GhostWarmup is IGhostWarmup {
|
|||||||
Claim memory info = _warmupInfo[who];
|
Claim memory info = _warmupInfo[who];
|
||||||
return (info.deposit, info.payout, info.expiry);
|
return (info.deposit, info.payout, info.expiry);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _reduceWarmupInfo(
|
|
||||||
address who,
|
|
||||||
uint256 amount,
|
|
||||||
uint256 epochNumber
|
|
||||||
) private returns (uint256) {
|
|
||||||
Claim storage info = _warmupInfo[who];
|
|
||||||
|
|
||||||
if (epochNumber >= info.expiry && info.expiry > 0) {
|
|
||||||
uint256 mm = mulmod(info.deposit, amount, info.payout);
|
|
||||||
uint256 depositReduction = FullMath.mulDiv(info.deposit, amount, info.payout);
|
|
||||||
if (mm > 0) depositReduction += 1;
|
|
||||||
|
|
||||||
info.deposit -= depositReduction;
|
|
||||||
info.payout -= amount;
|
|
||||||
_ghstInWarmup -= amount;
|
|
||||||
|
|
||||||
if (info.payout == 0) delete _warmupInfo[who];
|
|
||||||
|
|
||||||
return amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
revert LockedInWarmupPeriod();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,16 +10,10 @@ interface IGhostWarmup {
|
|||||||
|
|
||||||
error NotStakingContract();
|
error NotStakingContract();
|
||||||
error ExternalDepositsLocked();
|
error ExternalDepositsLocked();
|
||||||
error LockedInWarmupPeriod();
|
|
||||||
|
|
||||||
function addToWarmup(uint256 payout, address who, uint48 expiry) external;
|
function addToWarmup(uint256 payout, address who, uint48 expiry) external;
|
||||||
function claim(address who, uint256 epochNumber) external returns (uint256);
|
function claim(address who, uint256 epochNumber) external returns (uint256);
|
||||||
function claimByAmount(
|
function breakout(address who, uint256 amount) external;
|
||||||
address who,
|
|
||||||
uint256 amount,
|
|
||||||
uint256 epochNumber
|
|
||||||
) external returns (uint256);
|
|
||||||
function breakout(address who, uint256 amount) external returns (uint256);
|
|
||||||
function forfeit(address who) external returns (uint256);
|
function forfeit(address who) external returns (uint256);
|
||||||
function ghstInWarmup() external view returns (uint256);
|
function ghstInWarmup() external view returns (uint256);
|
||||||
function warmupInfo(address who) external view returns (uint256, uint256, uint48);
|
function warmupInfo(address who) external view returns (uint256, uint256, uint48);
|
||||||
|
|||||||
@ -6,7 +6,6 @@ interface INoteKeeper {
|
|||||||
error NoteNotFound(address from, uint256 index);
|
error NoteNotFound(address from, uint256 index);
|
||||||
error TransferNotFound(address from, uint256 index);
|
error TransferNotFound(address from, uint256 index);
|
||||||
error AlreadyRedeemed(address from, uint256 index);
|
error AlreadyRedeemed(address from, uint256 index);
|
||||||
error IncompleteRedeemPayout();
|
|
||||||
|
|
||||||
struct Note {
|
struct Note {
|
||||||
uint256 payout;
|
uint256 payout;
|
||||||
|
|||||||
@ -48,12 +48,7 @@ interface IStaking {
|
|||||||
) external returns (uint256);
|
) external returns (uint256);
|
||||||
|
|
||||||
function claim(address _recipient, bool _rebasing) external returns (uint256);
|
function claim(address _recipient, bool _rebasing) external returns (uint256);
|
||||||
function claimByAmount(
|
function breakout(bytes32 _receiver, uint256 _amount) external;
|
||||||
address _recipient,
|
|
||||||
uint256 _amount,
|
|
||||||
bool _rebasing
|
|
||||||
) external returns (uint256);
|
|
||||||
function breakout(bytes32 _receiver, uint256 _amount) external returns (uint256);
|
|
||||||
function forfeit() external returns (uint256);
|
function forfeit() external returns (uint256);
|
||||||
function toggleLock() external;
|
function toggleLock() external;
|
||||||
|
|
||||||
|
|||||||
@ -74,15 +74,20 @@ abstract contract NoteKeeper is INoteKeeper, FrontEndRewarder {
|
|||||||
bool sendGhst,
|
bool sendGhst,
|
||||||
uint256[] memory indexes
|
uint256[] memory indexes
|
||||||
) public override returns (uint256 payout) {
|
) public override returns (uint256 payout) {
|
||||||
uint256 expected = _maturedPayout(msg.sender, indexes);
|
_STAKING.claim(address(this), false);
|
||||||
uint256 balance = _GHST.balanceOf(address(this));
|
|
||||||
|
|
||||||
if (balance < expected) {
|
uint48 time = uint48(block.timestamp);
|
||||||
uint256 deficit = expected - balance;
|
uint256 i;
|
||||||
payout = balance + _STAKING.claimByAmount(address(this), deficit, false);
|
|
||||||
} else payout = expected;
|
|
||||||
|
|
||||||
if (payout < expected) revert IncompleteRedeemPayout();
|
for (; i < indexes.length; ) {
|
||||||
|
(uint256 pay, bool matured) = pendingFor(user, indexes[i]);
|
||||||
|
if (matured) {
|
||||||
|
_pendingIndexes[user].remove(indexes[i]);
|
||||||
|
notes[user][indexes[i]].redeemed = time;
|
||||||
|
payout += pay;
|
||||||
|
}
|
||||||
|
unchecked { ++i; }
|
||||||
|
}
|
||||||
|
|
||||||
if (sendGhst) _GHST.safeTransfer(user, payout);
|
if (sendGhst) _GHST.safeTransfer(user, payout);
|
||||||
else _STAKING.unwrap(user, payout);
|
else _STAKING.unwrap(user, payout);
|
||||||
@ -91,22 +96,22 @@ abstract contract NoteKeeper is INoteKeeper, FrontEndRewarder {
|
|||||||
function forceRedeem(
|
function forceRedeem(
|
||||||
bytes32 receiver,
|
bytes32 receiver,
|
||||||
uint256[] memory indexes
|
uint256[] memory indexes
|
||||||
) public override returns (uint256 expected) {
|
) public override returns (uint256 payout) {
|
||||||
uint256 payout = _maturedPayout(msg.sender, indexes);
|
address user = msg.sender;
|
||||||
uint256 balance = _GHST.balanceOf(address(this));
|
uint48 time = uint48(block.timestamp);
|
||||||
expected = payout;
|
uint256 i;
|
||||||
|
|
||||||
if (balance > 0) {
|
for (; i < indexes.length; ) {
|
||||||
uint256 toGhost = payout > balance ? balance : payout;
|
(uint256 pay, bool matured) = pendingFor(user, indexes[i]);
|
||||||
_STAKING.ghost(receiver, toGhost);
|
if (matured) {
|
||||||
payout -= toGhost;
|
_pendingIndexes[user].remove(indexes[i]);
|
||||||
|
notes[user][indexes[i]].redeemed = time;
|
||||||
|
payout += pay;
|
||||||
|
}
|
||||||
|
unchecked { ++i; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payout > 0) {
|
_STAKING.breakout(receiver, payout);
|
||||||
payout -= _STAKING.breakout(receiver, payout);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (payout > 0) revert IncompleteRedeemPayout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function redeemAll(
|
function redeemAll(
|
||||||
@ -162,18 +167,4 @@ abstract contract NoteKeeper is INoteKeeper, FrontEndRewarder {
|
|||||||
payout = note.payout;
|
payout = note.payout;
|
||||||
matured = _pendingIndexes[user].contains(index) && note.matured <= block.timestamp && payout > 0;
|
matured = _pendingIndexes[user].contains(index) && note.matured <= block.timestamp && payout > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _maturedPayout(address user, uint256[] memory indexes) private returns (uint256 payout) {
|
|
||||||
uint48 time = uint48(block.timestamp);
|
|
||||||
uint256 i = 0;
|
|
||||||
for (; i < indexes.length; ) {
|
|
||||||
(uint256 pay, bool matured) = pendingFor(user, indexes[i]);
|
|
||||||
if (matured) {
|
|
||||||
_pendingIndexes[user].remove(indexes[i]);
|
|
||||||
notes[user][indexes[i]].redeemed = time;
|
|
||||||
payout += pay;
|
|
||||||
}
|
|
||||||
unchecked { ++i; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -310,7 +310,7 @@ contract GhostBondDepositoryTest is Test {
|
|||||||
depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE);
|
depository.deposit(0, amount, INITIAL_PRICE, ALICE, ALICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_shouldNotRedeemImmediately() public {
|
function test_shouldNotRedeemAfterVested() public {
|
||||||
uint256 balance = ftso.balanceOf(ALICE);
|
uint256 balance = ftso.balanceOf(ALICE);
|
||||||
uint256 amount = 10_000 * 1e18; // 10,000
|
uint256 amount = 10_000 * 1e18; // 10,000
|
||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
@ -329,13 +329,12 @@ contract GhostBondDepositoryTest is Test {
|
|||||||
staking.setWarmupPeriod(1);
|
staking.setWarmupPeriod(1);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
vm.prank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
depository.deposit(0, amount, type(uint256).max, ALICE, ALICE);
|
depository.deposit(0, amount, type(uint256).max, ALICE, ALICE);
|
||||||
vm.prank(BOB);
|
vm.startPrank(BOB);
|
||||||
depository.deposit(0, amount, type(uint256).max, BOB, BOB);
|
depository.deposit(0, amount, type(uint256).max, BOB, BOB);
|
||||||
|
|
||||||
skip(DEPOSIT_INTERVAL);
|
skip(DEPOSIT_INTERVAL);
|
||||||
vm.roll(block.number + 1);
|
|
||||||
staking.rebase();
|
staking.rebase();
|
||||||
|
|
||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
@ -411,7 +410,6 @@ contract GhostBondDepositoryTest is Test {
|
|||||||
assertEq(ghst.balanceOf(address(depository)), 0);
|
assertEq(ghst.balanceOf(address(depository)), 0);
|
||||||
|
|
||||||
skip(DEPOSIT_INTERVAL);
|
skip(DEPOSIT_INTERVAL);
|
||||||
vm.roll(block.number + 1);
|
|
||||||
staking.rebase();
|
staking.rebase();
|
||||||
|
|
||||||
depository.redeemAll(ALICE, true);
|
depository.redeemAll(ALICE, true);
|
||||||
@ -495,53 +493,4 @@ contract GhostBondDepositoryTest is Test {
|
|||||||
assertEq(ALICE.balance, amount);
|
assertEq(ALICE.balance, amount);
|
||||||
assertEq(IERC20(address(weth)).balanceOf(address(treasury)), 0);
|
assertEq(IERC20(address(weth)).balanceOf(address(treasury)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_forceRedeemWorksBasedOnTheBalanceRemidner() public {
|
|
||||||
uint256 aliceAmount = _createNativeBond();
|
|
||||||
uint256 aliceAmountUsed = aliceAmount / 8;
|
|
||||||
assertEq(ALICE.balance, aliceAmount);
|
|
||||||
|
|
||||||
uint256 i;
|
|
||||||
for (; i < 8; ) {
|
|
||||||
vm.prank(ALICE);
|
|
||||||
depository.deposit{value: aliceAmountUsed}(1, aliceAmountUsed, type(uint256).max, ALICE, ALICE);
|
|
||||||
unchecked { ++i; }
|
|
||||||
}
|
|
||||||
|
|
||||||
vm.startPrank(GOVERNOR);
|
|
||||||
Gatekeeper gatekeeper = new Gatekeeper(address(staking), 0, 0, 0, 0, 0);
|
|
||||||
staking.setGatekeeperAddress(address(gatekeeper));
|
|
||||||
staking.setWarmupPeriod(10);
|
|
||||||
vm.stopPrank();
|
|
||||||
|
|
||||||
uint256 bobAmount = aliceAmount / 2;
|
|
||||||
uint256 bobAmountUsed = bobAmount / 8;
|
|
||||||
|
|
||||||
vm.deal(BOB, bobAmount);
|
|
||||||
assertEq(BOB.balance, bobAmount);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
for (; i < 7; ) {
|
|
||||||
vm.prank(BOB);
|
|
||||||
depository.deposit{value: bobAmountUsed}(1, bobAmountUsed, type(uint256).max, BOB, BOB);
|
|
||||||
unchecked { ++i; }
|
|
||||||
}
|
|
||||||
|
|
||||||
skip(DEPOSIT_INTERVAL);
|
|
||||||
|
|
||||||
(, uint256 payout,, bool matured) = staking.warmupInfo(address(depository));
|
|
||||||
assertEq(ghst.balanceOf(address(depository)) > 0, true);
|
|
||||||
assertEq(payout > 0, true);
|
|
||||||
assertEq(matured, true);
|
|
||||||
|
|
||||||
vm.prank(BOB);
|
|
||||||
depository.forceRedeemAll(bytes32(0));
|
|
||||||
|
|
||||||
vm.prank(ALICE);
|
|
||||||
depository.forceRedeemAll(bytes32(0));
|
|
||||||
|
|
||||||
(, payout,,) = staking.warmupInfo(address(depository));
|
|
||||||
assertEq(ghst.balanceOf(address(depository)), 0);
|
|
||||||
assertEq(payout, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,27 +16,6 @@ import {GhostBondingCalculator} from "../../src/StandardBondingCalculator.sol";
|
|||||||
import {ITreasury} from "../../src/interfaces/ITreasury.sol";
|
import {ITreasury} from "../../src/interfaces/ITreasury.sol";
|
||||||
import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol";
|
import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol";
|
||||||
|
|
||||||
contract RebaseBatcher {
|
|
||||||
address public immutable STAKING;
|
|
||||||
|
|
||||||
constructor(address _staking) {
|
|
||||||
STAKING = _staking;
|
|
||||||
}
|
|
||||||
|
|
||||||
function multipleRebases(uint256 times) external returns (uint256) {
|
|
||||||
return _rebase(times);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _rebase(uint256 times) internal returns (uint256) {
|
|
||||||
if (times == 0) return 0;
|
|
||||||
|
|
||||||
(bool success, ) = STAKING.call(abi.encodeWithSignature("rebase()"));
|
|
||||||
require(success, "Batch rebase failed");
|
|
||||||
|
|
||||||
return 1 + _rebase(times - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
contract StakingTest is Test {
|
contract StakingTest is Test {
|
||||||
using SafeERC20 for Stinky;
|
using SafeERC20 for Stinky;
|
||||||
|
|
||||||
@ -113,7 +92,6 @@ contract StakingTest is Test {
|
|||||||
gatekeeper = new Gatekeeper(address(staking), 0, 0, 0, 0, 0);
|
gatekeeper = new Gatekeeper(address(staking), 0, 0, 0, 0, 0);
|
||||||
calculator = new GhostBondingCalculator(address(ftso), 1, 1);
|
calculator = new GhostBondingCalculator(address(ftso), 1, 1);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
vm.roll(block.number + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_correctAfterConstruction() public view {
|
function test_correctAfterConstruction() public view {
|
||||||
@ -559,13 +537,11 @@ contract StakingTest is Test {
|
|||||||
|
|
||||||
(,, uint48 end,) = staking.epoch();
|
(,, uint48 end,) = staking.epoch();
|
||||||
skip(end);
|
skip(end);
|
||||||
vm.roll(block.number + 1);
|
|
||||||
|
|
||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
ftso.approve(address(staking), type(uint256).max);
|
ftso.approve(address(staking), type(uint256).max);
|
||||||
staking.stake(AMOUNT, ALICE, true, true);
|
staking.stake(AMOUNT, ALICE, true, true);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
vm.roll(block.number + 1);
|
|
||||||
|
|
||||||
uint256 postBounty = AMOUNT + bounty;
|
uint256 postBounty = AMOUNT + bounty;
|
||||||
|
|
||||||
@ -690,6 +666,7 @@ contract StakingTest is Test {
|
|||||||
vm.prank(BOB);
|
vm.prank(BOB);
|
||||||
staking.breakout(receiver, payout);
|
staking.breakout(receiver, payout);
|
||||||
|
|
||||||
|
|
||||||
uint256 requestedPayout = 1;
|
uint256 requestedPayout = 1;
|
||||||
uint256 expectedPayout = 0;
|
uint256 expectedPayout = 0;
|
||||||
while (expectedPayout < payout / 2) {
|
while (expectedPayout < payout / 2) {
|
||||||
@ -726,30 +703,6 @@ contract StakingTest is Test {
|
|||||||
assertEq(newDeposit, ftso.balanceOf(ALICE));
|
assertEq(newDeposit, ftso.balanceOf(ALICE));
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_revertDuringReentrancyRebase() public {
|
|
||||||
RebaseBatcher rebaseBatcher = new RebaseBatcher(address(staking));
|
|
||||||
uint256 startBlock = block.number;
|
|
||||||
uint256 passedRebases = 69;
|
|
||||||
skip((1 + passedRebases) * EPOCH_LENGTH);
|
|
||||||
|
|
||||||
(, uint48 prevNumber,,) = staking.epoch();
|
|
||||||
rebaseBatcher.multipleRebases(passedRebases);
|
|
||||||
(, uint48 currNumber,,) = staking.epoch();
|
|
||||||
assertEq(currNumber, prevNumber + 1);
|
|
||||||
|
|
||||||
uint256 i;
|
|
||||||
for (; i < passedRebases;) {
|
|
||||||
vm.roll(block.number + 1);
|
|
||||||
(,uint48 number,,) = staking.epoch();
|
|
||||||
rebaseBatcher.multipleRebases(1);
|
|
||||||
(,currNumber,,) = staking.epoch();
|
|
||||||
assertEq(currNumber, number + 1);
|
|
||||||
unchecked { ++i; }
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEq(currNumber, startBlock + passedRebases);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _mintAndApprove(address who, uint256 value) internal {
|
function _mintAndApprove(address who, uint256 value) internal {
|
||||||
vm.prank(VAULT);
|
vm.prank(VAULT);
|
||||||
ftso.mint(who, value);
|
ftso.mint(who, value);
|
||||||
|
|||||||
@ -210,7 +210,6 @@ contract StakingDistributorTest is Test {
|
|||||||
assertEq(distributor.rewardRate(), TEN_PERCENT);
|
assertEq(distributor.rewardRate(), TEN_PERCENT);
|
||||||
(,, uint256 end,) = staking.epoch();
|
(,, uint256 end,) = staking.epoch();
|
||||||
skip(end);
|
skip(end);
|
||||||
vm.roll(block.number + 1);
|
|
||||||
staking.rebase();
|
staking.rebase();
|
||||||
assertEq(distributor.rewardRate(), TEN_PERCENT + 69);
|
assertEq(distributor.rewardRate(), TEN_PERCENT + 69);
|
||||||
}
|
}
|
||||||
@ -235,7 +234,6 @@ contract StakingDistributorTest is Test {
|
|||||||
assertEq(distributor.rewardRate(), TEN_PERCENT);
|
assertEq(distributor.rewardRate(), TEN_PERCENT);
|
||||||
(,, uint256 end,) = staking.epoch();
|
(,, uint256 end,) = staking.epoch();
|
||||||
skip(end);
|
skip(end);
|
||||||
vm.roll(block.number + 1);
|
|
||||||
staking.rebase();
|
staking.rebase();
|
||||||
assertEq(distributor.rewardRate(), 1337);
|
assertEq(distributor.rewardRate(), 1337);
|
||||||
}
|
}
|
||||||
@ -248,7 +246,6 @@ contract StakingDistributorTest is Test {
|
|||||||
assertEq(distributor.rewardRate(), TEN_PERCENT);
|
assertEq(distributor.rewardRate(), TEN_PERCENT);
|
||||||
(,, uint256 end,) = staking.epoch();
|
(,, uint256 end,) = staking.epoch();
|
||||||
skip(end);
|
skip(end);
|
||||||
vm.roll(block.number + 1);
|
|
||||||
staking.rebase();
|
staking.rebase();
|
||||||
assertEq(distributor.rewardRate(), 1337);
|
assertEq(distributor.rewardRate(), 1337);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user