From 5fc34aec8d4929680e7cdf0798137093bb65b79e Mon Sep 17 00:00:00 2001 From: Alex <71931113+af-afk@users.noreply.github.com> Date: Mon, 8 Apr 2024 23:20:59 +0930 Subject: [PATCH] Develop support retroactive bonus (#2599) * Support retroactive awarding benefits, and some extra events * Also support staked for for operator * Update the staked length functino name to be more consistent --------- Co-authored-by: user --- contracts/ethereum/contracts/StakingV1.sol | 29 ++++++++++++++++++++-- contracts/ethereum/interfaces/IStaking.sol | 6 +++++ contracts/ethereum/test/staking-v1.ts | 10 ++++---- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/contracts/ethereum/contracts/StakingV1.sol b/contracts/ethereum/contracts/StakingV1.sol index 287f228dc..93128acc9 100644 --- a/contracts/ethereum/contracts/StakingV1.sol +++ b/contracts/ethereum/contracts/StakingV1.sol @@ -63,6 +63,8 @@ contract StakingV1 is IStaking, IERC20, IEmergencyMode, IOperatorOwned { event NewMerkleDistributor(address old, address _new); + event Day1BonusApplied(address user, uint stakedPosition); + /* ~~~~~~~~~~ HOUSEKEEPING ~~~~~~~~~~ */ /// @dev if false, emergency mode is active - can be called by either the @@ -182,6 +184,8 @@ return a // take the ERC20 from the spender. flyToken_.safeTransferFrom(_spender, address(this), _flyAmount); + emit NewStake(_recipient, _flyAmount); + return _flyAmount; } @@ -210,7 +214,7 @@ return a } /* ~~~~~~~~~~ INFORMATIONAL ~~~~~~~~~~ */ - function stakingPositionsLen(address _account) public view returns (uint) { + function stakedPositionsLen(address _account) public view returns (uint) { return stakedStorage_[_account].length; } @@ -233,6 +237,16 @@ return a return 0; } + function stakedStorage(address _a, uint _p) public view returns ( + bool receivedBonus, + uint256 flyVested, + uint256 depositTimestamp + ) { + receivedBonus = stakedStorage_[_a][_p].receivedBonus; + flyVested = stakedStorage_[_a][_p].flyVested; + depositTimestamp = stakedStorage_[_a][_p].depositTimestamp; + } + /* ~~~~~~~~~~ NORMAL USER PUBLIC ~~~~~~~~~~ */ /// @inheritdoc IStaking @@ -257,7 +271,10 @@ return a uint256 flyStaked, uint256 day1Points ) { - require(msg.sender == merkleDistributor_, "not merkle distributor"); + require( + msg.sender == merkleDistributor_ || msg.sender == operator_, + "not merkle distributor" + ); flyStaked = _stake(msg.sender, _recipient, _flyAmount, true); return (flyStaked, _calcDay1Points(_flyAmount)); } @@ -283,6 +300,7 @@ return a // take the full amount for this position, pop the staked amount, reduce // the fly remaining, then move on. flyRemaining -= s.flyVested; + emit UnstakeBeginning(msg.sender, s.flyVested, unstakedBy); unstakingStorage_[msg.sender].push(UnstakingPrivate({ flyAmount: s.flyVested, unstakedTimestamp: unstakedBy @@ -348,6 +366,7 @@ return a } // now we can use ERC20 to send the token back, if they got more than 0 back. if (flyReturned == 0) revert("no fly returned"); + emit UnstakeFinalised(msg.sender, flyReturned); flyToken_.safeTransfer(msg.sender, flyReturned); } @@ -360,6 +379,12 @@ return a emit NewMerkleDistributor(_old, _new); } + function applyDay1Bonus(address _user, uint _pos) public { + require(msg.sender == operator_, "operator only"); + require(stakedStorage_[_user][_pos].flyVested > 0, "empty staking storage"); + stakedStorage_[_user][_pos].receivedBonus = true; + } + /* ~~~~~~~~~~ EMERGENCY FUNCTIONS ~~~~~~~~~~ */ /// @inheritdoc IStaking diff --git a/contracts/ethereum/interfaces/IStaking.sol b/contracts/ethereum/interfaces/IStaking.sol index e17f2df27..21974cb40 100644 --- a/contracts/ethereum/interfaces/IStaking.sol +++ b/contracts/ethereum/interfaces/IStaking.sol @@ -33,6 +33,12 @@ struct Staked { * amounts out in an emergency mode stake. */ interface IStaking { + event NewStake(address staker, uint256 amount); + + event UnstakeBeginning(address unstaker, uint256 amount, uint256 unlockTimestamp); + + event UnstakeFinalised(address unstaker, uint256 amount); + /* ~~~~~~~~~~ SIMPLE GETTER ~~~~~~~~~~ */ /// @notice merkleDistributor that's in use for the stakeFor function. diff --git a/contracts/ethereum/test/staking-v1.ts b/contracts/ethereum/test/staking-v1.ts index 54a38e572..c7ef1c205 100644 --- a/contracts/ethereum/test/staking-v1.ts +++ b/contracts/ethereum/test/staking-v1.ts @@ -1125,7 +1125,7 @@ describe("StakingV1", async () => { expect(await stakingContract.callStatic.stake(amountStaked)).to.be.equal(amountStaked); // then send on-chain to continue the life of the testing await stakingContract.stake(amountStaked); - expect(await stakingContract.stakingPositionsLen(signerAddr)).to.be.equal(1); + expect(await stakingContract.stakedPositionsLen(signerAddr)).to.be.equal(1); let { flyStaked } = await stakingContract.stakingDetails(signerAddr); expect(flyStaked).to.be.equal(amountStaked); const { flyRemaining } = await stakingContract.callStatic.beginUnstake(0); @@ -1144,7 +1144,7 @@ describe("StakingV1", async () => { .to.be.equal(amountStaked); await stakingContract.stake(amountStaked); - expect(await stakingContract.stakingPositionsLen(signerAddr)) + expect(await stakingContract.stakedPositionsLen(signerAddr)) .to.be.equal(1); // now wait a seeminly random amount of time, get the points @@ -1256,7 +1256,7 @@ describe("StakingV1", async () => { // the amount of positions remaining should be equal to 2 since we // closed the newest position. - expect(await stakingContract.stakingPositionsLen(signerAddr)).to.be.equal(2); + expect(await stakingContract.stakedPositionsLen(signerAddr)).to.be.equal(2); ({ flyStaked } = await stakingContract.stakingDetails(signerAddr)); expect(flyStaked).to.be.equal(s1.add(s2.sub(flyUnstake1)).add(s3)); @@ -1273,7 +1273,7 @@ describe("StakingV1", async () => { ({ flyStaked } = await stakingContract.stakingDetails(signerAddr)); expect(flyStaked).to.be.equal(s3); - expect(await stakingContract.stakingPositionsLen(signerAddr)).to.be.equal(1); + expect(await stakingContract.stakedPositionsLen(signerAddr)).to.be.equal(1); /* * unstake just 1 this time. @@ -1287,7 +1287,7 @@ describe("StakingV1", async () => { ({ flyStaked } = await stakingContract.stakingDetails(signerAddr)); expect(flyStaked).to.be.equal(s3.sub(1)); - expect(await stakingContract.stakingPositionsLen(signerAddr)).to.be.equal(1); + expect(await stakingContract.stakedPositionsLen(signerAddr)).to.be.equal(1); }); });