What you want to achieve is possible. Consider:
function balanceOf(address _user) public{
uint256 rawBalance = balances[_user];
if (rawBalance == 0) {
return 0;
}
uint256 startLevel = compoundedInterestFactor[_user];
uint256 currentLevel = getInterestRate().getCurrentCompoundingLevel(); // defined in another contract
return _rawBalance.mul(currentLevel).div(startLevel);
}
Assume that the getCurrentCompoundingLevel
returns a number depending on the time. If this number is rising as a function of time, this will correspond to a positive interest rate; if it is falling, it will correspond to a negative interest rate.
Each time you update a balance (send or receive a balance), you need to update both the balances
mapping and the compoundedInterestFactor
mapping for this user. The compoundedInterestFactor[_owner]
must be set to the current level when the transaction occurs.
If a user receives 1000 units when the getInterestRate().getCurrentCompoundingLevel()
function call returns 1000, and you want to apply a positive interest rate of 0.1 % per day, the function call must return 1001 the next day. The number returned from balanceOf(_user)
will then be 1000 * 1001 / 1000 = 1001
which corresponds to the desired 0.1 % interest rate per day.
This way, you can enforce both a negative and a positive interest rate without looping over all balances to have them updated.