Brave Saffron Rooster
High
The price of pTKN
decreases all the time and previous bond users may debond at a lower price.
Within WeightedIndex.sol
, the _bond
function wraps index tokens to pTKN
token.
function _bond(address _token, uint256 _amount, uint256 _amountMintMin, address _user) internal {
require(_isTokenInIndex[_token], "IT");
uint256 _tokenIdx = _fundTokenIdx[_token];
bool _firstIn = _isFirstIn();
uint256 _tokenAmtSupplyRatioX96 =
_firstIn ? FixedPoint96.Q96 : (_amount * FixedPoint96.Q96) / _totalAssets[_token];
uint256 _tokensMinted;
if (_firstIn) {
@> _tokensMinted = (_amount * FixedPoint96.Q96 * 10 ** decimals()) / indexTokens[_tokenIdx].q1;
} else {
@> _tokensMinted = (_totalSupply * _tokenAmtSupplyRatioX96) / FixedPoint96.Q96;
}
uint256 _feeTokens = _canWrapFeeFree(_user) ? 0 : (_tokensMinted * _fees.bond) / DEN;
require(_tokensMinted - _feeTokens >= _amountMintMin, "M");
@> _totalSupply += _tokensMinted;
_mint(_user, _tokensMinted - _feeTokens);
if (_feeTokens > 0) {
_mint(address(this), _feeTokens);
@> _processBurnFee(_feeTokens);
}
[...]
}
When multiple users bond _token
with amounts of x1, x2, x3, etc.,we can analyze _totalSupply
and _totalAssets[_token]
as follows.
bondorder _totalAssets[_token] _tokensMinted _totalSupply
0(firstbond) x1 y1 z1(=y1)
1 x1+x2 y2=z1/x1*x2 z2=z1+z1/x1*x2*(1-_fees.burn / DEN)
2 x1+x2+x3 y3=z2/x2*x3 z3=z2+z2/x2*x3*(1-_fees.burn / DEN)
3 x1+x2+x3+x4 y4=z3/x3*x4 z4=z3+z3/x3*x4*(1-_fees.burn / DEN)
4 x1+x2+x3+x4+x5 y5=z4/x4*x5 z5=z4+z4/x4*x5*(1-_fees.burn / DEN)
5 x1+x2+x3+x4+x5+x6 y6=z5/x5*x6 z6=z5+z5/x5*x6*(1-_fees.burn / DEN)
...
From this, we can derive that:
`z2/(x1+x2)=(z1+z1/x1*x2*(1-_fees.burn / DEN))/(x1+x2)<z1/x1`
`z3/(x1+x2+x3)<z2/(x1+x2)<z1/x1`
...
Thus, the ratio _totalSupply/_totalAssets[_token] decreases with each bond.
In practice, as users also debond tokens and the rate _totalSupply/_totalAssets[_token]
also decreases witheach debond.
function debond(uint256 _amount, address[] memory, uint8[] memory) external override lock noSwapOrFee {
uint256 _amountAfterFee = _isLastOut(_amount) || REWARDS_WHITELIST.isWhitelistedFromDebondFee(_msgSender())
? _amount
: (_amount * (DEN - _fees.debond)) / DEN;
@> uint256 _percSharesX96 = (_amountAfterFee * FixedPoint96.Q96) / _totalSupply;
super._transfer(_msgSender(), address(this), _amount);
@> _totalSupply -= _amountAfterFee;
_burn(address(this), _amountAfterFee);
@> _processBurnFee(_amount - _amountAfterFee);
uint256 _il = indexTokens.length;
for (uint256 _i; _i < _il; _i++) {
@> uint256 _debondAmount = (_totalAssets[indexTokens[_i].token] * _percSharesX96) / FixedPoint96.Q96;
if (_debondAmount > 0) {
@> _totalAssets[indexTokens[_i].token] -= _debondAmount;
IERC20(indexTokens[_i].token).safeTransfer(_msgSender(), _debondAmount);
}
}
[...]
}
If the _totalSupply
is low, the rate _totalSupply/_totalAssets[_token]
decreases more rapidly.
This results in a continuous decline, potentially approaching zero. Mathematically, it is evident that the first bonder can debond pTKN
at a cheaper price since the ratio is significantly lower than at the initial bonding stage, allowing them to increase their tokens.
No response
No response
No response
Users can increase their tokens by taking advantage of the decreasing rate _totalSupply/_totalAssets[_token]
.
It is evident that continuous bonding (wrapping) and debonding (unwrapping) of tokens will decrease the rate _totalSupply/_totalAssets[_token]
.
Please introduce a parameter to control the rate _totalSupply/_totalAssets[_token]
to prevent it from reaching excessively low values.