diff --git a/contracts/libraries/MathUtils.sol b/contracts/libraries/MathUtils.sol index b2989822..1e26366d 100644 --- a/contracts/libraries/MathUtils.sol +++ b/contracts/libraries/MathUtils.sol @@ -31,7 +31,14 @@ library MathUtils { } /** - * @dev function to calculate the interest using a compounded interest rate formula + * @dev function to calculate the interest using a compounded interest rate formula. + * To avoid expensive exponentiation, the calculation is performed using a binomial approximation: + * + * (1+x)^n = 1+n*x+[n/2*(n-1)]*x^2+[n/6*(n-1)*(n-2)*x^3... + * + * The approximation slightly underpays liquidity providers, with the advantage of great gas cost reductions. + * The whitepaper contains reference to the approximation and a table showing the margin of error per different time periods. + * * @param _rate the interest rate, in ray * @param _lastUpdateTimestamp the timestamp of the last update of the interest * @return the interest rate compounded during the timeDelta, in ray @@ -41,11 +48,30 @@ library MathUtils { view returns (uint256) { + //solium-disable-next-line - uint256 timeDifference = block.timestamp.sub(uint256(_lastUpdateTimestamp)); + uint256 exp = block.timestamp.sub(uint256(_lastUpdateTimestamp)); - uint256 ratePerSecond = _rate.div(SECONDS_PER_YEAR); + if(exp == 0){ + return WadRayMath.ray(); + } + + uint256 expMinusOne = exp.sub(1); + + uint256 expMinusTwo = exp > 2 ? exp.sub(2) : 0; + + uint256 ratePerSecond = _rate.div(31536000); + + uint basePowerTwo = ratePerSecond.rayMul(ratePerSecond); + uint basePowerThree = basePowerTwo.rayMul(ratePerSecond); + + + + uint256 secondTerm = exp.mul(expMinusOne).mul(basePowerTwo).div(2); + uint256 thirdTerm = exp.mul(expMinusOne).mul(expMinusTwo).mul(basePowerThree).div(6); + + + return WadRayMath.ray().add(ratePerSecond.mul(exp)).add(secondTerm).add(thirdTerm); - return ratePerSecond.add(WadRayMath.ray()).rayPow(timeDifference); } } diff --git a/contracts/libraries/WadRayMath.sol b/contracts/libraries/WadRayMath.sol index bf3495b3..0dc29657 100644 --- a/contracts/libraries/WadRayMath.sol +++ b/contracts/libraries/WadRayMath.sol @@ -113,20 +113,4 @@ library WadRayMath { return a.mul(WAD_RAY_RATIO); } - /** - * @dev calculates base^exp. The code uses the ModExp precompile - * @return z base^exp, in ray - */ - //solium-disable-next-line - function rayPow(uint256 x, uint256 n) internal pure returns (uint256 z) { - z = n % 2 != 0 ? x : RAY; - - for (n /= 2; n != 0; n /= 2) { - x = rayMul(x, x); - - if (n % 2 != 0) { - z = rayMul(z, x); - } - } - } } diff --git a/contracts/tokenization/AToken.sol b/contracts/tokenization/AToken.sol index 85229cf0..879ef54c 100644 --- a/contracts/tokenization/AToken.sol +++ b/contracts/tokenization/AToken.sol @@ -223,9 +223,10 @@ contract AToken is VersionedInitializable, ERC20 { require(_amount > 0, 'Amount to redeem needs to be > 0'); //cumulates the balance of the user - (, uint256 currentBalance, uint256 balanceIncrease, uint256 index) = cumulateBalanceInternal( + (, uint256 currentBalance, uint256 balanceIncrease) = calculateBalanceIncreaseInternal( msg.sender ); + uint256 amountToRedeem = _amount; //if amount is equal to uint(-1), the user wants to redeem everything @@ -247,13 +248,21 @@ contract AToken is VersionedInitializable, ERC20 { amountToRedeem ); - // burns tokens equivalent to the amount requested - _burn(msg.sender, amountToRedeem); + if(balanceIncrease > amountToRedeem){ + _mint(msg.sender, balanceIncrease.sub(amountToRedeem)); + } + else{ + _burn(msg.sender, amountToRedeem.sub(balanceIncrease)); + } + + uint256 userIndex = 0; - bool userIndexReset = false; //reset the user data if the remaining balance is 0 if (currentBalance.sub(amountToRedeem) == 0) { - userIndexReset = resetDataOnZeroBalanceInternal(msg.sender); + resetDataOnZeroBalanceInternal(msg.sender); + } else { + //updates the user index + userIndex = userIndexes[msg.sender] = pool.getReserveNormalizedIncome(underlyingAssetAddress); } // executes redeem of the underlying asset @@ -264,28 +273,32 @@ contract AToken is VersionedInitializable, ERC20 { currentBalance.sub(amountToRedeem) ); - emit Redeem(msg.sender, amountToRedeem, balanceIncrease, userIndexReset ? 0 : index); + emit Redeem(msg.sender, amountToRedeem, balanceIncrease, userIndex); } /** * @dev mints token in the event of users depositing the underlying asset into the lending pool * only lending pools can call this function - * @param _account the address receiving the minted tokens + * @param _user the address receiving the minted tokens * @param _amount the amount of tokens to mint */ - function mintOnDeposit(address _account, uint256 _amount) external onlyLendingPool { + function mintOnDeposit(address _user, uint256 _amount) external onlyLendingPool { + //cumulates the balance of the user - (, , uint256 balanceIncrease, uint256 index) = cumulateBalanceInternal(_account); + (, , uint256 balanceIncrease) = calculateBalanceIncreaseInternal(_user); + //updates the user index + uint256 index = userIndexes[_user] = pool.getReserveNormalizedIncome(underlyingAssetAddress); + //if the user is redirecting his interest towards someone else, //we update the redirected balance of the redirection address by adding the accrued interest //and the amount deposited - updateRedirectedBalanceOfRedirectionAddressInternal(_account, balanceIncrease.add(_amount), 0); + updateRedirectedBalanceOfRedirectionAddressInternal(_user, balanceIncrease.add(_amount), 0); //mint an equivalent amount of tokens to cover the new deposit - _mint(_account, _amount); + _mint(_user, _amount.add(balanceIncrease)); - emit MintOnDeposit(_account, _amount, balanceIncrease, index); + emit MintOnDeposit(_user, _amount, balanceIncrease, index); } /** @@ -437,7 +450,34 @@ contract AToken is VersionedInitializable, ERC20 { return redirectedBalances[_user]; } + /** + * @dev calculates the increase in balance since the last user action + * @param _user the address of the user + * @return the last user principal balance, the current balance and the balance increase + **/ + function calculateBalanceIncreaseInternal(address _user) + internal + returns ( + uint256, + uint256, + uint256 + ) + { + uint256 currentBalance = balanceOf(_user); + uint256 balanceIncrease = 0; + uint256 previousBalance = 0; + + if (currentBalance != 0) { + previousBalance = super.balanceOf(_user); + //calculate the accrued interest since the last accumulation + balanceIncrease = currentBalance.sub(previousBalance); + } + + return (previousBalance, currentBalance, balanceIncrease); + } + + /** * @dev accumulates the accrued interest of the user to the principal balance * @param _user the address of the user for which the interest is being accumulated * @return the previous principal balance, the new principal balance, the balance increase @@ -452,21 +492,16 @@ contract AToken is VersionedInitializable, ERC20 { uint256 ) { - uint256 currBalance = balanceOf(_user); - uint256 balanceIncrease = 0; - uint256 previousBalance = 0; + (uint256 previousBalance, uint256 currentBalance, uint256 balanceIncrease) = calculateBalanceIncreaseInternal(_user); + + _mint(_user, balanceIncrease); - if (currBalance != 0) { - previousBalance = super.balanceOf(_user); - //calculate the accrued interest since the last accumulation - balanceIncrease = currBalance.sub(previousBalance); - //mints an amount of tokens equivalent to the amount accumulated - _mint(_user, balanceIncrease); - } //updates the user index uint256 index = userIndexes[_user] = pool.getReserveNormalizedIncome(underlyingAssetAddress); - return (previousBalance, currBalance, balanceIncrease, index); - } + + return (previousBalance, currentBalance, balanceIncrease, index); + + } /** * @dev updates the redirected balance of the user. If the user is not redirecting his diff --git a/contracts/tokenization/StableDebtToken.sol b/contracts/tokenization/StableDebtToken.sol index 6fffbc2a..3f740c7f 100644 --- a/contracts/tokenization/StableDebtToken.sol +++ b/contracts/tokenization/StableDebtToken.sol @@ -67,6 +67,11 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { uint256 _balanceIncrease ); + constructor(address _pool, address _underlyingAsset) + public + DebtTokenBase(_pool, _underlyingAsset) + {} + /** * @dev returns the average stable rate across all the stable rate debt * @return the average stable rate @@ -111,7 +116,8 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { } struct MintLocalVars { - uint256 newSupply; + uint256 supplyAfterMint; + uint256 supplyBeforeMint; uint256 amountInRay; uint256 newStableRate; } @@ -131,11 +137,14 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { MintLocalVars memory vars; //cumulates the user debt - (uint256 previousBalance, uint256 currentBalance, uint256 balanceIncrease) = _cumulateBalance( - _user - ); + ( + uint256 previousBalance, + uint256 currentBalance, + uint256 balanceIncrease + ) = _calculateBalanceIncrease(_user); - vars.newSupply = totalSupply.add(_amount); + vars.supplyBeforeMint = totalSupply.add(balanceIncrease); + vars.supplyAfterMint = vars.supplyBeforeMint.add(_amount); vars.amountInRay = _amount.wadToRay(); @@ -153,11 +162,11 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { //calculates the updated average stable rate avgStableRate = avgStableRate - .rayMul(totalSupply.wadToRay()) + .rayMul(vars.supplyBeforeMint.wadToRay()) .add(_rate.rayMul(vars.amountInRay)) - .rayDiv(vars.newSupply.wadToRay()); + .rayDiv(vars.supplyAfterMint.wadToRay()); - _mint(_user, _amount); + _mint(_user, _amount.add(balanceIncrease)); emit mintDebt( _user, @@ -175,11 +184,16 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { * @param _amount the amount of debt tokens to mint **/ function burn(address _user, uint256 _amount) public override onlyLendingPool { - (uint256 previousBalance, uint256 currentBalance, uint256 balanceIncrease) = _cumulateBalance( - _user - ); + ( + uint256 previousBalance, + uint256 currentBalance, + uint256 balanceIncrease + ) = _calculateCumulatedBalance(_user); - uint256 newSupply = totalSupply.sub(_amount); + uint256 supplyBeforeBurn = totalSupply.add(balanceIncrease); + uint256 supplyAfterBurn = supplyBeforeBurn.sub(_amount); + + uint256 newSupply = totalSupply.add(balanceIncrease).sub(_amount); uint256 amountInRay = _amount.wadToRay(); @@ -187,9 +201,9 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { avgStableRate = 0; } else { avgStableRate = avgStableRate - .rayMul(totalSupply.wadToRay()) + .rayMul(supplyBeforeBurn.wadToRay()) .sub(usersData[_user].currentRate.rayMul(amountInRay)) - .rayDiv(newSupply.wadToRay()); + .rayDiv(supplyAfterBurn.wadToRay()); } if (_amount == currentBalance) { @@ -197,17 +211,21 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { usersData[_user].lastUpdateTimestamp = 0; } - _burn(_user, _amount); + if (balanceIncrease > _amount) { + _mint(_user, balanceIncrease.sub(_amount)); + } else { + _burn(_user, _amount.sub(balanceIncrease)); + } emit burnDebt(_user, _amount, previousBalance, currentBalance, balanceIncrease); } /** - * @dev accumulates the accrued interest of the user to the principal balance + * @dev calculates the increase in balance since the last user action * @param _user the address of the user for which the interest is being accumulated * @return the previous principal balance, the new principal balance, the balance increase **/ - function _cumulateBalance(address _user) + function _calculateBalanceIncrease(address _user) internal returns ( uint256, @@ -223,8 +241,6 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { //calculate the accrued interest since the last accumulation uint256 balanceIncrease = balanceOf(_user).sub(previousPrincipalBalance); - //mints an amount of tokens equivalent to the amount accumulated - _mint(_user, balanceIncrease); return ( previousPrincipalBalance, diff --git a/contracts/tokenization/VariableDebtToken.sol b/contracts/tokenization/VariableDebtToken.sol index 6d1b7337..3e5a3746 100644 --- a/contracts/tokenization/VariableDebtToken.sol +++ b/contracts/tokenization/VariableDebtToken.sol @@ -58,6 +58,11 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken { uint256 _index ); + constructor(address _pool, address _underlyingAsset) + public + DebtTokenBase(_pool, _underlyingAsset) + {} + /** * @dev calculates the accumulated debt balance of the user * @return the debt balance of the user @@ -90,11 +95,13 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken { * @param _amount the amount of debt being minted **/ function mint(address _user, uint256 _amount) public override onlyLendingPool { - (uint256 previousBalance, uint256 currentBalance, uint256 balanceIncrease) = _cumulateBalance( - _user - ); + ( + uint256 previousBalance, + uint256 currentBalance, + uint256 balanceIncrease + ) = _calculateCumulatedBalance(_user); - _mint(_user, _amount); + _mint(_user, _amount.add(balanceIncrease)); userIndexes[_user] = pool.getReserveNormalizedVariableDebt(underlyingAssetAddress); @@ -114,11 +121,17 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken { * @param _amount the amount of debt being burned **/ function burn(address _user, uint256 _amount) public override onlyLendingPool { - (uint256 previousBalance, uint256 currentBalance, uint256 balanceIncrease) = _cumulateBalance( - _user - ); + ( + uint256 previousBalance, + uint256 currentBalance, + uint256 balanceIncrease + ) = _calculateBalanceIncrease(_user); - _burn(_user, _amount); + if (balanceIncrease > _amount) { + _mint(_user, balanceIncrease.sub(_amount)); + } else { + _burn(_user, _amount.sub(balanceIncrease)); + } //if user repaid everything if (currentBalance == _amount) { @@ -138,12 +151,12 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken { } /** - * @dev accumulates the accrued interest of the user to the principal balance + * @dev calculates the increase in balance since the last user interaction * @param _user the address of the user for which the interest is being accumulated * @return the previous principal balance, the new principal balance, the balance increase * and the new user index **/ - function _cumulateBalance(address _user) + function _calculateBalanceIncrease(address _user) internal returns ( uint256, @@ -160,9 +173,6 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken { //calculate the accrued interest since the last accumulation uint256 balanceIncrease = balanceOf(_user).sub(previousPrincipalBalance); - //mints an _amount of tokens equivalent to the _amount accumulated - _mint(_user, balanceIncrease); - return ( previousPrincipalBalance, previousPrincipalBalance.add(balanceIncrease), diff --git a/contracts/tokenization/base/DebtTokenBase.sol b/contracts/tokenization/base/DebtTokenBase.sol index 022c142c..8d0f8e91 100644 --- a/contracts/tokenization/base/DebtTokenBase.sol +++ b/contracts/tokenization/base/DebtTokenBase.sol @@ -22,9 +22,9 @@ abstract contract DebtTokenBase is IERC20 { string public name; string public symbol; uint8 public decimals; - address public underlyingAssetAddress; + address public immutable underlyingAssetAddress; - LendingPool internal pool; + LendingPool internal immutable pool; mapping(address => uint256) internal balances; /** @@ -35,26 +35,24 @@ abstract contract DebtTokenBase is IERC20 { _; } + constructor(address _pool, address _underlyingAssetAddress) public { + pool = LendingPool(payable(_pool)); + underlyingAssetAddress = _underlyingAssetAddress; + } /** * @dev initializes the debt token. * @param _name the name of the token * @param _symbol the symbol of the token * @param _decimals the decimals of the token - * @param _underlying the underlying asset of the debt token - * @param _addressesProvider the addresses provider of the protocol */ function init( string memory _name, string memory _symbol, - uint8 _decimals, - address _underlying, - ILendingPoolAddressesProvider _addressesProvider + uint8 _decimals ) public { name = _name; symbol = _symbol; decimals = _decimals; - underlyingAssetAddress = _underlying; - pool = LendingPool(payable(_addressesProvider.getLendingPool())); } /** diff --git a/deployed-contracts.json b/deployed-contracts.json index 5cfabe17..1c408f8e 100644 --- a/deployed-contracts.json +++ b/deployed-contracts.json @@ -5,7 +5,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xB00cC45B4a7d3e1FEE684cFc4417998A1c183e6d", + "address": "0x4da11393102f7c324f7Bfd07B58773264986e211", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -15,7 +15,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22", + "address": "0x479182FBD6270898bf472583876527667dE6aC04", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -25,7 +25,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x22474D350EC2dA53D717E30b96e9a2B7628Ede5b", + "address": "0x4cC8D5649e9d91a4bD054667691aebeC69B69FfB", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -34,7 +34,7 @@ "address": "0x852e3718A320aD93Ad8692E8D663d247e4c1b400" }, "localhost": { - "address": "0x852e3718A320aD93Ad8692E8D663d247e4c1b400" + "address": "0x0f2cE53B3410a2007d6C4ad8940Ffa5AdCC2916C" } }, "LendingPoolParametersProvider": { @@ -52,7 +52,7 @@ "address": "0xA10958a24032283FbE2D23cedf264d6eC9411CBA" }, "localhost": { - "address": "0xA10958a24032283FbE2D23cedf264d6eC9411CBA" + "address": "0x0ca5E5B6F09C97f30Ed6e5E99be65A38eE7edfaB" } }, "LendingPoolDataProvider": { @@ -65,7 +65,7 @@ "address": "0x2C4603396dE2F08642354A3A102760827FfFe113" }, "localhost": { - "address": "0x2C4603396dE2F08642354A3A102760827FfFe113" + "address": "0x7FE8419fACf45dFa93d471644e87122923EC9D94" } }, "PriceOracle": { @@ -74,7 +74,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xE4C10Db67595aF2Cb4166c8C274e0140f7E43059", + "address": "0xEDf104A35B3293F4BdB987be9D57EFe3b69C19c7", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -84,7 +84,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89", + "address": "0x4CAf641bceba759b352e07B2aE3A079B5F409dA6", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -94,7 +94,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x7B6C3e5486D9e6959441ab554A889099eed76290", + "address": "0xCb9cdF2CfeE567b43FD654f8b831528c2d54D901", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -104,7 +104,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xD83D2773a7873ae2b5f8Fb92097e20a8C64F691E", + "address": "0xeB3E3b080821399daF535D0C52f642b8f14993AC", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -114,7 +114,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x09d728F76D543DB1925f7d1Fd8823e4e82700F99", + "address": "0x3888B5ac0089C12cDF21DD8B0234029f80645324", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -149,7 +149,7 @@ "address": "0x03A6802eF9060a8E1f0e56Bafc9C9AB1A26a1f06" }, "localhost": { - "address": "0x03A6802eF9060a8E1f0e56Bafc9C9AB1A26a1f06" + "address": "0x39f713653d31a8e0D7a51061F1159861290e65Fd" } }, "InitializableAdminUpgradeabilityProxy": { @@ -158,7 +158,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x03A6802eF9060a8E1f0e56Bafc9C9AB1A26a1f06", + "address": "0x39f713653d31a8e0D7a51061F1159861290e65Fd", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -167,7 +167,7 @@ "address": "0x9D37fB22EA7d655f12E68DABBf6B6585A00774C3" }, "localhost": { - "address": "0x9D37fB22EA7d655f12E68DABBf6B6585A00774C3" + "address": "0xC4e948241c7A63d1f21fD98D652aE4B59180e07F" } }, "WalletBalanceProvider": { @@ -176,7 +176,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x2005823e074313cd644035557bF4FFa0ca0Bddff", + "address": "0x5361A119A2b3daFB88585b24997aAB2232C655a3", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -186,7 +186,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F", + "address": "0xeb544bEfD42128e6b08A821aCCc5562c395E8c9d", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -196,7 +196,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf", + "address": "0xe3353ddEc0cf8aA6761a3C21D896D04ebd59bDe2", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -206,7 +206,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x0078371BDeDE8aAc7DeBfFf451B74c5EDB385Af7", + "address": "0xa7B8e0F888D416d7e08bD12029c6ec8b8Ed18373", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -216,7 +216,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xf4e77E5Da47AC3125140c470c71cBca77B5c638c", + "address": "0x7dF045e4721203EBEDD3436b15391f32A375Cbc4", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -226,7 +226,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xf784709d2317D872237C4bC22f867d1BAe2913AB", + "address": "0xbcd58cEF3F429f99CA32Dc06F28Ca7F7ea6aC5bB", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -236,7 +236,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x3619DbE27d7c1e7E91aA738697Ae7Bc5FC3eACA5", + "address": "0xb528f2371502B38d87af537292e88721F4728915", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -246,7 +246,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x038B86d9d8FAFdd0a02ebd1A476432877b0107C8", + "address": "0xC2CC8DD97D4680FCfE2338117D23fa7E4858E09B", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -256,7 +256,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x1A1FEe7EeD918BD762173e4dc5EfDB8a78C924A8", + "address": "0xfC6d9227413D021f7a50EF3AAdF9545aA4ebb439", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -266,7 +266,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x500D1d6A4c7D8Ae28240b47c8FCde034D827fD5e", + "address": "0xdc006C4186148C29B57f52A8ad7694542ad4E675", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -276,7 +276,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xc4905364b78a742ccce7B890A89514061E47068D", + "address": "0x77488a02Baf7a80a5E7D1Da37921D0554C112c7F", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -286,7 +286,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xD6C850aeBFDC46D7F4c207e445cC0d6B0919BDBe", + "address": "0x107Aa2cc3FE981E78140424C3d4DD55aF00Ab24C", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -296,7 +296,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x8B5B7a6055E54a36fF574bbE40cf2eA68d5554b3", + "address": "0x512555303417D50E8E2a3BE333896f5f8c54205c", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -306,7 +306,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xEcc0a6dbC0bb4D51E4F84A315a9e5B0438cAD4f0", + "address": "0x8cD1B99Ff499438BC9B5A41F558E41e3Df10ff08", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -316,7 +316,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x20Ce94F404343aD2752A2D01b43fa407db9E0D00", + "address": "0x66F7097B8204A7a93850D5D29eAcdA6E2AA09A06", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -326,7 +326,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x1d80315fac6aBd3EfeEbE97dEc44461ba7556160", + "address": "0xAfD2Ac057dA78019436cbc59E08a4567E1FDCB02", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -336,7 +336,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x2D8553F9ddA85A9B3259F6Bf26911364B85556F5", + "address": "0xc989A9cB29D1e65F5fD1f5e54306D81EC2aae2d4", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -346,7 +346,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x52d3b94181f8654db2530b0fEe1B19173f519C52", + "address": "0x5D5492e4659e8c26A86a4cB2122b59d3fC8afA23", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -356,7 +356,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xd15468525c35BDBC1eD8F2e09A00F8a173437f2f", + "address": "0x67863e08EBA141fe927605A9A4C614751d550416", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -366,7 +366,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x7e35Eaf7e8FBd7887ad538D4A38Df5BbD073814a", + "address": "0x83eDd07E49dFaBc288AF2215C9dC534C52AB549f", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -376,7 +376,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x5bcb88A0d20426e451332eE6C4324b0e663c50E0", + "address": "0x02D4086e063Ef6cc8d8e6e811bFc596Ed4aa7F0f", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -386,7 +386,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x3521eF8AaB0323004A6dD8b03CE890F4Ea3A13f5", + "address": "0x1865BF8d8F8392a823D9063f55beC6D450c6756A", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -396,7 +396,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x53369fd4680FfE3DfF39Fc6DDa9CfbfD43daeA2E", + "address": "0x2f2abb208a543B0A076aF58cc806a899dE9EFfAC", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -406,7 +406,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xB00cC45B4a7d3e1FEE684cFc4417998A1c183e6d", + "address": "0x4da11393102f7c324f7Bfd07B58773264986e211", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -415,7 +415,7 @@ "address": "0x850Fae11E1313e6C23Db7c2410Ec0985d9Ea325A" }, "localhost": { - "address": "0x850Fae11E1313e6C23Db7c2410Ec0985d9Ea325A" + "address": "0x26af54A97F214dB563711B0670c4FbA2Eb935E37" } }, "StableDebtToken": { @@ -424,7 +424,7 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0xb2B548BE73010C188C083c510d255Aed74843b05", + "address": "0xB76Ea4df0263F99daf33765541b1933AD5bB4410", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -434,13 +434,13 @@ "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "localhost": { - "address": "0x5Ea694f66BD0CBd08FC7967af01b67Dcef68cC5c", + "address": "0x7376e7b11aCE5dDa9068f770a27796826e66E305", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "AToken": { "localhost": { - "address": "0xd4e934C2749CA8C1618659D02E7B28B074bf4df7", + "address": "0x2abb2787B4C39a5667E95f11E8a44c034a58aaac", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" }, "buidlerevm": { diff --git a/helpers/contracts-helpers.ts b/helpers/contracts-helpers.ts index b3392faf..6862b55b 100644 --- a/helpers/contracts-helpers.ts +++ b/helpers/contracts-helpers.ts @@ -259,11 +259,11 @@ export const deployStableDebtToken = async ([ symbol, decimals, underlyingAsset, - addressesProvider, + poolAddress, ]: [string, string, string, tEthereumAddress, tEthereumAddress]) => { - const token = await deployContract(eContractid.StableDebtToken, []); + const token = await deployContract(eContractid.StableDebtToken, [poolAddress, underlyingAsset]); - await token.init(name, symbol, decimals, underlyingAsset, addressesProvider); + await token.init(name, symbol, decimals); return token; }; @@ -273,11 +273,11 @@ export const deployVariableDebtToken = async ([ symbol, decimals, underlyingAsset, - addressesProvider, + poolAddress, ]: [string, string, string, tEthereumAddress, tEthereumAddress]) => { - const token = await deployContract(eContractid.VariableDebtToken, []); + const token = await deployContract(eContractid.VariableDebtToken, [poolAddress, underlyingAsset]); - await token.init(name, symbol, decimals, underlyingAsset, addressesProvider); + await token.init(name, symbol, decimals); return token; }; diff --git a/test/__setup.spec.ts b/test/__setup.spec.ts index 95beef40..952ae07b 100644 --- a/test/__setup.spec.ts +++ b/test/__setup.spec.ts @@ -229,7 +229,7 @@ const initReserves = async ( `stableDebt${assetSymbol}`, reserveDecimals, tokenAddress, - lendingPoolAddressesProvider.address, + lendingPool.address, ]); const variableDebtToken = await deployVariableDebtToken([ @@ -237,7 +237,7 @@ const initReserves = async ( `stableDebt${assetSymbol}`, reserveDecimals, tokenAddress, - lendingPoolAddressesProvider.address, + lendingPool.address, ]); const aToken = await deployGenericAToken([ diff --git a/test/helpers/utils/calculations.ts b/test/helpers/utils/calculations.ts index a3de3eb5..34c25069 100644 --- a/test/helpers/utils/calculations.ts +++ b/test/helpers/utils/calculations.ts @@ -1262,12 +1262,33 @@ const calcCompoundedInterest = ( currentTimestamp: BigNumber, lastUpdateTimestamp: BigNumber ) => { + const timeDifference = currentTimestamp.minus(lastUpdateTimestamp); - const ratePerSecond = rate.div(ONE_YEAR); - const compoundedInterest = ratePerSecond.plus(RAY).rayPow(timeDifference); + if(timeDifference.eq(0)){ + return new BigNumber(RAY); + } - return compoundedInterest; + const expMinusOne = timeDifference.minus(1); + const expMinusTwo = timeDifference.gt(2) ? timeDifference.minus(2) : 0; + + const ratePerSecond = rate.div(ONE_YEAR); + + const basePowerTwo = ratePerSecond.rayMul(ratePerSecond); + const basePowerThree = basePowerTwo.rayMul(ratePerSecond); + + const secondTerm = timeDifference.times(expMinusOne).times(basePowerTwo).div(2); + const thirdTerm = timeDifference + .times(expMinusOne) + .times(expMinusTwo) + .times(basePowerThree) + .div(6); + + return new BigNumber(RAY) + .plus(ratePerSecond.times(timeDifference)) + .plus(secondTerm) + .plus(thirdTerm); + }; const calcExpectedInterestRates = ( diff --git a/test/helpers/utils/math.ts b/test/helpers/utils/math.ts index a56de5e0..df6165d2 100644 --- a/test/helpers/utils/math.ts +++ b/test/helpers/utils/math.ts @@ -13,7 +13,6 @@ declare module 'bignumber.js' { rayDiv: (a: BigNumber) => BigNumber; rayToWad: () => BigNumber; wadToRay: () => BigNumber; - rayPow: (n: BigNumber) => BigNumber; } } @@ -65,17 +64,3 @@ BigNumber.prototype.rayToWad = function (): BigNumber { BigNumber.prototype.wadToRay = function (): BigNumber { return this.multipliedBy(WAD_RAY_RATIO).decimalPlaces(0, BigNumber.ROUND_DOWN); }; - -BigNumber.prototype.rayPow = function (n: BigNumber): BigNumber { - let z = !n.modulo(2).eq(0) ? this : new BigNumber(RAY); - let x = new BigNumber(this); - - for (n = n.div(2); !n.eq(0); n = n.div(2)) { - x = x.rayMul(x); - - if (!n.modulo(2).eq(0)) { - z = z.rayMul(x); - } - } - return z; -}; diff --git a/types/DebtTokenBase.d.ts b/types/DebtTokenBase.d.ts index d701ee65..23d262bd 100644 --- a/types/DebtTokenBase.d.ts +++ b/types/DebtTokenBase.d.ts @@ -33,12 +33,10 @@ interface DebtTokenBaseInterface extends Interface { }>; init: TypedFunctionDescription<{ - encode([_name, _symbol, _decimals, _underlying, _addressesProvider]: [ + encode([_name, _symbol, _decimals]: [ string, string, - BigNumberish, - string, - string + BigNumberish ]): string; }>; @@ -133,8 +131,6 @@ export class DebtTokenBase extends Contract { _name: string, _symbol: string, _decimals: BigNumberish, - _underlying: string, - _addressesProvider: string, overrides?: TransactionOverrides ): Promise; @@ -190,8 +186,6 @@ export class DebtTokenBase extends Contract { _name: string, _symbol: string, _decimals: BigNumberish, - _underlying: string, - _addressesProvider: string, overrides?: TransactionOverrides ): Promise; @@ -250,9 +244,7 @@ export class DebtTokenBase extends Contract { init( _name: string, _symbol: string, - _decimals: BigNumberish, - _underlying: string, - _addressesProvider: string + _decimals: BigNumberish ): Promise; name(): Promise; diff --git a/types/DebtTokenBaseFactory.ts b/types/DebtTokenBaseFactory.ts index 28f29eb0..a2a39c77 100644 --- a/types/DebtTokenBaseFactory.ts +++ b/types/DebtTokenBaseFactory.ts @@ -16,6 +16,22 @@ export class DebtTokenBaseFactory { } const _abi = [ + { + inputs: [ + { + internalType: "address", + name: "_pool", + type: "address" + }, + { + internalType: "address", + name: "_underlyingAssetAddress", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "constructor" + }, { anonymous: false, inputs: [ @@ -210,16 +226,6 @@ const _abi = [ internalType: "uint8", name: "_decimals", type: "uint8" - }, - { - internalType: "address", - name: "_underlying", - type: "address" - }, - { - internalType: "contract ILendingPoolAddressesProvider", - name: "_addressesProvider", - type: "address" } ], name: "init", diff --git a/types/StableDebtToken.d.ts b/types/StableDebtToken.d.ts index 8d478a6a..f10adf93 100644 --- a/types/StableDebtToken.d.ts +++ b/types/StableDebtToken.d.ts @@ -49,12 +49,10 @@ interface StableDebtTokenInterface extends Interface { }>; init: TypedFunctionDescription<{ - encode([_name, _symbol, _decimals, _underlying, _addressesProvider]: [ + encode([_name, _symbol, _decimals]: [ string, string, - BigNumberish, - string, - string + BigNumberish ]): string; }>; @@ -190,8 +188,6 @@ export class StableDebtToken extends Contract { _name: string, _symbol: string, _decimals: BigNumberish, - _underlying: string, - _addressesProvider: string, overrides?: TransactionOverrides ): Promise; @@ -266,8 +262,6 @@ export class StableDebtToken extends Contract { _name: string, _symbol: string, _decimals: BigNumberish, - _underlying: string, - _addressesProvider: string, overrides?: TransactionOverrides ): Promise; @@ -358,9 +352,7 @@ export class StableDebtToken extends Contract { init( _name: string, _symbol: string, - _decimals: BigNumberish, - _underlying: string, - _addressesProvider: string + _decimals: BigNumberish ): Promise; mint( diff --git a/types/StableDebtTokenFactory.ts b/types/StableDebtTokenFactory.ts index 474bd20a..d6d82ce3 100644 --- a/types/StableDebtTokenFactory.ts +++ b/types/StableDebtTokenFactory.ts @@ -13,11 +13,21 @@ export class StableDebtTokenFactory extends ContractFactory { super(_abi, _bytecode, signer); } - deploy(overrides?: TransactionOverrides): Promise { - return super.deploy(overrides) as Promise; + deploy( + _pool: string, + _underlyingAsset: string, + overrides?: TransactionOverrides + ): Promise { + return super.deploy(_pool, _underlyingAsset, overrides) as Promise< + StableDebtToken + >; } - getDeployTransaction(overrides?: TransactionOverrides): UnsignedTransaction { - return super.getDeployTransaction(overrides); + getDeployTransaction( + _pool: string, + _underlyingAsset: string, + overrides?: TransactionOverrides + ): UnsignedTransaction { + return super.getDeployTransaction(_pool, _underlyingAsset, overrides); } attach(address: string): StableDebtToken { return super.attach(address) as StableDebtToken; @@ -34,6 +44,22 @@ export class StableDebtTokenFactory extends ContractFactory { } const _abi = [ + { + inputs: [ + { + internalType: "address", + name: "_pool", + type: "address" + }, + { + internalType: "address", + name: "_underlyingAsset", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "constructor" + }, { anonymous: false, inputs: [ @@ -377,16 +403,6 @@ const _abi = [ internalType: "uint8", name: "_decimals", type: "uint8" - }, - { - internalType: "address", - name: "_underlying", - type: "address" - }, - { - internalType: "contract ILendingPoolAddressesProvider", - name: "_addressesProvider", - type: "address" } ], name: "init", diff --git a/types/VariableDebtToken.d.ts b/types/VariableDebtToken.d.ts index 586d5c11..8b9c379c 100644 --- a/types/VariableDebtToken.d.ts +++ b/types/VariableDebtToken.d.ts @@ -41,12 +41,10 @@ interface VariableDebtTokenInterface extends Interface { }>; init: TypedFunctionDescription<{ - encode([_name, _symbol, _decimals, _underlying, _addressesProvider]: [ + encode([_name, _symbol, _decimals]: [ string, string, - BigNumberish, - string, - string + BigNumberish ]): string; }>; @@ -175,8 +173,6 @@ export class VariableDebtToken extends Contract { _name: string, _symbol: string, _decimals: BigNumberish, - _underlying: string, - _addressesProvider: string, overrides?: TransactionOverrides ): Promise; @@ -246,8 +242,6 @@ export class VariableDebtToken extends Contract { _name: string, _symbol: string, _decimals: BigNumberish, - _underlying: string, - _addressesProvider: string, overrides?: TransactionOverrides ): Promise; @@ -334,9 +328,7 @@ export class VariableDebtToken extends Contract { init( _name: string, _symbol: string, - _decimals: BigNumberish, - _underlying: string, - _addressesProvider: string + _decimals: BigNumberish ): Promise; mint(_user: string, _amount: BigNumberish): Promise; diff --git a/types/VariableDebtTokenFactory.ts b/types/VariableDebtTokenFactory.ts index 815bc758..ce20142a 100644 --- a/types/VariableDebtTokenFactory.ts +++ b/types/VariableDebtTokenFactory.ts @@ -13,11 +13,21 @@ export class VariableDebtTokenFactory extends ContractFactory { super(_abi, _bytecode, signer); } - deploy(overrides?: TransactionOverrides): Promise { - return super.deploy(overrides) as Promise; + deploy( + _pool: string, + _underlyingAsset: string, + overrides?: TransactionOverrides + ): Promise { + return super.deploy(_pool, _underlyingAsset, overrides) as Promise< + VariableDebtToken + >; } - getDeployTransaction(overrides?: TransactionOverrides): UnsignedTransaction { - return super.getDeployTransaction(overrides); + getDeployTransaction( + _pool: string, + _underlyingAsset: string, + overrides?: TransactionOverrides + ): UnsignedTransaction { + return super.getDeployTransaction(_pool, _underlyingAsset, overrides); } attach(address: string): VariableDebtToken { return super.attach(address) as VariableDebtToken; @@ -34,6 +44,22 @@ export class VariableDebtTokenFactory extends ContractFactory { } const _abi = [ + { + inputs: [ + { + internalType: "address", + name: "_pool", + type: "address" + }, + { + internalType: "address", + name: "_underlyingAsset", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "constructor" + }, { anonymous: false, inputs: [ @@ -351,16 +377,6 @@ const _abi = [ internalType: "uint8", name: "_decimals", type: "uint8" - }, - { - internalType: "address", - name: "_underlying", - type: "address" - }, - { - internalType: "contract ILendingPoolAddressesProvider", - name: "_addressesProvider", - type: "address" } ], name: "init",