How to use Floating Points in Solidity? || How to Calculate Amortizing Loans in Solidity?
Solidity is an object-oriented programming language for implementing smart contracts on various blockchain platforms, most notably, Ethereum.
Yet, Solidity not supporting Floating points is really painful, right?
That’s why I, Wahaj am here to present a workaround using precisions by levelling each value to a certain power and it is really simple, now there’s one thing that you should know beforehand, its that solidity cannot handle really huge numbers for example 50³⁶⁰ etc so we are going to be taking help from the frontend as well, since the smart contract solely cannot do anything without the help of its best friend.
I am going to teach this by example of calculating Amortizing Loans and what monthly payment should be made along with the interest applied. This is going to be gas expensive since the loops usually have a lot of iterations but the main point is to get to use Floating Points.
Lets talk about how to calculate the Amortizing Loan:
Here the Monthly Payment = Principal Amount + Interest Amount
The Variables we need are the loan required(a), the interest rate, and the term(n) in months.
Now,
Periodic Interest Rate (r) = Interest / 12(months in a year)
and
Loan Amount (Monthly Payment) = [a * {r(1+r)^n}] / [{(1+r)^n}-1]
So, Open up Remix, fasten your seatbelts and here we go:
Step 1: Safety First
The first thing you need to do is to import SafeMath and use it for uint256 so we do not end up doing something really scary for the compiler.
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract Loan {using SafeMath for uint256;}
Step 2: Time to be Precise
Now, you have to decide how many decimal places you want your accuracy to hold for. I am using 8 as my PRECISION value.
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract Loan{using SafeMath for uint256;uint256 private constant PRECISION = 8;}
Step 3: Create the function with the requirements
Before doing that, suppose
b = [{(1+r)^n}-1] and c = [{r(1+r)^n}]
so the formula potentially becomes:
Payment = (a * c) / b
The reason I am receiving these values as function arguments is as I mentioned above that solidity cannot fathom such high powers for numbers and since we are going to use precisions these values are going to go really high later on. But that’s for later on, here is the function structure. The values being returned are simple, we will also get onto them later.
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract Loan{using SafeMath for uint256;uint256 private constant PRECISION = 8;function calculate(uint256 b,uint256 c)public pure returns(uint256,uint256[] memory,uint256[] memory){}
}
Step 4: Calculating the Periodic Interest Rate (r)
You must have seen it coming, we are finally onto using precisions. So, considering Interest Rate at 6% we can calculate this value as:
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract Loan{using SafeMath for uint256;uint256 private constant PRECISION = 8;function calculate(uint256 b,uint256 c)public pure returns(uint256,uint256[] memory,uint256[] memory){uint256 interest = 6;uint256 r = (interest* 10**PRECISION) / 1200;}
}
if you print the rate now, you can just go back 8 decimal places to see the actual result.
take the decimal back 8 places, and it becomes 0.005 which is in fact correct.
Step 5: Add Required Variables
Now, its about time we add the variables we are going to need either from our contract or outside from the contract. You can always of course get them as parameters but for now I am just getting b and c here.
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract Loan{using SafeMath for uint256;uint256 private constant PRECISION = 8;function calculate(uint256 b,uint256 c)public pure returns(uint256,uint256[] memory,uint256[] memory){
uint256 loanRequired = 40000;
uint256 a = loanRequired * 10**PRECISION;
uint256 n = 60;uint256[] memory interestAmount = new uint256[](10);uint256[] memory principal = new uint256[](10);uint256 interest = 6;uint256 r = (interest* 10**PRECISION) / 1200;
}}
Let’s talk about arrays I just created. I am giving them a size of 10 instead of n since remix has a limited memory. These arrays will be used to store our answers.
Step 6: Monthly Payment TIME
Remember the formula for b and c?
About time we use them…
b = [{(1+r)^n}-1]
using a calculator or (frontend) we can get b which is :
and c = [{r(1+r)^n}] which is:
Pick the values till the first 8 decimal places.
we get b = 34885015 and c = 674425.
Now, everything is intact, so about time we calculate the monthly payment.
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract Loan{using SafeMath for uint256;uint256 private constant PRECISION = 8;function calculate(uint256 b,uint256 c)public pure returns(uint256,uint256[] memory,uint256[] memory){
uint256 loanRequired = 40000;
uint256 a = loanRequired * 10**PRECISION;
uint256 n = 60;uint256[] memory interestAmount = new uint256[](10);uint256[] memory principal = new uint256[](10);uint256 interest = 6;uint256 r = (interest* 10**PRECISION) / 1200;uint256 monthly = SafeMath.div(a.mul(c),b);}}
Step 7: Create the Loop and get the values for the first 10 months.
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract Loan{using SafeMath for uint256;uint256 private constant PRECISION = 8;function calculate(uint256 b,uint256 c)public pure returns(uint256,uint256[] memory,uint256[] memory){
uint256 loanRequired = 40000;
uint256 a = loanRequired * 10**PRECISION;
uint256 n = 60;uint256[] memory interestAmount = new uint256[](10);uint256[] memory principal = new uint256[](10);uint256 interest = 6;uint256 r = (interest* 10**PRECISION) / 1200;uint256 monthly = SafeMath.div(a.mul(c),b);for(uint256 i=0;i<10;i++){interestAmount[i] = (r.mul(a));principal[i] = monthly - interestAmount[i]/ 10**PRECISION;a -= principal[i];}
return (monthly,interestAmount,principal);}}
Here we go, this is the final state of the smart contract and we are returning the monthly amount to be paid, the interest amount and the principal amount per month.
Step 8: TESTING TIME
Here are the actual calculations from the balance loan calculator.
and here are our answers :
Monthly Payment is:
Take 8 decimal places backwards and we get 773.31197936$ which is exactly what we need. There is more, just wait
Next up, we have Interest Payment per month:
cropped the first 4 here and since the interest payment was calculated with two 8 decimal precision numbers, we will take 16 places back so the values are 200$, 197.13344$, 194.252547$ and 191.357$ which is accurate. You can always round off to the decimal places you want.
and finally we have Principal Payments :
Again, take 8 decimal places back and we have 573.311979$, 576.178539$, 579.059$ and 581.9547$.
And there we have it. Thankyou for reading this article and I am hopeful that you got better with using Floating Points after this. If you liked this, follow me on Linkedin Wahaj Javed At last, Happy Coding!
New to trading? Try crypto trading bots or copy trading