diff --git a/contracts/tokenization/StableDebtToken.sol b/contracts/tokenization/StableDebtToken.sol index 89430392..ca76237c 100644 --- a/contracts/tokenization/StableDebtToken.sol +++ b/contracts/tokenization/StableDebtToken.sol @@ -18,7 +18,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { uint256 internal _avgStableRate; mapping(address => uint40) internal _timestamps; - mapping(address => uint256) internal _usersData; + mapping(address => uint256) internal _usersStableRate; uint40 internal _totalSupplyTimestamp; constructor( @@ -59,7 +59,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { * @return the stable rate of user **/ function getUserStableRate(address user) external virtual override view returns (uint256) { - return _usersData[user]; + return _usersStableRate[user]; } /** @@ -68,7 +68,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { **/ function balanceOf(address account) public virtual override view returns (uint256) { uint256 accountBalance = super.balanceOf(account); - uint256 stableRate = _usersData[account]; + uint256 stableRate = _usersStableRate[account]; if (accountBalance == 0) { return 0; } @@ -117,13 +117,13 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { vars.amountInRay = amount.wadToRay(); //calculates the new stable rate for the user - vars.newStableRate = _usersData[onBehalfOf] + vars.newStableRate = _usersStableRate[onBehalfOf] .rayMul(currentBalance.wadToRay()) .add(vars.amountInRay.rayMul(rate)) .rayDiv(currentBalance.add(amount).wadToRay()); require(vars.newStableRate < (1 << 128), 'Debt token: stable rate overflow'); - _usersData[onBehalfOf] = vars.newStableRate; + _usersStableRate[onBehalfOf] = vars.newStableRate; //updating the user and supply timestamp //solium-disable-next-line @@ -166,6 +166,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { uint256 previousSupply = totalSupply(); uint256 newStableRate = 0; uint256 nextSupply = 0; + uint256 userStableRate = _usersStableRate[user]; //since the total supply and each single user debt accrue separately, //there might be accumulation errors so that the last borrower repaying @@ -176,14 +177,21 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { _totalSupply = 0; } else { nextSupply = _totalSupply = previousSupply.sub(amount); - newStableRate = _avgStableRate = _avgStableRate - .rayMul(previousSupply.wadToRay()) - .sub(_usersData[user].rayMul(amount.wadToRay())) - .rayDiv(nextSupply.wadToRay()); + uint256 firstTerm = _avgStableRate.rayMul(previousSupply.wadToRay()); + uint256 secondTerm = userStableRate.rayMul(amount.wadToRay()); + + //for the same reason described above, when the last user is repaying it might + //happen that user rate * user balance > avg rate * total supply. In that case, + //we simply set the avg rate to 0 + if (secondTerm >= firstTerm) { + newStableRate = _avgStableRate = _totalSupply = 0; + } else { + newStableRate = _avgStableRate = firstTerm.sub(secondTerm).rayDiv(nextSupply.wadToRay()); + } } if (amount == currentBalance) { - _usersData[user] = 0; + _usersStableRate[user] = 0; _timestamps[user] = 0; } else { //solium-disable-next-line diff --git a/deployed-contracts.json b/deployed-contracts.json index 50adf22d..67361d8c 100644 --- a/deployed-contracts.json +++ b/deployed-contracts.json @@ -1285,4 +1285,4 @@ "address": "0xaDF23b1cAa6a7B3b077c432794FfF80A4b935cdF" } } -} +} \ No newline at end of file