Enforce valid range of LoanSet.InterestRate

- Addresses FIND-002 from audit.
- Enforces a range of 0-100% in 1/10 bips.
- Also add a couple of unit test checks.
This commit is contained in:
Ed Hennis
2025-07-30 13:56:50 -04:00
parent 83ba11d505
commit 84acebeb7f
3 changed files with 26 additions and 0 deletions

View File

@@ -146,6 +146,14 @@ static_assert(maxCoverRate == TenthBips32(100'000u));
Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxOverpaymentFee = percentageToTenthBips(100);
static_assert(maxOverpaymentFee == TenthBips32(100'000u));
/** Annualized interest rate of the Loan in 1/10 bips.
*
* Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxInterestRate = percentageToTenthBips(100);
static_assert(maxInterestRate == TenthBips32(100'000u));
/** The maximum premium added to the interest rate for late payments on a loan
* in 1/10 bips.
@@ -153,6 +161,7 @@ TenthBips32 constexpr maxOverpaymentFee = percentageToTenthBips(100);
* Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxLateInterestRate = percentageToTenthBips(100);
static_assert(maxLateInterestRate == TenthBips32(100'000u));
/** The maximum close interest rate charged for repaying a loan early in 1/10
* bips.
@@ -160,6 +169,7 @@ TenthBips32 constexpr maxLateInterestRate = percentageToTenthBips(100);
* Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxCloseInterestRate = percentageToTenthBips(100);
static_assert(maxCloseInterestRate == TenthBips32(100'000u));
/** The maximum overpayment interest rate charged on loan overpayments in 1/10
* bips.
@@ -167,6 +177,7 @@ TenthBips32 constexpr maxCloseInterestRate = percentageToTenthBips(100);
* Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxOverpaymentInterestRate = percentageToTenthBips(100);
static_assert(maxOverpaymentInterestRate == TenthBips32(100'000u));
/** The maximum length of a URI inside an NFT */
std::size_t constexpr maxTokenURILength = 256;

View File

@@ -748,6 +748,19 @@ class Loan_test : public beast::unit_test::suite
loanSetFee,
ter(temINVALID));
// sfInterestRate: good value, bad account
env(set(evan, broker.brokerID, principalRequest, startDate),
sig(sfCounterpartySignature, borrower),
interestRate(maxInterestRate),
loanSetFee,
ter(tefBAD_AUTH));
// sfInterestRate: too big
env(set(evan, broker.brokerID, principalRequest, startDate),
sig(sfCounterpartySignature, lender),
interestRate(maxInterestRate + 1),
loanSetFee,
ter(temINVALID));
// sfLateInterestRate: good value, bad account
env(set(evan, broker.brokerID, principalRequest, startDate),
sig(sfCounterpartySignature, borrower),

View File

@@ -82,6 +82,8 @@ LoanSet::preflight(PreflightContext const& ctx)
if (auto const data = tx[~sfData]; data && !data->empty() &&
!validDataLength(tx[~sfData], maxDataPayloadLength))
return temINVALID;
if (!validNumericRange(tx[~sfInterestRate], maxInterestRate))
return temINVALID;
if (!validNumericRange(tx[~sfOverpaymentFee], maxOverpaymentFee))
return temINVALID;
if (!validNumericRange(tx[~sfLateInterestRate], maxLateInterestRate))