Beginner FriendlyFoundryDeFi
100 EXP
View results
Submission Details
Severity: high
Valid

Users can get as many points as they can based on the minimum requirement staked amount, which will destroy the points campaign's goal.

Summary

Users can get as many points as they can by staking, unStaking,staking again. Becasue the back server only listening the Staked event, which only accounts for adding the points. When users unstake, there is no corrospending unStaking listening in the back server, which should dealing with this issue.

Vulnerability Details

  1. One user stake 0.5 eth, get 500 points, then unStaked 0.5 eth.

  2. The user continue stake 0.5 eth, current totoal points: 1000. unStaked 0.5 eth.

  3. Repeat above steps, the user can get as many point as he want and just based on the minimum requirement staked amount.

Below code, only listening the staked event and which only increasing the user's points.

async function main() {
await connectToMongodb();
const { rpcUrl, steakingAddress } = getConfig();
const provider = new ethers.JsonRpcProvider(rpcUrl);
const steaking = new ethers.Contract(steakingAddress, steakingAbi, provider);
steaking.on(STAKED, async (_, amount, onBehalfOf) => {
let steakPoints;
steakPoints = await steakPointsModel.findOne({ walletAddress: onBehalfOf });
if (!steakPoints) {
steakPoints = new steakPointsModel({
walletAddress: onBehalfOf,
points: +ethers.formatEther(amount) * PRECISION,
});
} else {
steakPoints.points += +ethers.formatEther(amount) * PRECISION;
}
await steakPoints.save();
});
}

Impact

  1. User can get as many points as they want just based on the minimum required amount, which destroy the airdrop design. User take the minimum required amount, to take as many as airdrop they want.

  2. The protocol can't achieve the goal attracting so much liquidity, because this issue leads to the minimum staked amount can get huge rewads, so user will just stake the minimum amount to get the max rewards.

Tools Used

Manual

Recommendations

Add listening unstaked event in the back server, when user unstaked should delete their points.

To make the points rewards more rational, the calcualtion can take account the user's different staking periods, such as the 4 weeks, or 1 week.

async function main() {
await connectToMongodb();
const { rpcUrl, steakingAddress } = getConfig();
const provider = new ethers.JsonRpcProvider(rpcUrl);
const steaking = new ethers.Contract(steakingAddress, steakingAbi, provider);
steaking.on(STAKED, async (_, amount, onBehalfOf) => {
let steakPoints;
steakPoints = await steakPointsModel.findOne({ walletAddress: onBehalfOf });
if (!steakPoints) {
steakPoints = new steakPointsModel({
walletAddress: onBehalfOf,
points: +ethers.formatEther(amount) * PRECISION,
});
} else {
steakPoints.points += +ethers.formatEther(amount) * PRECISION;
}
await steakPoints.save();
});
// listening the unstaked event which decrease the user's points.
steaking.on(UNSTAKED, async (staker, amount) => {
let steakPoints;
// As the smart contract can guarantee the unstake amount must less then the staked amount, So there just do the calculation.
// But for more security, can add more check. there just ignore.
steakPoints = await steakPointsModel.findOne({ walletAddress: staker });
console.log("listening unstake event, unstaker,amount", staker, amount);
steakPoints.points -= +ethers.formatEther(amount) * PRECISION;
await steakPoints.save();
});
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Steaking server is not taking unstakes into account

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.