Open hats-bug-reporter[bot] opened 11 months ago
Thanks for the submission!
I´m not sure I understand the negative impact here.
Receiving more PSM for the same amount of Portal Energy if there is more PSM inside the pool is the normal function of a constant product DEX. Solidity still rounds down at the precision limit, so if anything, users will "lose money" if they only sell very small amounts.
The pool itself cannot grow nor shrink as the constant product is fixed at the moment of Portal activation. (see activatePortal()
)
Can you give a numeric example of the issue?
Hi ,@PossumLabsCrypto
Here some example
1.two users contribute PSM tokens (100 1e18) each means (200 1e18). Here fundingBalance
variable will be 200*1e18.
btokens minted for each contribution (1000 1e18) each means (2000 1e18)
Now if user calls activatePortal()
function
requiredPortalEnergyLiquidity
= (200 1e18) (550) = 110000 1e18
constantProduct
= (2001e18) (110000 1e18) = 22000000 * 1e36
new Dust user stakes HLP tokens (1e18 / 2 = 1e17). maxStakeDebt
and portal Energy will be 24657534246575342
.
Again same Dust user calls sellPortalEnergy()
function with exact maxStakeDebt
and portalEnergy
assigned in above step.
Note :- in this function we are not considering fundingRewardPool
and _updateAccount(msg.sender,0);
Because update will increase the dust user portal energy which means amountReceived
will be more than explained here.
reserve0
= 200 1e18.
reserve1
= 110000 1e18; ( It includes division of constantProduct also).
amountReceived
= 44831870398833. (PSM transfer to DustUser).
We can run below code in Remix
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.15;
contract DustEX {
uint256 _amountInput = 246575342465753424; // new user's max value and portal energy when stake 1e18
uint256 _amountinput2 =24657534246575342; // new user's max value and portal energy when stake 1e17.
uint256 reserve0 = 200 * 1e18;
uint256 reserve1 = 110000 * 1e18; // It includes constantProduct also.
uint256 maxLockDuration = 7776000 ;
uint256 constant private SECONDS_PER_YEAR = 31536000;
function amountR_When_Stake_1e18( uint256 _amountInputZ ) public view returns(uint256 amountReceived) {
amountReceived = (_amountInputZ * reserve0) / (_amountInputZ + reserve1);
}
// new user maxStake and portal Energy .
function maxStake(uint _amount) public view returns(uint maxStakeDebt){
maxStakeDebt = (_amount * maxLockDuration) / SECONDS_PER_YEAR;
}
}
// Amount received = 448317799536688 when 1e18.
// Amount recevied = 44831870398833 when 1e17.
We will try to provide POC in foundry (error occurred ) and please correct if this wrong calculation.
Thank you for the POC.
This is exactly how it should work. 🙂
Scenarios A) staked 1e18 & sold PE -> output 448317799536688 PSM B) staked 1e17 & sold PE -> output 44831870398833 PSM
The general condition that more input brings more output is true: inputA > inputB && outputA > outputB
And also the price impact of selling is visible: inputA == inputB 10 && outputA < outputB 10
I suggest to not lose more time on this. 🤝
Github username: @pavankv241 Twitter username: @PavanKumarKv2 Submission hash (on-chain): 0xbf1e2542281915652a11d7455bc260ebe3bcc9913a55de4d23d0633f399a7e86 Severity: low
Description:
Description
Implement a dust amount check mechanism to prevent users to stake small amounts and earn equivalent pool energy and more PSM tokens than usual. As the PSM pool grows, dust users can call the sellPortalEnergy() function to redeem pool energy for PSM tokens based on reserves.
sellPortalEnergy()
function