Skip to content

Commit

Permalink
Merge pull request #3 from ThenafiBNB/HighSeverity
Browse files Browse the repository at this point in the history
High severity
  • Loading branch information
PrometeoThena committed Jun 11, 2023
2 parents d9962ba + 35c01c8 commit c5cdb49
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 33 deletions.
43 changes: 34 additions & 9 deletions contracts/GaugeExtraRewarder.sol
Expand Up @@ -54,7 +54,7 @@ contract GaugeExtraRewarder is Ownable {
uint public ACC_TOKEN_PRECISION = 1e12;


address private immutable GAUGE;
address private GAUGE;

event LogOnReward(address indexed user, uint256 indexed pid, uint256 amount, address indexed to);

Expand All @@ -69,31 +69,43 @@ contract GaugeExtraRewarder is Ownable {


function onReward(uint256 /*pid*/, address _user, address to, uint256 /*extraData*/, uint256 lpToken) onlyGauge external {
if(stop) return;
if(stop){
return;
}
PoolInfo memory pool = updatePool();
UserInfo storage user = userInfo[_user];
uint256 pending;
uint256 accRewardPerShare = pool.accRewardPerShare;
if (user.amount > 0) {
pending = int256( user.amount.mul(accRewardPerShare) / ACC_TOKEN_PRECISION ).sub(user.rewardDebt).toUInt256();
pending = _pendingReward(_user);
rewardToken.safeTransfer(to, pending);
}
user.amount = lpToken;
user.rewardDebt = int256(lpToken.mul(pool.accRewardPerShare) / ACC_TOKEN_PRECISION);
}


/// @notice View function to see pending WBNB on frontend.
/// @notice View function to see pending Rewards on frontend.
/// @param _user Address of user.
/// @return pending rewardToken reward for a given user.
function pendingReward(address _user) external view returns (uint256 pending){
function pendingReward(address _user) public view returns (uint256 pending){
pending = _pendingReward(_user);
}
function _pendingReward(address _user) internal view returns(uint256 pending){
PoolInfo memory pool = poolInfo;
UserInfo storage user = userInfo[_user];
uint256 accRewardPerShare = pool.accRewardPerShare;
uint256 lpSupply = IERC20(IGauge(GAUGE).TOKEN()).balanceOf(GAUGE);

if (block.timestamp > pool.lastRewardTime && lpSupply != 0) {
uint256 time = block.timestamp.sub(pool.lastRewardTime);
// if we reach the end, look for the missing seconds up to LastDistributedTime ; else use block.timestamp
uint _tempTimestamp;
if( block.timestamp >= lastDistributedTime){
// if lastRewardTime is > than LastDistributedTime then set tempTimestamp to 0 to avoid underflow
_tempTimestamp = pool.lastRewardTime > lastDistributedTime ? 0 : lastDistributedTime.sub(pool.lastRewardTime);
} else {
_tempTimestamp = block.timestamp.sub(pool.lastRewardTime);
}
uint256 time = _tempTimestamp;
uint256 reward = time.mul(rewardPerSecond);
accRewardPerShare = accRewardPerShare.add( reward.mul(ACC_TOKEN_PRECISION) / lpSupply );
}
Expand Down Expand Up @@ -137,11 +149,19 @@ contract GaugeExtraRewarder is Ownable {
/// @return pool Returns the pool that was updated.
function updatePool() public returns (PoolInfo memory pool) {
pool = poolInfo;

if (block.timestamp > pool.lastRewardTime) {
uint256 lpSupply = IERC20(IGauge(GAUGE).TOKEN()).balanceOf(GAUGE);
if (lpSupply > 0) {
uint256 time = block.timestamp.sub(pool.lastRewardTime);
// if we reach the end, look for the missing seconds up to LastDistributedTime ; else use block.timestamp
uint _tempTimestamp;
if( block.timestamp >= lastDistributedTime){
// if lastRewardTime is > than LastDistributedTime then set tempTimestamp to 0 to avoid underflow
_tempTimestamp = pool.lastRewardTime > lastDistributedTime ? 0 : lastDistributedTime.sub(pool.lastRewardTime);
} else {
_tempTimestamp = block.timestamp.sub(pool.lastRewardTime);
}

uint256 time = _tempTimestamp;
uint256 reward = time.mul(rewardPerSecond);
pool.accRewardPerShare = pool.accRewardPerShare.add( reward.mul(ACC_TOKEN_PRECISION).div(lpSupply) );
}
Expand All @@ -166,5 +186,10 @@ contract GaugeExtraRewarder is Ownable {
stop = false;
}

function _gauge() external view returns(address){
return GAUGE;
}



}
2 changes: 1 addition & 1 deletion contracts/GaugeV2.sol
Expand Up @@ -294,7 +294,7 @@ contract GaugeV2 is ReentrancyGuard, Ownable {
}
}

///@notice User harvest function
///@notice User harvest function
function getReward() public nonReentrant updateReward(msg.sender) {
uint256 reward = rewards[msg.sender];
if (reward > 0) {
Expand Down
31 changes: 8 additions & 23 deletions contracts/VoterV3.sol
Expand Up @@ -299,6 +299,9 @@ contract VoterV3 is IVoter, OwnableUpgradeable, ReentrancyGuardUpgradeable {
require(isAlive[_gauge], "gauge already dead");
isAlive[_gauge] = false;
claimable[_gauge] = 0;
uint _time = _epochTimestamp();
totWeightsPerEpoch[_time] -= weightsPerEpoch[_time][poolForGauge[_gauge]];

emit GaugeKilled(_gauge);
}

Expand All @@ -310,27 +313,7 @@ contract VoterV3 is IVoter, OwnableUpgradeable, ReentrancyGuardUpgradeable {
isAlive[_gauge] = true;
emit GaugeRevived(_gauge);
}

/// @notice Kill a malicious gauge completly
/// @param _gauge gauge to kill
function killGaugeTotally(address _gauge) external Governance {
require(isAlive[_gauge], "gauge already dead");

delete isAlive[_gauge];
delete internal_bribes[_gauge];
delete external_bribes[_gauge];
delete poolForGauge[_gauge];
delete isGauge[_gauge];
delete claimable[_gauge];
delete supplyIndex[_gauge];

address _pool = poolForGauge[_gauge];
gauges[_pool] = address(0);


emit GaugeKilled(_gauge);
}


/* -----------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Expand Down Expand Up @@ -369,7 +352,9 @@ contract VoterV3 is IVoter, OwnableUpgradeable, ReentrancyGuardUpgradeable {
if (_votes > 0) {
IBribe(internal_bribes[gauges[_pool]])._withdraw(uint256(_votes), _tokenId);
IBribe(external_bribes[gauges[_pool]])._withdraw(uint256(_votes), _tokenId);
_totalWeight += _votes;

// if is alive remove _votes, else don't because we already done it in killGauge()
if(isAlive[gauges[_pool]]) _totalWeight += _votes;
}

emit Abstained(_tokenId, _votes);
Expand Down Expand Up @@ -431,7 +416,7 @@ contract VoterV3 is IVoter, OwnableUpgradeable, ReentrancyGuardUpgradeable {
address _pool = _poolVote[i];
address _gauge = gauges[_pool];

if (isGauge[_gauge]) {
if (isGauge[_gauge] && isAlive[_gauge]) {
uint256 _poolWeight = _weights[i] * _weight / _totalVoteWeight;
require(votes[_tokenId][_pool] == 0);
require(_poolWeight != 0);
Expand Down
128 changes: 128 additions & 0 deletions test/TestAudit/m01_gaugeExtraReward.js
@@ -0,0 +1,128 @@


const { expect } = require("chai");
const { erc20Abi } = require("../Abi.js")
const { ethers } = require("hardhat");


describe("test rewarder", function () {

beforeEach(async () => {
//await ethers.provider.send('evm_increaseTime', [5]);
//await ethers.provider.send('evm_mine');

const blockNumBefore = await ethers.provider.getBlockNumber();
const blockBefore = await ethers.provider.getBlock(blockNumBefore);
timestampBefore = blockBefore.timestamp;
});

it("Deploy contract", async function () {
accounts = await ethers.getSigners();
owner = accounts[0]


usdc = await ethers.getContractAt(erc20Abi, "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d")
usdt = await ethers.getContractAt(erc20Abi, "0x55d398326f99059fF775485246999027B3197955")

user = ethers.utils.getAddress("0x993Ae2b514677c7AC52bAeCd8871d2b362A9D693")
depositor = ethers.utils.getAddress("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")


// deploy gauge
data = await ethers.getContractFactory("GaugeV2");
// we care only of _token variable to let the ExtraRewarder read the total balance
GaugeV2 = await data.deploy(usdc.address, usdc.address, usdt.address, owner.address, owner.address, owner.address, true);
txDeployed = await GaugeV2.deployed();
console.log("GaugeV2: ", GaugeV2.address)


// deploy contract
data = await ethers.getContractFactory("GaugeExtraRewarder");
GaugeExtraRewarder = await data.deploy(usdc.address, GaugeV2.address);
txDeployed = await GaugeExtraRewarder.deployed();
console.log("GaugeExtraRewarder: ", GaugeExtraRewarder.address)
});

it("Set contracts ", async function () {
// transfer ownership to depositor and set gaugerewarder to gauge
await GaugeV2.setGaugeRewarder(GaugeExtraRewarder.address)
await GaugeExtraRewarder.transferOwnership(depositor)


// send 1k usdc as reward
const rewardAmount = ethers.utils.parseEther("1000")
await hre.network.provider.request({method: "hardhat_impersonateAccount",params: [depositor]});
signer = await ethers.getSigner(depositor)
await usdc.connect(signer).transfer(GaugeExtraRewarder.address, rewardAmount)
await usdt.connect(signer).transfer(user, rewardAmount)
await GaugeExtraRewarder.connect(signer).setDistributionRate(rewardAmount)
await hre.network.provider.request({method: "hardhat_stopImpersonatingAccount",params: [depositor]});
console.log("Reward Per Second: ", await GaugeExtraRewarder.rewardPerSecond())
console.log("lastDistributedTime: ", await GaugeExtraRewarder.lastDistributedTime())

});

it("User interaction", async function () {

await hre.network.provider.request({method: "hardhat_impersonateAccount",params: [user]});
signer = await ethers.getSigner(user)
const amountToDeposit = ethers.utils.parseEther("1000")
await usdt.connect(signer).approve(GaugeV2.address, amountToDeposit)

// deposit for user
const bal_before = await usdc.balanceOf(user)
await GaugeV2.connect(signer).depositAll()
console.log("Pending Reward after first deposit: ", await GaugeExtraRewarder.pendingReward(user) /1e18)


// user recall onReward after 3days
await ethers.provider.send('evm_increaseTime', [3 * 86400]);
await ethers.provider.send('evm_mine');
console.log("Pending Reward after 3days: ", await GaugeExtraRewarder.pendingReward(user) /1e18)


// user recall onReward after 6days
await ethers.provider.send('evm_increaseTime', [3 * 86400]);
await ethers.provider.send('evm_mine');
console.log("Pending Reward after 6days: ", await GaugeExtraRewarder.pendingReward(user) /1e18)

// user recall onReward after 7days
await ethers.provider.send('evm_increaseTime', [86400]);
await ethers.provider.send('evm_mine');
console.log("Pending Reward after 7days: ", await GaugeExtraRewarder.pendingReward(user) /1e18)


// user recall onReward after 14days
await ethers.provider.send('evm_increaseTime', [7 * 86400]);
await ethers.provider.send('evm_mine');
console.log("Pending Reward after 14days: ", await GaugeExtraRewarder.pendingReward(user) /1e18)

// user recall onReward after 21days
await ethers.provider.send('evm_increaseTime', [7 * 86400]);
await ethers.provider.send('evm_mine');
console.log("Pending Reward after 21days: ", await GaugeExtraRewarder.pendingReward(user) /1e18)
expect( await GaugeExtraRewarder.pendingReward(user)).to.above(ethers.utils.parseEther("999.99"))


// withdraw to trigger the claim, check amounts and pending
await GaugeV2.connect(signer).withdrawAll()
expect( await GaugeExtraRewarder.pendingReward(user)).to.equal(0)
await ethers.provider.send('evm_increaseTime', [7 * 86400]);
await ethers.provider.send('evm_mine');
expect( await GaugeExtraRewarder.pendingReward(user)).to.equal(0)

const bal_after = await usdc.balanceOf(user)
console.log("Start bal: ", bal_before /1e18)
console.log("End Bal: ", bal_after /1e18)
expect(bal_after.sub(bal_before)).to.be.above(ethers.utils.parseEther("999.99"))


await hre.network.provider.request({method: "hardhat_stopImpersonatingAccount",params: [user]});


});



});

0 comments on commit c5cdb49

Please sign in to comment.