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

Fix Review #1

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions Numa/contracts/NumaProtocol/NumaOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ contract NumaOracle is Ownable2Step, INumaOracle {
//uint maxSpotOffsetBps = 145;//1.45%
//uint maxSpotOffsetSqrtBps = 1204;//sqrt(1.45%)

uint160 maxSpotOffsetPlus1SqrtBps = 10072;
uint160 maxSpotOffsetMinus1SqrtBps = 9927;
uint160 public maxSpotOffsetPlus1SqrtBps = 10072;
uint160 public maxSpotOffsetMinus1SqrtBps = 9927;
Comment on lines +26 to +27
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175

Comment on lines +26 to +27
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175


nuAssetManager public nuAManager;

event IntervalShort(uint32 _intervalShort);
event IntervalLong(uint32 _intervalLong);
event MaxSpotOffsetBps(uint _maxSpotOffsetBps);
event MaxSpotOffset(uint _maxSpotOffset);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175

constructor(
address _token,
uint32 _intervalShort,
Expand Down Expand Up @@ -69,20 +69,18 @@ contract NumaOracle is Ownable2Step, INumaOracle {

/**
*
* @param _maxSpotOffsetBps offset percentage variable (cf doc)
* @param _maxSpotOffset offset percentage variable (cf doc)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175

*/
function setMaxSpotOffsetBps(uint _maxSpotOffsetBps) external onlyOwner {
require(_maxSpotOffsetBps < 10000, "percentage must be less than 100");
function setMaxSpotOffset(uint _maxSpotOffset) external onlyOwner {
require(_maxSpotOffset < 1 ether, "percentage must be less than 100");
Comment on lines +74 to +75
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175

Comment on lines +74 to +75
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175


maxSpotOffsetPlus1SqrtBps =
100 *
uint160(Math.sqrt(10000 + _maxSpotOffsetBps));
uint160(Math.sqrt(1 ether + _maxSpotOffset))/1e5;
Comment on lines 77 to +78
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175

Comment on lines 77 to +78
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175


maxSpotOffsetMinus1SqrtBps =
100 *
uint160(Math.sqrt(10000 - _maxSpotOffsetBps));
uint160(Math.sqrt(1 ether - _maxSpotOffset))/1e5;
Comment on lines 80 to +81
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175

Comment on lines 80 to +81
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175


emit MaxSpotOffsetBps(_maxSpotOffsetBps);
emit MaxSpotOffset(_maxSpotOffset);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#7.

Fixes issues: #175

}

/**
Expand Down
8 changes: 5 additions & 3 deletions Numa/contracts/NumaProtocol/NumaPrinter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,12 @@ contract NumaPrinter is Pausable, Ownable2Step {
uint256 _amountReceived
);

// sherlock issue 41
// CF warning can be bypassed
Comment on lines +71 to +72
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#8.

Fixes issues: #41

Comment on lines +71 to +72
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#8.

Fixes issues: #41

modifier notInWarningCF() {
_;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#8.

Fixes issues: #41

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#8.

Fixes issues: #41

uint currentCF = vaultManager.getGlobalCF();
require(currentCF > vaultManager.getWarningCF(), "minting forbidden");
_;
}

constructor(
Expand Down Expand Up @@ -449,7 +451,7 @@ contract NumaPrinter is Pausable, Ownable2Step {

(uint scaleSynthBurn, , , ) = vaultManager.getSynthScaling();
// apply scale
costWithoutFee = (costWithoutFee * scaleSynthBurn) / BASE_1000;
costWithoutFee = (costWithoutFee * scaleSynthBurn) / BASE_SCALE;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#6.

Fixes issues: #161

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#6.

Fixes issues: #161

// burn fee
uint256 amountToBurn = computeFeeAmountIn(
costWithoutFee,
Expand Down Expand Up @@ -493,7 +495,7 @@ contract NumaPrinter is Pausable, Ownable2Step {
uint256 nuAssetIn = oracle.ethToNuAssetRoundUp(_nuAsset, ethAmount);
(uint scaleSynthBurn, , , ) = vaultManager.getSynthScaling();
// apply scale
nuAssetIn = (nuAssetIn * BASE_1000) / scaleSynthBurn;
nuAssetIn = (nuAssetIn * BASE_SCALE) / scaleSynthBurn;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#6.

Fixes issues: #161

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#6.

Fixes issues: #161


return (nuAssetIn, amountWithFee - _numaAmount);
}
Expand Down
112 changes: 85 additions & 27 deletions Numa/contracts/NumaProtocol/NumaVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ import "../interfaces/INumaVault.sol";

import "./NumaMinter.sol";
import "../lending/CNumaToken.sol";

import "../lending/NumaComptroller.sol";
import "@openzeppelin/contracts_5.0.2/utils/structs/EnumerableSet.sol";
import "../utils/constants.sol";


Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #67, #101, #153

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #153, #67, #101

/// @title Numa vault to mint/burn Numa to lst token
contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {
using EnumerableSet for EnumerableSet.AddressSet;
Expand Down Expand Up @@ -172,14 +173,47 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {
}

/**
* @dev minimum reth borrow balance needed to allow partial liquidations
* @dev minimum lst borrow balance needed to allow partial liquidations
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #67, #101, #153

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #153, #67, #101

*/
function setMinBorrowAmountAllowPartialLiquidation(
uint _minBorrowAmountAllowPartialLiquidation
) external onlyOwner {
minBorrowAmountAllowPartialLiquidation = _minBorrowAmountAllowPartialLiquidation;
}

/**
* @dev minimum borrow balance needed to allow partial liquidations in numa or in lst
*/
function getMinBorrowAmountAllowPartialLiquidation(address _cBorrowToken) external view returns (uint) {
if (_cBorrowToken == address(cNuma) )
{
// numa borrower
// min amount in numa
(
,
,
uint criticalScaleForNumaPriceAndSellFee,
) = vaultManager.getSynthScaling();

uint minBorrowAmountAllowPartialLiquidationNuma = vaultManager
.tokenToNuma(
minBorrowAmountAllowPartialLiquidation,
last_lsttokenvalueWei,
decimals,
criticalScaleForNumaPriceAndSellFee
);
return minBorrowAmountAllowPartialLiquidationNuma;

}
else
{
return minBorrowAmountAllowPartialLiquidation;

}


}

Comment on lines +184 to +216
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #67, #101, #153

Comment on lines +184 to +216
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #153, #67, #101

/**
* @dev set the IVaultOracle address (used to compute token price in Eth)
*/
Expand Down Expand Up @@ -855,11 +889,12 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {

function startLiquidation()
internal
returns (uint criticalScaleForNumaPriceAndSellFee)
returns (uint criticalScaleForNumaPriceAndSellFee, uint sell_fee)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#13.

Fixes issues: #42, #86

{
(
,
criticalScaleForNumaPriceAndSellFee,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#13.

Fixes issues: #86, #42

sell_fee
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#13.

Fixes issues: #42, #86


) = updateVaultAndUpdateDebasing();
// lock numa supply
Expand Down Expand Up @@ -975,7 +1010,7 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {
"invalid param"
);

uint criticalScaleForNumaPriceAndSellFee = startLiquidation();
(uint criticalScaleForNumaPriceAndSellFee,) = startLiquidation();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#13.

Fixes issues: #42, #86


uint numaAmount = _numaAmount;

Expand All @@ -985,19 +1020,6 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {
// AUDITV2FIX: handle max liquidations
if (_numaAmount == type(uint256).max) {
numaAmount = borrowAmount;
} else {
// min liquidation amount
// convert minimum amount for partial liquidations in numa
uint minBorrowAmountAllowPartialLiquidationNuma = vaultManager
.tokenToNuma(
minBorrowAmountAllowPartialLiquidation,
last_lsttokenvalueWei,
decimals,
criticalScaleForNumaPriceAndSellFee
);
uint minAmount = minBorrowAmountAllowPartialLiquidationNuma;
if (borrowAmount < minAmount) minAmount = borrowAmount;
require(numaAmount >= minAmount, "min liquidation");
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #67, #101, #153


if (_flashloan) {
Expand All @@ -1015,7 +1037,7 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {

// liquidate
numa.approve(address(cNuma), numaAmount);
cNuma.liquidateBorrow(
(,uint badDebt) = cNuma.liquidateBorrow(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #67, #101, #153

_borrower,
numaAmount,
CTokenInterface(address(cLstToken))
Expand Down Expand Up @@ -1051,9 +1073,15 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {
decimals,
criticalScaleForNumaPriceAndSellFee
);
// sherlock 86 42
// for numa borrow, numa <-> lst conversions should use buyPrice
maxNumaProfitForLiquidations = (maxNumaProfitForLiquidations * vaultManager.getBuyFee()) / 1 ether;
Comment on lines +1080 to +1082
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#13.

Fixes issues: #42, #86


// cap profit
if (numaLiquidatorProfit > maxNumaProfitForLiquidations)
// sherlock 101 153
// cap only if there is no bad debt, because if we are in bad debt it means this is a partial liquidation which
Comment on lines 1084 to +1086
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#13.

Fixes issues: #86, #42

// should not be capped
if ((badDebt == 0) && (numaLiquidatorProfit > maxNumaProfitForLiquidations))
Comment on lines +1085 to +1088
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #67, #101, #153

numaLiquidatorProfit = maxNumaProfitForLiquidations;

uint numaToSend = numaLiquidatorProfit;
Expand All @@ -1078,6 +1106,9 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {
decimals,
criticalScaleForNumaPriceAndSellFee
);
// sherlock 86 42
// for numa borrow, numa <-> lst conversions should use buyPrice
lstProvidedEstimate = (lstProvidedEstimate * 1 ether) / vaultManager.getBuyFee();
Comment on lines +1113 to +1115
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#13.

Fixes issues: #42, #86


uint lstLiquidatorProfit;
// we don't revert if liquidation is not profitable because it might be profitable
Expand All @@ -1086,8 +1117,13 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {
lstLiquidatorProfit = receivedlst - lstProvidedEstimate;
}


// cap profit
// sherlock 101 153
// cap only if there is no bad debt, because if we are in bad debt it means this is a partial liquidation which
// should not be capped
Comment on lines +1124 to +1128
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #67, #101, #153

uint vaultProfit;
if (lstLiquidatorProfit > maxLstProfitForLiquidations) {
if ((badDebt == 0) && (lstLiquidatorProfit > maxLstProfitForLiquidations)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #67, #101, #153

vaultProfit = lstLiquidatorProfit - maxLstProfitForLiquidations;
}
Comment on lines +1128 to 1132
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #153, #67, #101


Expand Down Expand Up @@ -1132,12 +1168,9 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {
lstAmount = borrowAmount;
}

uint minAmount = minBorrowAmountAllowPartialLiquidation;
if (borrowAmount < minAmount) minAmount = borrowAmount;

require(lstAmount >= minAmount, "min liquidation");

uint criticalScaleForNumaPriceAndSellFee = startLiquidation();
(uint criticalScaleForNumaPriceAndSellFee,uint sellfee) = startLiquidation();
Comment on lines 1176 to +1177
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#13.

Fixes issues: #42, #86


if (!_flashloan) {
// user supplied funds
Expand All @@ -1151,7 +1184,7 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {

// liquidate
IERC20(lstToken).approve(address(cLstToken), lstAmount);
cLstToken.liquidateBorrow(
(,uint badDebt) = cLstToken.liquidateBorrow(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #67, #101, #153

_borrower,
lstAmount,
CTokenInterface(address(cNuma))
Expand All @@ -1176,7 +1209,10 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {
uint lstLiquidatorProfit = lstReceived - lstAmount;

// cap profit
if (lstLiquidatorProfit > maxLstProfitForLiquidations)
// sherlock 101 153
// cap only if there is no bad debt, because if we are in bad debt it means this is a partial liquidation which
// should not be capped
if ((badDebt == 0) && (lstLiquidatorProfit > maxLstProfitForLiquidations))
Comment on lines +1216 to +1219
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #67, #101, #153

lstLiquidatorProfit = maxLstProfitForLiquidations;

uint lstToSend = lstLiquidatorProfit;
Expand All @@ -1193,12 +1229,20 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {
decimals,
criticalScaleForNumaPriceAndSellFee
);
// sherlock 86 42
// for lst borrow, numa <-> lst conversions should use sellPrice
numaProvidedEstimate = (numaProvidedEstimate * 1 ether) / sellfee;

Comment on lines +1236 to +1239
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#13.

Fixes issues: #42, #86

uint maxNumaProfitForLiquidations = vaultManager.tokenToNuma(
maxLstProfitForLiquidations,
last_lsttokenvalueWei,
decimals,
Comment on lines 1240 to 1243
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#13.

Fixes issues: #86, #42

criticalScaleForNumaPriceAndSellFee
);
// sherlock 86 42
// for lst borrow, numa <-> lst conversions should use sellPrice
maxNumaProfitForLiquidations = (maxNumaProfitForLiquidations * 1 ether) / sellfee;

Comment on lines +1246 to +1249
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#13.

Fixes issues: #42, #86


uint numaLiquidatorProfit;
// we don't revert if liquidation is not profitable because it might be profitable
Expand All @@ -1208,7 +1252,11 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {
}

uint vaultProfit;
if (numaLiquidatorProfit > maxNumaProfitForLiquidations) {
// cap profit
// sherlock 101 153
// cap only if there is no bad debt, because if we are in bad debt it means this is a partial liquidation which
// should not be capped
if ((badDebt == 0) && (numaLiquidatorProfit > maxNumaProfitForLiquidations)) {
Comment on lines +1259 to +1263
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#16.

Fixes issues: #67, #101, #153

vaultProfit =
numaLiquidatorProfit -
maxNumaProfitForLiquidations;
Expand Down Expand Up @@ -1318,4 +1366,14 @@ contract NumaVault is Ownable2Step, ReentrancyGuard, Pausable, INumaVault {
}
return (extSize > 0);
}


function borrowAllowed(address _ctokenAddress) external view returns (bool allowed)
{
allowed = true;
if (_ctokenAddress == address(cNuma))
{
Comment on lines +1373 to +1379
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#14.

Fixes issues: #57

allowed = vaultManager.numaBorrowAllowed();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#14.

Fixes issues: #57

}
}
Comment on lines +1381 to +1382
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#14.

Fixes issues: #57

}
Comment on lines +1377 to 1383
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change related to NumaMoney/Numa#14.

Fixes issues: #57

Loading