Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Higher precision interest per block info #1082

Merged
merged 13 commits into from
Jan 28, 2022
39 changes: 39 additions & 0 deletions src/masternodes/loan.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

#include <chainparams.h>
#include <masternodes/loan.h>
#include <boost/multiprecision/cpp_int.hpp>

std::unique_ptr<CLoanView::CLoanSetCollateralTokenImpl> CLoanView::GetLoanCollateralToken(uint256 const & txid) const
{
Expand Down Expand Up @@ -478,3 +479,41 @@ CAmount CLoanView::GetLoanLiquidationPenalty()

return 5 * COIN / 100;
}

std::string GetInterestPerBlockHighPrecisionString(base_uint<128> value) {
struct HighPrecisionInterestValue {
typedef boost::multiprecision::int128_t int128;
typedef int64_t int64;

int128 value;

HighPrecisionInterestValue(base_uint<128> val) {
value = int128("0x" + val.GetHex());
}

int64 GetInterestPerBlockSat() {
return int64(value / HIGH_PRECISION_SCALER);
}

int64 GetInterestPerBlockSubSat() {
return int64(value % HIGH_PRECISION_SCALER);
}

int64 GetInterestPerBlockMagnitude() {
return int64(value / HIGH_PRECISION_SCALER / COIN);
}

int128 GetInterestPerBlockDecimal() {
auto v = GetInterestPerBlockSat();
return v == 0 ? value : value % (int128(HIGH_PRECISION_SCALER) * COIN);
}

std::string GetInterestPerBlockString() {
std::ostringstream result;
result << GetInterestPerBlockMagnitude() << ".";
result << std::setw(24) << std::setfill('0') << GetInterestPerBlockDecimal();
return result.str();
}
};
return HighPrecisionInterestValue(value).GetInterestPerBlockString();
}
2 changes: 2 additions & 0 deletions src/masternodes/loan.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <masternodes/vault.h>
#include <script/script.h>


class CLoanSetCollateralToken
{
public:
Expand Down Expand Up @@ -265,6 +266,7 @@ CAmount TotalInterest(const CInterestRateV2& rate, uint32_t height);
CAmount InterestPerBlock(const CInterestRateV2& rate, uint32_t height);
base_uint<128> TotalInterestCalculation(const CInterestRateV2& rate, uint32_t height);
CAmount CeilInterest(const base_uint<128>& value, uint32_t height);
std::string GetInterestPerBlockHighPrecisionString(base_uint<128> value);

class CLoanTakeLoanMessage
{
Expand Down
25 changes: 17 additions & 8 deletions src/masternodes/rpc_loan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,13 @@ UniValue getinterest(const JSONRPCRequest& request) {
RPCResult
{
"{...} (object) Json object with interest information\n"
" - `interestPerBlock`: Interest per block is always ceiled\n"
" to the min. unit of fi (8 decimals), however interest\n"
" less than this will continue to accrue until actual utilization\n"
" (eg. - payback of the loan), or until sub-fi maturity."
" - `realizedInterestPerBlock`: The actual realized interest\n"
" per block. This is continues to accumulate until\n"
" the min. unit of the blockchain (fi) can be realized. \n"
},
RPCExamples{
HelpExampleCli("getinterest", "LOAN0001 TSLA")
Expand Down Expand Up @@ -1395,19 +1402,21 @@ UniValue getinterest(const JSONRPCRequest& request) {
UniValue obj(UniValue::VOBJ);
for (std::map<DCT_ID, std::pair<base_uint<128>, base_uint<128> > >::iterator it=interest.begin(); it!=interest.end(); ++it)
{
auto token = pcustomcsview->GetToken(it->first);
obj.pushKV("token", token->CreateSymbolKey(it->first));
obj.pushKV("totalInterest", ValueFromAmount(CeilInterest(it->second.first, height)));
obj.pushKV("interestPerBlock", ValueFromAmount(CeilInterest(it->second.second, height)));
auto tokenId = it->first;
auto interestRate = it->second;
auto totalInterest = it->second.first;
auto interestPerBlock = it->second.second;

auto token = pcustomcsview->GetToken(tokenId);
obj.pushKV("token", token->CreateSymbolKey(tokenId));
obj.pushKV("totalInterest", ValueFromAmount(CeilInterest(totalInterest, height)));
obj.pushKV("interestPerBlock", ValueFromAmount(CeilInterest(interestPerBlock, height)));
if (height >= Params().GetConsensus().FortCanningHillHeight)
{
auto subSatoshiInterest = (it->second.second - ((it->second.second / HIGH_PRECISION_SCALER) * HIGH_PRECISION_SCALER)).GetLow64();
obj.pushKV("immatureInterest", UniValue(UniValue::VNUM, strprintf("%de-24", subSatoshiInterest)));
obj.pushKV("realizedInterestPerBlock", UniValue(UniValue::VNUM, GetInterestPerBlockHighPrecisionString(interestPerBlock)));
}

ret.push_back(obj);
}

return ret;
}

Expand Down
21 changes: 21 additions & 0 deletions src/test/loan_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,27 @@ extern std::vector<CAuctionBatch> CollectAuctionBatches(const CCollateralLoans&

BOOST_FIXTURE_TEST_SUITE(loan_tests, TestChain100Setup)

BOOST_AUTO_TEST_CASE(high_precision_interest_rate_tests)
{
BOOST_CHECK_EQUAL(GetInterestPerBlockHighPrecisionString(base_uint<128>(0)), "0.000000000000000000000000");
BOOST_CHECK_EQUAL(GetInterestPerBlockHighPrecisionString(base_uint<128>(1)), "0.000000000000000000000001");
BOOST_CHECK_EQUAL(GetInterestPerBlockHighPrecisionString(base_uint<128>(1)), "0.000000000000000000000001");
BOOST_CHECK_EQUAL(GetInterestPerBlockHighPrecisionString(base_uint<128>(42058)), "0.000000000000000000042058");
BOOST_CHECK_EQUAL(GetInterestPerBlockHighPrecisionString(base_uint<128>(95129375)), "0.000000000000000095129375");
BOOST_CHECK_EQUAL(GetInterestPerBlockHighPrecisionString(base_uint<128>(117009132)), "0.000000000000000117009132");
BOOST_CHECK_EQUAL(GetInterestPerBlockHighPrecisionString(base_uint<128>(11700913242)), "0.000000000000011700913242");

base_uint<128> num;
num.SetHex("21012F95D4094B33"); // 2378234398782343987
BOOST_CHECK_EQUAL(GetInterestPerBlockHighPrecisionString(base_uint<128>(num)), "0.000002378234398782343987");
num.SetHex("3CDC4CA64879921C03BF061156E455BC"); // 80897539693407360060932882613242451388
BOOST_CHECK_EQUAL(GetInterestPerBlockHighPrecisionString(base_uint<128>(num)), "80897539693407.360060932882613242451388");
num.SetHex("10E5FBB8CA9E273D0B0353C23D90A6"); // 87741364994776235347880977943597222
BOOST_CHECK_EQUAL(GetInterestPerBlockHighPrecisionString(base_uint<128>(num)), "87741364994.776235347880977943597222");
num.SetHex("2D5C78FF9C3FE70F9F0B0C7"); // 877413626032608048611111111
BOOST_CHECK_EQUAL(GetInterestPerBlockHighPrecisionString(base_uint<128>(num)), "877.413626032608048611111111");
}

BOOST_AUTO_TEST_CASE(loan_iterest_rate)
{
CCustomCSView mnview(*pcustomcsview);
Expand Down
1 change: 1 addition & 0 deletions test/lint/lint-includes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ EXPECTED_BOOST_INCLUDES=(
boost/variant.hpp
boost/variant/apply_visitor.hpp
boost/variant/static_visitor.hpp
boost/multiprecision/cpp_int.hpp
)

for BOOST_INCLUDE in $(git grep '^#include <boost/' -- "*.cpp" "*.h" | cut -f2 -d: | cut -f2 -d'<' | cut -f1 -d'>' | sort -u); do
Expand Down