@rev-net/core-v6 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ADMINISTRATION.md +186 -0
- package/ARCHITECTURE.md +87 -0
- package/README.md +4 -2
- package/RISKS.md +49 -0
- package/SKILLS.md +22 -2
- package/STYLE_GUIDE.md +482 -0
- package/foundry.toml +6 -6
- package/package.json +13 -10
- package/script/Deploy.s.sol +3 -2
- package/src/REVDeployer.sol +129 -72
- package/src/REVLoans.sol +174 -165
- package/src/interfaces/IREVDeployer.sol +111 -72
- package/src/interfaces/IREVLoans.sol +116 -76
- package/src/structs/REV721TiersHookFlags.sol +14 -0
- package/src/structs/REVBaseline721HookConfig.sol +27 -0
- package/src/structs/REVDeploy721TiersHookConfig.sol +2 -2
- package/test/REV.integrations.t.sol +4 -3
- package/test/REVAutoIssuanceFuzz.t.sol +12 -8
- package/test/REVDeployerAuditRegressions.t.sol +4 -3
- package/test/REVInvincibility.t.sol +8 -6
- package/test/REVInvincibilityHandler.sol +1 -0
- package/test/REVLifecycle.t.sol +4 -3
- package/test/REVLoans.invariants.t.sol +5 -3
- package/test/REVLoansAttacks.t.sol +4 -3
- package/test/REVLoansAuditRegressions.t.sol +13 -24
- package/test/REVLoansFeeRecovery.t.sol +4 -3
- package/test/REVLoansSourced.t.sol +4 -3
- package/test/REVLoansUnSourced.t.sol +4 -3
- package/test/REVLoans_AuditFindings.t.sol +644 -0
- package/test/TestEmptyBuybackSpecs.t.sol +4 -3
- package/test/TestPR09_ConversionDocumentation.t.sol +4 -3
- package/test/TestPR10_LiquidationBehavior.t.sol +4 -3
- package/test/TestPR11_LowFindings.t.sol +4 -3
- package/test/TestPR12_FlashLoanSurplus.t.sol +4 -3
- package/test/TestPR13_CrossSourceReallocation.t.sol +4 -3
- package/test/TestPR15_CashOutCallerValidation.t.sol +4 -3
- package/test/TestPR16_ZeroRepayment.t.sol +4 -3
- package/test/TestPR21_Uint112Overflow.t.sol +4 -3
- package/test/TestPR22_HookArrayOOB.t.sol +4 -3
- package/test/TestPR26_BurnHeldTokens.t.sol +4 -3
- package/test/TestPR27_CEIPattern.t.sol +4 -3
- package/test/TestPR29_SwapTerminalPermission.t.sol +4 -3
- package/test/TestPR32_MixedFixes.t.sol +4 -3
- package/test/TestSplitWeightAdjustment.t.sol +445 -0
- package/test/TestSplitWeightE2E.t.sol +528 -0
- package/test/TestSplitWeightFork.t.sol +821 -0
- package/test/TestStageTransitionBorrowable.t.sol +4 -3
- package/test/fork/ForkTestBase.sol +617 -0
- package/test/fork/TestCashOutFork.t.sol +245 -0
- package/test/fork/TestLoanBorrowFork.t.sol +163 -0
- package/test/fork/TestLoanLiquidationFork.t.sol +129 -0
- package/test/fork/TestLoanReallocateFork.t.sol +103 -0
- package/test/fork/TestLoanRepayFork.t.sol +184 -0
- package/test/fork/TestSplitWeightFork.t.sol +186 -0
- package/test/mock/MockBuybackDataHook.sol +11 -4
- package/test/mock/MockBuybackDataHookMintPath.sol +11 -3
- package/test/regression/TestI20_CumulativeLoanCounter.t.sol +6 -5
- package/test/regression/TestL27_LiquidateGapHandling.t.sol +7 -6
- package/SECURITY.md +0 -68
package/src/REVLoans.sol
CHANGED
|
@@ -57,14 +57,15 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
57
57
|
|
|
58
58
|
error REVLoans_CollateralExceedsLoan(uint256 collateralToReturn, uint256 loanCollateral);
|
|
59
59
|
error REVLoans_InvalidPrepaidFeePercent(uint256 prepaidFeePercent, uint256 min, uint256 max);
|
|
60
|
-
error
|
|
61
|
-
error
|
|
62
|
-
error REVLoans_OverMaxRepayBorrowAmount(uint256 maxRepayBorrowAmount, uint256 repayBorrowAmount);
|
|
63
|
-
error REVLoans_PermitAllowanceNotEnough(uint256 allowanceAmount, uint256 requiredAmount);
|
|
60
|
+
error REVLoans_InvalidTerminal(address terminal, uint256 revnetId);
|
|
61
|
+
error REVLoans_LoanExpired(uint256 timeSinceLoanCreated, uint256 loanLiquidationDuration);
|
|
64
62
|
error REVLoans_NewBorrowAmountGreaterThanLoanAmount(uint256 newBorrowAmount, uint256 loanAmount);
|
|
65
63
|
error REVLoans_NoMsgValueAllowed();
|
|
64
|
+
error REVLoans_NotEnoughCollateral();
|
|
66
65
|
error REVLoans_NothingToRepay();
|
|
67
|
-
error
|
|
66
|
+
error REVLoans_OverMaxRepayBorrowAmount(uint256 maxRepayBorrowAmount, uint256 repayBorrowAmount);
|
|
67
|
+
error REVLoans_OverflowAlert(uint256 value, uint256 limit);
|
|
68
|
+
error REVLoans_PermitAllowanceNotEnough(uint256 allowanceAmount, uint256 requiredAmount);
|
|
68
69
|
error REVLoans_ReallocatingMoreCollateralThanBorrowedAmountAllows(uint256 newBorrowAmount, uint256 loanAmount);
|
|
69
70
|
error REVLoans_SourceMismatch();
|
|
70
71
|
error REVLoans_Unauthorized(address caller, address owner);
|
|
@@ -257,6 +258,13 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
257
258
|
return _determineSourceFeeAmount(loan, amount);
|
|
258
259
|
}
|
|
259
260
|
|
|
261
|
+
/// @notice The revnet ID for the loan with the provided loan ID.
|
|
262
|
+
/// @param loanId The loan ID of the loan to get the revnet ID of.
|
|
263
|
+
/// @return The ID of the revnet.
|
|
264
|
+
function revnetIdOfLoanWith(uint256 loanId) public pure override returns (uint256) {
|
|
265
|
+
return loanId / _ONE_TRILLION;
|
|
266
|
+
}
|
|
267
|
+
|
|
260
268
|
/// @notice Returns the URI where the ERC-721 standard JSON of a loan is hosted.
|
|
261
269
|
/// @param loanId The ID of the loan to get a URI of.
|
|
262
270
|
/// @return The token URI to use for the provided `loanId`.
|
|
@@ -271,13 +279,6 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
271
279
|
return resolver.getUri(loanId);
|
|
272
280
|
}
|
|
273
281
|
|
|
274
|
-
/// @notice The revnet ID for the loan with the provided loan ID.
|
|
275
|
-
/// @param loanId The loan ID of the loan to get the revnet ID of.
|
|
276
|
-
/// @return The ID of the revnet.
|
|
277
|
-
function revnetIdOfLoanWith(uint256 loanId) public pure override returns (uint256) {
|
|
278
|
-
return loanId / _ONE_TRILLION;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
282
|
//*********************************************************************//
|
|
282
283
|
// -------------------------- internal views ------------------------- //
|
|
283
284
|
//*********************************************************************//
|
|
@@ -556,6 +557,11 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
556
557
|
// A loan needs to have collateral.
|
|
557
558
|
if (collateralCount == 0) revert REVLoans_ZeroCollateralLoanIsInvalid();
|
|
558
559
|
|
|
560
|
+
// Make sure the source terminal is registered in the directory for this revnet.
|
|
561
|
+
if (!DIRECTORY.isTerminalOf(revnetId, IJBTerminal(address(source.terminal)))) {
|
|
562
|
+
revert REVLoans_InvalidTerminal(address(source.terminal), revnetId);
|
|
563
|
+
}
|
|
564
|
+
|
|
559
565
|
// Make sure the prepaid fee percent is between `MIN_PREPAID_FEE_PERCENT` and `MAX_PREPAID_FEE_PERCENT`. Meaning
|
|
560
566
|
// an 16 year loan can be paid upfront with a
|
|
561
567
|
// payment of 50% of the borrowed assets, the cheapest possible rate.
|
|
@@ -839,6 +845,56 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
839
845
|
// --------------------- internal transactions ----------------------- //
|
|
840
846
|
//*********************************************************************//
|
|
841
847
|
|
|
848
|
+
/// @notice Accepts an incoming token.
|
|
849
|
+
/// @param token The token being accepted.
|
|
850
|
+
/// @param amount The number of tokens being accepted.
|
|
851
|
+
/// @param allowance The permit2 context.
|
|
852
|
+
/// @return amount The number of tokens which have been accepted.
|
|
853
|
+
function _acceptFundsFor(
|
|
854
|
+
address token,
|
|
855
|
+
uint256 amount,
|
|
856
|
+
JBSingleAllowance memory allowance
|
|
857
|
+
)
|
|
858
|
+
internal
|
|
859
|
+
returns (uint256)
|
|
860
|
+
{
|
|
861
|
+
// If the token is the native token, override `amount` with `msg.value`.
|
|
862
|
+
if (token == JBConstants.NATIVE_TOKEN) return msg.value;
|
|
863
|
+
|
|
864
|
+
// If the token is not native, revert if there is a non-zero `msg.value`.
|
|
865
|
+
if (msg.value != 0) revert REVLoans_NoMsgValueAllowed();
|
|
866
|
+
|
|
867
|
+
// Check if the metadata contains permit data.
|
|
868
|
+
if (allowance.amount != 0) {
|
|
869
|
+
// Make sure the permit allowance is enough for this payment. If not we revert early.
|
|
870
|
+
if (allowance.amount < amount) {
|
|
871
|
+
revert REVLoans_PermitAllowanceNotEnough(allowance.amount, amount);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// Keep a reference to the permit rules.
|
|
875
|
+
IAllowanceTransfer.PermitSingle memory permitSingle = IAllowanceTransfer.PermitSingle({
|
|
876
|
+
details: IAllowanceTransfer.PermitDetails({
|
|
877
|
+
token: token, amount: allowance.amount, expiration: allowance.expiration, nonce: allowance.nonce
|
|
878
|
+
}),
|
|
879
|
+
spender: address(this),
|
|
880
|
+
sigDeadline: allowance.sigDeadline
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
// Set the allowance to `spend` tokens for the user.
|
|
884
|
+
try PERMIT2.permit({owner: _msgSender(), permitSingle: permitSingle, signature: allowance.signature}) {}
|
|
885
|
+
catch (bytes memory) {}
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// Get a reference to the balance before receiving tokens.
|
|
889
|
+
uint256 balanceBefore = _balanceOf(token);
|
|
890
|
+
|
|
891
|
+
// Transfer tokens to this terminal from the msg sender.
|
|
892
|
+
_transferFrom({from: _msgSender(), to: payable(address(this)), token: token, amount: amount});
|
|
893
|
+
|
|
894
|
+
// The amount should reflect the change in balance.
|
|
895
|
+
return _balanceOf(token) - balanceBefore;
|
|
896
|
+
}
|
|
897
|
+
|
|
842
898
|
/// @notice Adds collateral to a loan by burning the collateral tokens permanently.
|
|
843
899
|
/// @dev The collateral tokens are burned via the controller, not held in escrow. They are only re-minted if the
|
|
844
900
|
/// loan is repaid. If the loan expires and is liquidated, the burned collateral is permanently lost.
|
|
@@ -1028,67 +1084,118 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
1028
1084
|
}
|
|
1029
1085
|
}
|
|
1030
1086
|
|
|
1031
|
-
/// @notice
|
|
1032
|
-
/// @param
|
|
1033
|
-
/// @param
|
|
1034
|
-
/// @param
|
|
1035
|
-
///
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1087
|
+
/// @notice Logic to be triggered before transferring tokens from this contract.
|
|
1088
|
+
/// @param to The address the transfer is going to.
|
|
1089
|
+
/// @param token The token being transferred.
|
|
1090
|
+
/// @param amount The number of tokens being transferred, as a fixed point number with the same number of decimals
|
|
1091
|
+
/// as the token specifies.
|
|
1092
|
+
/// @return payValue The value to attach to the transaction being sent.
|
|
1093
|
+
function _beforeTransferTo(address to, address token, uint256 amount) internal returns (uint256) {
|
|
1094
|
+
// If the token is the native token, no allowance needed.
|
|
1095
|
+
if (token == JBConstants.NATIVE_TOKEN) return amount;
|
|
1096
|
+
IERC20(token).safeIncreaseAllowance(to, amount);
|
|
1097
|
+
return 0;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
/// @notice Reallocates collateral from a loan by making a new loan based on the original, with reduced collateral.
|
|
1101
|
+
/// @param loanId The ID of the loan to reallocate collateral from.
|
|
1102
|
+
/// @param revnetId The ID of the revnet the loan is from.
|
|
1103
|
+
/// @param collateralCountToRemove The amount of collateral to remove from the loan.
|
|
1104
|
+
/// @return reallocatedLoanId The ID of the loan.
|
|
1105
|
+
/// @return reallocatedLoan The reallocated loan.
|
|
1106
|
+
function _reallocateCollateralFromLoan(
|
|
1107
|
+
uint256 loanId,
|
|
1108
|
+
uint256 revnetId,
|
|
1109
|
+
uint256 collateralCountToRemove
|
|
1040
1110
|
)
|
|
1041
1111
|
internal
|
|
1042
|
-
returns (uint256)
|
|
1112
|
+
returns (uint256 reallocatedLoanId, REVLoan storage reallocatedLoan)
|
|
1043
1113
|
{
|
|
1044
|
-
//
|
|
1045
|
-
|
|
1114
|
+
// Burn the original loan.
|
|
1115
|
+
_burn(loanId);
|
|
1046
1116
|
|
|
1047
|
-
//
|
|
1048
|
-
|
|
1117
|
+
// Keep a reference to loan having its collateral reduced.
|
|
1118
|
+
REVLoan storage loan = _loanOf[loanId];
|
|
1049
1119
|
|
|
1050
|
-
//
|
|
1051
|
-
if (
|
|
1052
|
-
// Make sure the permit allowance is enough for this payment. If not we revert early.
|
|
1053
|
-
if (allowance.amount < amount) {
|
|
1054
|
-
revert REVLoans_PermitAllowanceNotEnough(allowance.amount, amount);
|
|
1055
|
-
}
|
|
1120
|
+
// Make sure there is enough collateral to transfer.
|
|
1121
|
+
if (collateralCountToRemove > loan.collateral) revert REVLoans_NotEnoughCollateral();
|
|
1056
1122
|
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
details: IAllowanceTransfer.PermitDetails({
|
|
1060
|
-
token: token, amount: allowance.amount, expiration: allowance.expiration, nonce: allowance.nonce
|
|
1061
|
-
}),
|
|
1062
|
-
spender: address(this),
|
|
1063
|
-
sigDeadline: allowance.sigDeadline
|
|
1064
|
-
});
|
|
1123
|
+
// Keep a reference to the new collateral amount.
|
|
1124
|
+
uint256 newCollateralCount = loan.collateral - collateralCountToRemove;
|
|
1065
1125
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1126
|
+
// Keep a reference to the new borrow amount.
|
|
1127
|
+
uint256 borrowAmount = _borrowAmountFrom({loan: loan, revnetId: revnetId, collateralCount: newCollateralCount});
|
|
1128
|
+
|
|
1129
|
+
// Make sure the borrow amount is not less than the original loan's amount.
|
|
1130
|
+
if (borrowAmount < loan.amount) {
|
|
1131
|
+
revert REVLoans_ReallocatingMoreCollateralThanBorrowedAmountAllows(borrowAmount, loan.amount);
|
|
1069
1132
|
}
|
|
1070
1133
|
|
|
1071
|
-
// Get a reference to the
|
|
1072
|
-
|
|
1134
|
+
// Get a reference to the replacement loan ID.
|
|
1135
|
+
reallocatedLoanId = _generateLoanId({revnetId: revnetId, loanNumber: ++totalLoansBorrowedFor[revnetId]});
|
|
1073
1136
|
|
|
1074
|
-
//
|
|
1075
|
-
|
|
1137
|
+
// Get a reference to the loan being created.
|
|
1138
|
+
reallocatedLoan = _loanOf[reallocatedLoanId];
|
|
1076
1139
|
|
|
1077
|
-
//
|
|
1078
|
-
|
|
1140
|
+
// Set the reallocated loan's values the same as the original loan.
|
|
1141
|
+
reallocatedLoan.amount = loan.amount;
|
|
1142
|
+
reallocatedLoan.collateral = loan.collateral;
|
|
1143
|
+
reallocatedLoan.createdAt = loan.createdAt;
|
|
1144
|
+
reallocatedLoan.prepaidFeePercent = loan.prepaidFeePercent;
|
|
1145
|
+
reallocatedLoan.prepaidDuration = loan.prepaidDuration;
|
|
1146
|
+
reallocatedLoan.source = loan.source;
|
|
1147
|
+
|
|
1148
|
+
// Reduce the collateral of the reallocated loan.
|
|
1149
|
+
_adjust({
|
|
1150
|
+
loan: reallocatedLoan,
|
|
1151
|
+
revnetId: revnetId,
|
|
1152
|
+
newBorrowAmount: reallocatedLoan.amount, // Don't change the borrow amount.
|
|
1153
|
+
newCollateralCount: newCollateralCount,
|
|
1154
|
+
sourceFeeAmount: 0,
|
|
1155
|
+
beneficiary: payable(_msgSender()) // use the msgSender as the beneficiary, who will have the returned
|
|
1156
|
+
// collateral tokens debited from their balance for the new loan.
|
|
1157
|
+
});
|
|
1158
|
+
|
|
1159
|
+
// Mint the replacement loan.
|
|
1160
|
+
_mint({to: _msgSender(), tokenId: reallocatedLoanId});
|
|
1161
|
+
|
|
1162
|
+
// Clear stale loan data for gas refund.
|
|
1163
|
+
delete _loanOf[loanId];
|
|
1164
|
+
|
|
1165
|
+
emit ReallocateCollateral({
|
|
1166
|
+
loanId: loanId,
|
|
1167
|
+
revnetId: revnetId,
|
|
1168
|
+
reallocatedLoanId: reallocatedLoanId,
|
|
1169
|
+
reallocatedLoan: reallocatedLoan,
|
|
1170
|
+
removedCollateralCount: collateralCountToRemove,
|
|
1171
|
+
caller: _msgSender()
|
|
1172
|
+
});
|
|
1079
1173
|
}
|
|
1080
1174
|
|
|
1081
|
-
/// @notice
|
|
1082
|
-
/// @param
|
|
1083
|
-
/// @param
|
|
1084
|
-
/// @param
|
|
1085
|
-
///
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1175
|
+
/// @notice Pays off a loan.
|
|
1176
|
+
/// @param loan The loan being paid off.
|
|
1177
|
+
/// @param revnetId The ID of the revnet the loan is being paid off in.
|
|
1178
|
+
/// @param repaidBorrowAmount The amount being paid off, denominated in the token of the source's accounting
|
|
1179
|
+
/// context.
|
|
1180
|
+
function _removeFrom(REVLoan memory loan, uint256 revnetId, uint256 repaidBorrowAmount) internal {
|
|
1181
|
+
// Decrement the total amount of a token being loaned out by the revnet from its terminal.
|
|
1182
|
+
totalBorrowedFrom[revnetId][loan.source.terminal][loan.source.token] -= repaidBorrowAmount;
|
|
1183
|
+
|
|
1184
|
+
// Increase the allowance for the beneficiary.
|
|
1185
|
+
uint256 payValue = _beforeTransferTo({
|
|
1186
|
+
to: address(loan.source.terminal), token: loan.source.token, amount: repaidBorrowAmount
|
|
1187
|
+
});
|
|
1188
|
+
|
|
1189
|
+
// Add the loaned amount back to the revnet.
|
|
1190
|
+
// slither-disable-next-line arbitrary-send-eth
|
|
1191
|
+
loan.source.terminal.addToBalanceOf{value: payValue}({
|
|
1192
|
+
projectId: revnetId,
|
|
1193
|
+
token: loan.source.token,
|
|
1194
|
+
amount: repaidBorrowAmount,
|
|
1195
|
+
shouldReturnHeldFees: false,
|
|
1196
|
+
memo: "Paying off loan",
|
|
1197
|
+
metadata: bytes(abi.encodePacked(REV_ID))
|
|
1198
|
+
});
|
|
1092
1199
|
}
|
|
1093
1200
|
|
|
1094
1201
|
/// @notice Pays down a loan.
|
|
@@ -1117,6 +1224,9 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
1117
1224
|
// If the loan will carry no more amount or collateral, store its changes directly.
|
|
1118
1225
|
// slither-disable-next-line incorrect-equality
|
|
1119
1226
|
if (collateralCountToReturn == loan.collateral) {
|
|
1227
|
+
// Snapshot the loan to memory BEFORE _adjust zeroes the storage pointer.
|
|
1228
|
+
REVLoan memory loanSnapshot = loan;
|
|
1229
|
+
|
|
1120
1230
|
// Borrow in.
|
|
1121
1231
|
_adjust({
|
|
1122
1232
|
loan: loan,
|
|
@@ -1127,15 +1237,15 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
1127
1237
|
beneficiary: beneficiary
|
|
1128
1238
|
});
|
|
1129
1239
|
|
|
1130
|
-
// Snapshot the loan
|
|
1131
|
-
REVLoan memory
|
|
1240
|
+
// Snapshot the zeroed loan for the return value (reflects post-repay state).
|
|
1241
|
+
REVLoan memory paidOffSnapshot = loan;
|
|
1132
1242
|
|
|
1133
1243
|
emit RepayLoan({
|
|
1134
1244
|
loanId: loanId,
|
|
1135
1245
|
revnetId: revnetId,
|
|
1136
1246
|
paidOffLoanId: loanId,
|
|
1137
1247
|
loan: loanSnapshot,
|
|
1138
|
-
paidOffLoan:
|
|
1248
|
+
paidOffLoan: paidOffSnapshot,
|
|
1139
1249
|
repayBorrowAmount: repayBorrowAmount,
|
|
1140
1250
|
sourceFeeAmount: sourceFeeAmount,
|
|
1141
1251
|
collateralCountToReturn: collateralCountToReturn,
|
|
@@ -1146,7 +1256,7 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
1146
1256
|
// Clear stale loan data for gas refund.
|
|
1147
1257
|
delete _loanOf[loanId];
|
|
1148
1258
|
|
|
1149
|
-
return (loanId,
|
|
1259
|
+
return (loanId, paidOffSnapshot);
|
|
1150
1260
|
} else {
|
|
1151
1261
|
// Make a new loan with the remaining amount and collateral.
|
|
1152
1262
|
// Get a reference to the replacement loan ID.
|
|
@@ -1196,107 +1306,6 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
1196
1306
|
}
|
|
1197
1307
|
}
|
|
1198
1308
|
|
|
1199
|
-
/// @notice Reallocates collateral from a loan by making a new loan based on the original, with reduced collateral.
|
|
1200
|
-
/// @param loanId The ID of the loan to reallocate collateral from.
|
|
1201
|
-
/// @param revnetId The ID of the revnet the loan is from.
|
|
1202
|
-
/// @param collateralCountToRemove The amount of collateral to remove from the loan.
|
|
1203
|
-
/// @return reallocatedLoanId The ID of the loan.
|
|
1204
|
-
/// @return reallocatedLoan The reallocated loan.
|
|
1205
|
-
function _reallocateCollateralFromLoan(
|
|
1206
|
-
uint256 loanId,
|
|
1207
|
-
uint256 revnetId,
|
|
1208
|
-
uint256 collateralCountToRemove
|
|
1209
|
-
)
|
|
1210
|
-
internal
|
|
1211
|
-
returns (uint256 reallocatedLoanId, REVLoan storage reallocatedLoan)
|
|
1212
|
-
{
|
|
1213
|
-
// Burn the original loan.
|
|
1214
|
-
_burn(loanId);
|
|
1215
|
-
|
|
1216
|
-
// Keep a reference to loan having its collateral reduced.
|
|
1217
|
-
REVLoan storage loan = _loanOf[loanId];
|
|
1218
|
-
|
|
1219
|
-
// Make sure there is enough collateral to transfer.
|
|
1220
|
-
if (collateralCountToRemove > loan.collateral) revert REVLoans_NotEnoughCollateral();
|
|
1221
|
-
|
|
1222
|
-
// Keep a reference to the new collateral amount.
|
|
1223
|
-
uint256 newCollateralCount = loan.collateral - collateralCountToRemove;
|
|
1224
|
-
|
|
1225
|
-
// Keep a reference to the new borrow amount.
|
|
1226
|
-
uint256 borrowAmount = _borrowAmountFrom({loan: loan, revnetId: revnetId, collateralCount: newCollateralCount});
|
|
1227
|
-
|
|
1228
|
-
// Make sure the borrow amount is not less than the original loan's amount.
|
|
1229
|
-
if (borrowAmount < loan.amount) {
|
|
1230
|
-
revert REVLoans_ReallocatingMoreCollateralThanBorrowedAmountAllows(borrowAmount, loan.amount);
|
|
1231
|
-
}
|
|
1232
|
-
|
|
1233
|
-
// Get a reference to the replacement loan ID.
|
|
1234
|
-
reallocatedLoanId = _generateLoanId({revnetId: revnetId, loanNumber: ++totalLoansBorrowedFor[revnetId]});
|
|
1235
|
-
|
|
1236
|
-
// Get a reference to the loan being created.
|
|
1237
|
-
reallocatedLoan = _loanOf[reallocatedLoanId];
|
|
1238
|
-
|
|
1239
|
-
// Set the reallocated loan's values the same as the original loan.
|
|
1240
|
-
reallocatedLoan.amount = loan.amount;
|
|
1241
|
-
reallocatedLoan.collateral = loan.collateral;
|
|
1242
|
-
reallocatedLoan.createdAt = loan.createdAt;
|
|
1243
|
-
reallocatedLoan.prepaidFeePercent = loan.prepaidFeePercent;
|
|
1244
|
-
reallocatedLoan.prepaidDuration = loan.prepaidDuration;
|
|
1245
|
-
reallocatedLoan.source = loan.source;
|
|
1246
|
-
|
|
1247
|
-
// Reduce the collateral of the reallocated loan.
|
|
1248
|
-
_adjust({
|
|
1249
|
-
loan: reallocatedLoan,
|
|
1250
|
-
revnetId: revnetId,
|
|
1251
|
-
newBorrowAmount: reallocatedLoan.amount, // Don't change the borrow amount.
|
|
1252
|
-
newCollateralCount: newCollateralCount,
|
|
1253
|
-
sourceFeeAmount: 0,
|
|
1254
|
-
beneficiary: payable(_msgSender()) // use the msgSender as the beneficiary, who will have the returned
|
|
1255
|
-
// collateral tokens debited from their balance for the new loan.
|
|
1256
|
-
});
|
|
1257
|
-
|
|
1258
|
-
// Mint the replacement loan.
|
|
1259
|
-
_mint({to: _msgSender(), tokenId: reallocatedLoanId});
|
|
1260
|
-
|
|
1261
|
-
// Clear stale loan data for gas refund.
|
|
1262
|
-
delete _loanOf[loanId];
|
|
1263
|
-
|
|
1264
|
-
emit ReallocateCollateral({
|
|
1265
|
-
loanId: loanId,
|
|
1266
|
-
revnetId: revnetId,
|
|
1267
|
-
reallocatedLoanId: reallocatedLoanId,
|
|
1268
|
-
reallocatedLoan: reallocatedLoan,
|
|
1269
|
-
removedCollateralCount: collateralCountToRemove,
|
|
1270
|
-
caller: _msgSender()
|
|
1271
|
-
});
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
/// @notice Pays off a loan.
|
|
1275
|
-
/// @param loan The loan being paid off.
|
|
1276
|
-
/// @param revnetId The ID of the revnet the loan is being paid off in.
|
|
1277
|
-
/// @param repaidBorrowAmount The amount being paid off, denominated in the token of the source's accounting
|
|
1278
|
-
/// context.
|
|
1279
|
-
function _removeFrom(REVLoan memory loan, uint256 revnetId, uint256 repaidBorrowAmount) internal {
|
|
1280
|
-
// Decrement the total amount of a token being loaned out by the revnet from its terminal.
|
|
1281
|
-
totalBorrowedFrom[revnetId][loan.source.terminal][loan.source.token] -= repaidBorrowAmount;
|
|
1282
|
-
|
|
1283
|
-
// Increase the allowance for the beneficiary.
|
|
1284
|
-
uint256 payValue = _beforeTransferTo({
|
|
1285
|
-
to: address(loan.source.terminal), token: loan.source.token, amount: repaidBorrowAmount
|
|
1286
|
-
});
|
|
1287
|
-
|
|
1288
|
-
// Add the loaned amount back to the revnet.
|
|
1289
|
-
// slither-disable-next-line arbitrary-send-eth
|
|
1290
|
-
loan.source.terminal.addToBalanceOf{value: payValue}({
|
|
1291
|
-
projectId: revnetId,
|
|
1292
|
-
token: loan.source.token,
|
|
1293
|
-
amount: repaidBorrowAmount,
|
|
1294
|
-
shouldReturnHeldFees: false,
|
|
1295
|
-
memo: "Paying off loan",
|
|
1296
|
-
metadata: bytes(abi.encodePacked(REV_ID))
|
|
1297
|
-
});
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
1309
|
/// @notice Returns collateral from a loan.
|
|
1301
1310
|
/// @param revnetId The ID of the revnet the loan is being returned in.
|
|
1302
1311
|
/// @param collateralCount The amount of collateral being returned from the loan.
|