@rev-net/core-v6 0.0.13 → 0.0.15

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.
Files changed (64) hide show
  1. package/CHANGE_LOG.md +8 -3
  2. package/SKILLS.md +1 -1
  3. package/foundry.toml +7 -0
  4. package/package.json +8 -9
  5. package/src/REVDeployer.sol +34 -12
  6. package/src/REVLoans.sol +1 -5
  7. package/test/REVDeployerRegressions.t.sol +6 -3
  8. package/test/REVInvincibility.t.sol +6 -18
  9. package/test/REVLoansAttacks.t.sol +19 -11
  10. package/test/REVLoansFeeRecovery.t.sol +19 -11
  11. package/test/REVLoansFindings.t.sol +19 -11
  12. package/test/REVLoansRegressions.t.sol +19 -11
  13. package/test/REVLoansSourced.t.sol +0 -8
  14. package/test/TestCashOutCallerValidation.t.sol +74 -0
  15. package/test/TestLowFindings.t.sol +3 -1
  16. package/test/TestMixedFixes.t.sol +6 -4
  17. package/test/TestSplitWeightAdjustment.t.sol +10 -5
  18. package/test/fork/TestAutoIssuanceFork.t.sol +148 -0
  19. package/test/fork/TestCashOutFork.t.sol +22 -21
  20. package/test/fork/TestIssuanceDecayFork.t.sol +158 -0
  21. package/test/fork/TestLoanERC20Fork.t.sol +463 -0
  22. package/test/fork/TestLoanRepayFork.t.sol +2 -2
  23. package/test/fork/TestPermit2PaymentFork.t.sol +299 -0
  24. package/test/helpers/MaliciousContracts.sol +36 -22
  25. package/test/mock/MockBuybackDataHook.sol +50 -6
  26. package/deployments/revnet-core-v5/arbitrum/REVDeployer.json +0 -2821
  27. package/deployments/revnet-core-v5/arbitrum/REVLoans.json +0 -2260
  28. package/deployments/revnet-core-v5/arbitrum_sepolia/REVDeployer.json +0 -2821
  29. package/deployments/revnet-core-v5/arbitrum_sepolia/REVLoans.json +0 -2260
  30. package/deployments/revnet-core-v5/base/REVDeployer.json +0 -2825
  31. package/deployments/revnet-core-v5/base/REVLoans.json +0 -2264
  32. package/deployments/revnet-core-v5/base_sepolia/REVDeployer.json +0 -2825
  33. package/deployments/revnet-core-v5/base_sepolia/REVLoans.json +0 -2264
  34. package/deployments/revnet-core-v5/ethereum/REVDeployer.json +0 -2825
  35. package/deployments/revnet-core-v5/ethereum/REVLoans.json +0 -2264
  36. package/deployments/revnet-core-v5/optimism/REVDeployer.json +0 -2821
  37. package/deployments/revnet-core-v5/optimism/REVLoans.json +0 -2260
  38. package/deployments/revnet-core-v5/optimism_sepolia/REVDeployer.json +0 -2825
  39. package/deployments/revnet-core-v5/optimism_sepolia/REVLoans.json +0 -2264
  40. package/deployments/revnet-core-v5/sepolia/REVDeployer.json +0 -2825
  41. package/deployments/revnet-core-v5/sepolia/REVLoans.json +0 -2264
  42. package/docs/book.css +0 -13
  43. package/docs/book.toml +0 -13
  44. package/docs/solidity.min.js +0 -74
  45. package/docs/src/README.md +0 -185
  46. package/docs/src/SUMMARY.md +0 -18
  47. package/docs/src/src/README.md +0 -7
  48. package/docs/src/src/REVDeployer.sol/contract.REVDeployer.md +0 -999
  49. package/docs/src/src/REVLoans.sol/contract.REVLoans.md +0 -1108
  50. package/docs/src/src/interfaces/IREVDeployer.sol/interface.IREVDeployer.md +0 -525
  51. package/docs/src/src/interfaces/IREVLoans.sol/interface.IREVLoans.md +0 -598
  52. package/docs/src/src/interfaces/README.md +0 -5
  53. package/docs/src/src/structs/README.md +0 -12
  54. package/docs/src/src/structs/REVAutoIssuance.sol/struct.REVAutoIssuance.md +0 -19
  55. package/docs/src/src/structs/REVBuybackHookConfig.sol/struct.REVBuybackHookConfig.md +0 -19
  56. package/docs/src/src/structs/REVBuybackPoolConfig.sol/struct.REVBuybackPoolConfig.md +0 -21
  57. package/docs/src/src/structs/REVConfig.sol/struct.REVConfig.md +0 -23
  58. package/docs/src/src/structs/REVCroptopAllowedPost.sol/struct.REVCroptopAllowedPost.md +0 -32
  59. package/docs/src/src/structs/REVDeploy721TiersHookConfig.sol/struct.REVDeploy721TiersHookConfig.md +0 -34
  60. package/docs/src/src/structs/REVDescription.sol/struct.REVDescription.md +0 -23
  61. package/docs/src/src/structs/REVLoan.sol/struct.REVLoan.md +0 -28
  62. package/docs/src/src/structs/REVLoanSource.sol/struct.REVLoanSource.md +0 -16
  63. package/docs/src/src/structs/REVStageConfig.sol/struct.REVStageConfig.md +0 -44
  64. package/docs/src/src/structs/REVSuckerDeploymentConfig.sol/struct.REVSuckerDeploymentConfig.md +0 -16
@@ -1,1108 +0,0 @@
1
- # REVLoans
2
- [Git Source](https://github.com/rev-net/revnet-core-v6/blob/94c003a3a16de2bd012d63cccedd6bd38d21f6e7/src/REVLoans.sol)
3
-
4
- **Inherits:**
5
- ERC721, ERC2771Context, Ownable, [IREVLoans](/src/interfaces/IREVLoans.sol/interface.IREVLoans.md)
6
-
7
- A contract for borrowing from revnets.
8
-
9
- Tokens used as collateral are burned, and reminted when the loan is paid off. This keeps the revnet's token
10
- structure orderly.
11
-
12
- The borrowable amount is the same as the cash out amount.
13
-
14
- An upfront fee is taken when a loan is created. 2.5% is charged by the underlying protocol, 2.5% is charged
15
- by the
16
- revnet issuing the loan, and a variable amount charged by the revnet that receives the fees. This variable amount is
17
- chosen by the borrower, the more paid upfront, the longer the prepaid duration. The loan can be repaid anytime
18
- within the prepaid duration without additional fees.
19
- After the prepaid duration, the loan will increasingly cost more to pay off. After 10 years, the loan collateral
20
- cannot be
21
- recouped.
22
-
23
- The loaned amounts include the fees taken, meaning the amount paid back is the amount borrowed plus the fees.
24
-
25
-
26
- ## State Variables
27
- ### LOAN_LIQUIDATION_DURATION
28
- After the prepaid duration, the loan will cost more to pay off. After 10 years, the loan
29
- collateral cannot be recouped. This means paying 50% of the loan amount upfront will pay for having access to
30
- the remaining 50% for 10 years,
31
- whereas paying 0% of the loan upfront will cost 100% of the loan amount to be paid off after 10 years. After 10
32
- years with repayment, both loans cost 100% and are liquidated.
33
-
34
-
35
- ```solidity
36
- uint256 public constant override LOAN_LIQUIDATION_DURATION = 3650 days
37
- ```
38
-
39
-
40
- ### MAX_PREPAID_FEE_PERCENT
41
- The maximum amount of a loan that can be prepaid at the time of borrowing, in terms of JBConstants.MAX_FEE.
42
-
43
-
44
- ```solidity
45
- uint256 public constant override MAX_PREPAID_FEE_PERCENT = 500
46
- ```
47
-
48
-
49
- ### REV_PREPAID_FEE_PERCENT
50
- A fee of 1% is charged by the $REV revnet.
51
-
52
-
53
- ```solidity
54
- uint256 public constant override REV_PREPAID_FEE_PERCENT = 10
55
- ```
56
-
57
-
58
- ### MIN_PREPAID_FEE_PERCENT
59
- A fee of 2.5% is charged by the loan's source upfront.
60
-
61
-
62
- ```solidity
63
- uint256 public constant override MIN_PREPAID_FEE_PERCENT = 25
64
- ```
65
-
66
-
67
- ### _ONE_TRILLION
68
- Just a kind reminder to our readers.
69
-
70
- Used in loan token ID generation.
71
-
72
-
73
- ```solidity
74
- uint256 private constant _ONE_TRILLION = 1_000_000_000_000
75
- ```
76
-
77
-
78
- ### PERMIT2
79
- The permit2 utility.
80
-
81
-
82
- ```solidity
83
- IPermit2 public immutable override PERMIT2
84
- ```
85
-
86
-
87
- ### CONTROLLER
88
- The controller of revnets that use this loans contract.
89
-
90
-
91
- ```solidity
92
- IJBController public immutable override CONTROLLER
93
- ```
94
-
95
-
96
- ### DIRECTORY
97
- The directory of terminals and controllers for revnets.
98
-
99
-
100
- ```solidity
101
- IJBDirectory public immutable override DIRECTORY
102
- ```
103
-
104
-
105
- ### PRICES
106
- A contract that stores prices for each revnet.
107
-
108
-
109
- ```solidity
110
- IJBPrices public immutable override PRICES
111
- ```
112
-
113
-
114
- ### PROJECTS
115
- Mints ERC-721s that represent revnet ownership and transfers.
116
-
117
-
118
- ```solidity
119
- IJBProjects public immutable override PROJECTS
120
- ```
121
-
122
-
123
- ### REV_ID
124
- The ID of the REV revnet that will receive the fees.
125
-
126
-
127
- ```solidity
128
- uint256 public immutable override REV_ID
129
- ```
130
-
131
-
132
- ### isLoanSourceOf
133
- An indication if a revnet currently has outstanding loans from the specified terminal in the specified
134
- token.
135
-
136
-
137
- ```solidity
138
- mapping(uint256 revnetId => mapping(IJBPayoutTerminal terminal => mapping(address token => bool)))
139
- public
140
- override isLoanSourceOf
141
- ```
142
-
143
-
144
- ### totalLoansBorrowedFor
145
- The cumulative number of loans ever created for a revnet, used as a loan ID sequence counter.
146
-
147
- This counter only increments (on borrow, repay-with-new-loan, and reallocation) and never decrements.
148
- It does NOT represent the number of currently active loans. Repaid and liquidated loans leave permanent gaps
149
- in the ID sequence. Integrators should not use this to count active loans.
150
-
151
-
152
- ```solidity
153
- mapping(uint256 revnetId => uint256) public override totalLoansBorrowedFor
154
- ```
155
-
156
-
157
- ### tokenUriResolver
158
- The contract resolving each project ID to its ERC721 URI.
159
-
160
-
161
- ```solidity
162
- IJBTokenUriResolver public override tokenUriResolver
163
- ```
164
-
165
-
166
- ### totalBorrowedFrom
167
- The total amount loaned out by a revnet from a specified terminal in a specified token.
168
-
169
-
170
- ```solidity
171
- mapping(uint256 revnetId => mapping(IJBPayoutTerminal terminal => mapping(address token => uint256)))
172
- public
173
- override totalBorrowedFrom
174
- ```
175
-
176
-
177
- ### totalCollateralOf
178
- The total amount of collateral supporting a revnet's loans.
179
-
180
-
181
- ```solidity
182
- mapping(uint256 revnetId => uint256) public override totalCollateralOf
183
- ```
184
-
185
-
186
- ### _loanSourcesOf
187
- The sources of each revnet's loan.
188
-
189
- This array grows monotonically -- entries are appended when a new (terminal, token) pair is first used for
190
- borrowing, but are never removed. The `isLoanSourceOf` mapping tracks whether a source has been registered.
191
- Since the number of distinct (terminal, token) pairs per revnet is practically bounded (typically < 10),
192
- the gas cost of iterating this array in `loanSourcesOf` remains manageable.
193
-
194
- **Note:**
195
- member: revnetId The ID of the revnet issuing the loan.
196
-
197
-
198
- ```solidity
199
- mapping(uint256 revnetId => REVLoanSource[]) internal _loanSourcesOf
200
- ```
201
-
202
-
203
- ### _loanOf
204
- The loans.
205
-
206
- **Note:**
207
- member: The ID of the loan.
208
-
209
-
210
- ```solidity
211
- mapping(uint256 loanId => REVLoan) internal _loanOf
212
- ```
213
-
214
-
215
- ## Functions
216
- ### constructor
217
-
218
-
219
- ```solidity
220
- constructor(
221
- IJBController controller,
222
- IJBProjects projects,
223
- uint256 revId,
224
- address owner,
225
- IPermit2 permit2,
226
- address trustedForwarder
227
- )
228
- ERC721("REV Loans", "$REVLOAN")
229
- ERC2771Context(trustedForwarder)
230
- Ownable(owner);
231
- ```
232
- **Parameters**
233
-
234
- |Name|Type|Description|
235
- |----|----|-----------|
236
- |`controller`|`IJBController`|The controller that manages revnets using this loans contract.|
237
- |`projects`|`IJBProjects`|The contract that mints ERC-721s representing project ownership.|
238
- |`revId`|`uint256`|The ID of the REV revnet that will receive the fees.|
239
- |`owner`|`address`|The owner of the contract that can set the URI resolver.|
240
- |`permit2`|`IPermit2`|A permit2 utility.|
241
- |`trustedForwarder`|`address`|A trusted forwarder of transactions to this contract.|
242
-
243
-
244
- ### borrowableAmountFrom
245
-
246
- The amount that can be borrowed from a revnet.
247
-
248
-
249
- ```solidity
250
- function borrowableAmountFrom(
251
- uint256 revnetId,
252
- uint256 collateralCount,
253
- uint256 decimals,
254
- uint256 currency
255
- )
256
- external
257
- view
258
- returns (uint256);
259
- ```
260
- **Parameters**
261
-
262
- |Name|Type|Description|
263
- |----|----|-----------|
264
- |`revnetId`|`uint256`|The ID of the revnet to check for borrowable assets from.|
265
- |`collateralCount`|`uint256`|The amount of collateral used to secure the loan.|
266
- |`decimals`|`uint256`|The decimals the resulting fixed point value will include.|
267
- |`currency`|`uint256`|The currency that the resulting amount should be in terms of.|
268
-
269
- **Returns**
270
-
271
- |Name|Type|Description|
272
- |----|----|-----------|
273
- |`<none>`|`uint256`|borrowableAmount The amount that can be borrowed from the revnet.|
274
-
275
-
276
- ### loanOf
277
-
278
- Get a loan.
279
-
280
- **Note:**
281
- member: The ID of the loan.
282
-
283
-
284
- ```solidity
285
- function loanOf(uint256 loanId) external view override returns (REVLoan memory);
286
- ```
287
-
288
- ### loanSourcesOf
289
-
290
- The sources of each revnet's loan.
291
-
292
- This array only grows -- sources are never removed. The number of distinct sources is practically bounded
293
- by the number of unique (terminal, token) pairs used for borrowing, which is typically small.
294
-
295
- **Note:**
296
- member: revnetId The ID of the revnet issuing the loan.
297
-
298
-
299
- ```solidity
300
- function loanSourcesOf(uint256 revnetId) external view override returns (REVLoanSource[] memory);
301
- ```
302
-
303
- ### determineSourceFeeAmount
304
-
305
- Determines the source fee amount for a loan being paid off a certain amount.
306
-
307
-
308
- ```solidity
309
- function determineSourceFeeAmount(REVLoan memory loan, uint256 amount) public view returns (uint256);
310
- ```
311
- **Parameters**
312
-
313
- |Name|Type|Description|
314
- |----|----|-----------|
315
- |`loan`|`REVLoan`|The loan having its source fee amount determined.|
316
- |`amount`|`uint256`|The amount being paid off.|
317
-
318
- **Returns**
319
-
320
- |Name|Type|Description|
321
- |----|----|-----------|
322
- |`<none>`|`uint256`|sourceFeeAmount The source fee amount for the loan.|
323
-
324
-
325
- ### tokenURI
326
-
327
- Returns the URI where the ERC-721 standard JSON of a loan is hosted.
328
-
329
-
330
- ```solidity
331
- function tokenURI(uint256 loanId) public view override returns (string memory);
332
- ```
333
- **Parameters**
334
-
335
- |Name|Type|Description|
336
- |----|----|-----------|
337
- |`loanId`|`uint256`|The ID of the loan to get a URI of.|
338
-
339
- **Returns**
340
-
341
- |Name|Type|Description|
342
- |----|----|-----------|
343
- |`<none>`|`string`|The token URI to use for the provided `loanId`.|
344
-
345
-
346
- ### revnetIdOfLoanWith
347
-
348
- The revnet ID for the loan with the provided loan ID.
349
-
350
-
351
- ```solidity
352
- function revnetIdOfLoanWith(uint256 loanId) public pure override returns (uint256);
353
- ```
354
- **Parameters**
355
-
356
- |Name|Type|Description|
357
- |----|----|-----------|
358
- |`loanId`|`uint256`|The loan ID of the loan to get the revnet ID of.|
359
-
360
- **Returns**
361
-
362
- |Name|Type|Description|
363
- |----|----|-----------|
364
- |`<none>`|`uint256`|The ID of the revnet.|
365
-
366
-
367
- ### _balanceOf
368
-
369
- Checks this contract's balance of a specific token.
370
-
371
-
372
- ```solidity
373
- function _balanceOf(address token) internal view returns (uint256);
374
- ```
375
- **Parameters**
376
-
377
- |Name|Type|Description|
378
- |----|----|-----------|
379
- |`token`|`address`|The address of the token to get this contract's balance of.|
380
-
381
- **Returns**
382
-
383
- |Name|Type|Description|
384
- |----|----|-----------|
385
- |`<none>`|`uint256`|This contract's balance.|
386
-
387
-
388
- ### _borrowableAmountFrom
389
-
390
- This function reads live surplus from the revnet's terminals. A potential concern is flash loan
391
- manipulation: an attacker could temporarily inflate surplus via `addToBalanceOf` or `pay`, borrow at the
392
- inflated rate, then repay the flash loan. However, this attack is economically irrational:
393
- - `addToBalanceOf` permanently donates funds to the project (no recovery mechanism). The attacker's extra
394
- borrowable amount equals `donation * (collateralCount / totalSupply)`, which is always less than the
395
- donation since `collateralCount < totalSupply`. The attacker loses more than they gain.
396
- - `pay` increases both surplus AND totalSupply (via newly minted tokens), so the net effect on the
397
- borrowable-amount-per-token ratio is neutral — the increased surplus is offset by supply dilution.
398
- - With non-zero `cashOutTaxRate`, the bonding curve is concave, making the attack even less profitable.
399
- - Refinancing during inflated surplus (`reallocateCollateralFromLoan`) does not help either: the freed
400
- collateral can only borrow a fraction of the donated amount, keeping the attack net-negative.
401
- In summary, any attempt to inflate surplus to increase borrowing power costs the attacker more than it yields,
402
- because the bonding curve ensures no individual can extract more than their proportional share of surplus.
403
-
404
- The amount that can be borrowed from a revnet given a certain amount of collateral.
405
-
406
- The system intentionally allows up to 100% LTV (loan-to-value) by design. The borrowable amount equals
407
- what the collateral tokens would receive if cashed out, computed via the bonding curve formula in
408
- `JBCashOuts.cashOutFrom`. The `cashOutTaxRate` configured for the current stage serves as an implicit margin
409
- buffer: a non-zero tax rate reduces the cash-out value below the pro-rata share of surplus, creating an
410
- effective collateralization margin. For example, a 20% `cashOutTaxRate` means borrowers can only extract ~80%
411
- of their pro-rata surplus, providing a ~20% buffer against collateral depreciation before liquidation.
412
- A `cashOutTaxRate` of 0 means the full pro-rata amount is borrowable (true 100% LTV with no margin).
413
-
414
-
415
- ```solidity
416
- function _borrowableAmountFrom(
417
- uint256 revnetId,
418
- uint256 collateralCount,
419
- uint256 decimals,
420
- uint256 currency,
421
- IJBTerminal[] memory terminals
422
- )
423
- internal
424
- view
425
- returns (uint256);
426
- ```
427
- **Parameters**
428
-
429
- |Name|Type|Description|
430
- |----|----|-----------|
431
- |`revnetId`|`uint256`|The ID of the revnet to check for borrowable assets from.|
432
- |`collateralCount`|`uint256`|The amount of collateral that the loan will be collateralized with.|
433
- |`decimals`|`uint256`|The decimals the resulting fixed point value will include.|
434
- |`currency`|`uint256`|The currency that the resulting amount should be in terms of.|
435
- |`terminals`|`IJBTerminal[]`|The terminals that the funds are being borrowed from.|
436
-
437
- **Returns**
438
-
439
- |Name|Type|Description|
440
- |----|----|-----------|
441
- |`<none>`|`uint256`|borrowableAmount The amount that can be borrowed from the revnet.|
442
-
443
-
444
- ### _borrowAmountFrom
445
-
446
- The amount of the loan that should be borrowed for the given collateral amount.
447
-
448
-
449
- ```solidity
450
- function _borrowAmountFrom(
451
- REVLoan storage loan,
452
- uint256 revnetId,
453
- uint256 collateralCount
454
- )
455
- internal
456
- view
457
- returns (uint256);
458
- ```
459
- **Parameters**
460
-
461
- |Name|Type|Description|
462
- |----|----|-----------|
463
- |`loan`|`REVLoan`|The loan having its borrow amount determined.|
464
- |`revnetId`|`uint256`|The ID of the revnet to check for borrowable assets from.|
465
- |`collateralCount`|`uint256`|The amount of collateral that the loan will be collateralized with.|
466
-
467
- **Returns**
468
-
469
- |Name|Type|Description|
470
- |----|----|-----------|
471
- |`<none>`|`uint256`|borrowAmount The amount of the loan that should be borrowed.|
472
-
473
-
474
- ### _contextSuffixLength
475
-
476
- `ERC-2771` specifies the context as being a single address (20 bytes).
477
-
478
-
479
- ```solidity
480
- function _contextSuffixLength() internal view override(ERC2771Context, Context) returns (uint256);
481
- ```
482
-
483
- ### _determineSourceFeeAmount
484
-
485
- Determines the source fee amount for a loan being paid off a certain amount.
486
-
487
-
488
- ```solidity
489
- function _determineSourceFeeAmount(REVLoan memory loan, uint256 amount) internal view returns (uint256);
490
- ```
491
- **Parameters**
492
-
493
- |Name|Type|Description|
494
- |----|----|-----------|
495
- |`loan`|`REVLoan`|The loan having its source fee amount determined.|
496
- |`amount`|`uint256`|The amount being paid off.|
497
-
498
- **Returns**
499
-
500
- |Name|Type|Description|
501
- |----|----|-----------|
502
- |`<none>`|`uint256`|The source fee amount for the loan.|
503
-
504
-
505
- ### _generateLoanId
506
-
507
- Generate a ID for a loan given a revnet ID and a loan number within that revnet.
508
-
509
-
510
- ```solidity
511
- function _generateLoanId(uint256 revnetId, uint256 loanNumber) internal pure returns (uint256);
512
- ```
513
- **Parameters**
514
-
515
- |Name|Type|Description|
516
- |----|----|-----------|
517
- |`revnetId`|`uint256`|The ID of the revnet to generate a loan ID for.|
518
- |`loanNumber`|`uint256`|The loan number of the loan within the revnet.|
519
-
520
- **Returns**
521
-
522
- |Name|Type|Description|
523
- |----|----|-----------|
524
- |`<none>`|`uint256`|The token ID of the 721.|
525
-
526
-
527
- ### _msgData
528
-
529
- The calldata. Preferred to use over `msg.data`.
530
-
531
-
532
- ```solidity
533
- function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata);
534
- ```
535
- **Returns**
536
-
537
- |Name|Type|Description|
538
- |----|----|-----------|
539
- |`<none>`|`bytes`|calldata The `msg.data` of this call.|
540
-
541
-
542
- ### _msgSender
543
-
544
- The message's sender. Preferred to use over `msg.sender`.
545
-
546
-
547
- ```solidity
548
- function _msgSender() internal view override(ERC2771Context, Context) returns (address sender);
549
- ```
550
- **Returns**
551
-
552
- |Name|Type|Description|
553
- |----|----|-----------|
554
- |`sender`|`address`|The address which sent this call.|
555
-
556
-
557
- ### _totalBorrowedFrom
558
-
559
- The total borrowed amount from a revnet, aggregated across all loan sources.
560
-
561
- Each source's `totalBorrowedFrom` is stored in the source token's native decimals (e.g. 6 for USDC,
562
- 18 for ETH). Before aggregation, each amount is normalized to the target `decimals` to prevent mixed-decimal
563
- arithmetic errors. For cross-currency sources, the normalized amount is then converted via the price feed.
564
-
565
- Callers should ensure the price feed has sufficient precision for the target `decimals`. Inverse price
566
- feeds may truncate to zero at low decimal counts (e.g. a feed returning 1e21 at 6 decimals inverts to
567
- mulDiv(1e6, 1e6, 1e21) = 0), which would cause a division-by-zero in the price conversion.
568
-
569
-
570
- ```solidity
571
- function _totalBorrowedFrom(
572
- uint256 revnetId,
573
- uint256 decimals,
574
- uint256 currency
575
- )
576
- internal
577
- view
578
- returns (uint256 borrowedAmount);
579
- ```
580
- **Parameters**
581
-
582
- |Name|Type|Description|
583
- |----|----|-----------|
584
- |`revnetId`|`uint256`|The ID of the revnet to check for borrowed assets from.|
585
- |`decimals`|`uint256`|The decimals the resulting fixed point value will include.|
586
- |`currency`|`uint256`|The currency the resulting value will be in terms of.|
587
-
588
- **Returns**
589
-
590
- |Name|Type|Description|
591
- |----|----|-----------|
592
- |`borrowedAmount`|`uint256`|The total amount borrowed.|
593
-
594
-
595
- ### borrowFrom
596
-
597
- Open a loan by borrowing from a revnet.
598
-
599
- Collateral tokens are permanently burned when the loan is created. They are re-minted to the borrower
600
- only upon repayment. If the loan expires (after LOAN_LIQUIDATION_DURATION), the collateral is permanently
601
- lost and cannot be recovered.
602
-
603
-
604
- ```solidity
605
- function borrowFrom(
606
- uint256 revnetId,
607
- REVLoanSource calldata source,
608
- uint256 minBorrowAmount,
609
- uint256 collateralCount,
610
- address payable beneficiary,
611
- uint256 prepaidFeePercent
612
- )
613
- public
614
- override
615
- returns (uint256 loanId, REVLoan memory);
616
- ```
617
- **Parameters**
618
-
619
- |Name|Type|Description|
620
- |----|----|-----------|
621
- |`revnetId`|`uint256`|The ID of the revnet being borrowed from.|
622
- |`source`|`REVLoanSource`|The source of the loan being borrowed.|
623
- |`minBorrowAmount`|`uint256`|The minimum amount being borrowed, denominated in the token of the source's accounting context.|
624
- |`collateralCount`|`uint256`|The amount of tokens to use as collateral for the loan.|
625
- |`beneficiary`|`address payable`|The address that'll receive the borrowed funds and the tokens resulting from fee payments.|
626
- |`prepaidFeePercent`|`uint256`|The fee percent that will be charged upfront from the revnet being borrowed from. Prepaying a fee is cheaper than paying later.|
627
-
628
- **Returns**
629
-
630
- |Name|Type|Description|
631
- |----|----|-----------|
632
- |`loanId`|`uint256`|The ID of the loan created from borrowing.|
633
- |`<none>`|`REVLoan`|loan The loan created from borrowing.|
634
-
635
-
636
- ### liquidateExpiredLoansFrom
637
-
638
- Liquidates loans that have exceeded the 10-year liquidation duration.
639
-
640
- Liquidation permanently destroys the collateral backing expired loans. Since collateral tokens were burned
641
- at deposit time (not held in escrow), there is nothing to return upon liquidation -- the collateral count is
642
- simply removed from tracking. The borrower retains whatever funds they received from the loan, but the
643
- collateral tokens that were burned to secure the loan are permanently lost.
644
-
645
- This is an intentional design choice to keep the protocol simple and to incentivize timely repayment or
646
- refinancing. Borrowers have the full LOAN_LIQUIDATION_DURATION (10 years) to repay their loan and recover
647
- their collateral via re-minting.
648
-
649
- Since some loans may be reallocated or paid off, loans within startingLoanId and startingLoanId + count
650
- may be skipped, so choose these parameters carefully to avoid extra gas usage.
651
-
652
-
653
- ```solidity
654
- function liquidateExpiredLoansFrom(uint256 revnetId, uint256 startingLoanId, uint256 count) external override;
655
- ```
656
- **Parameters**
657
-
658
- |Name|Type|Description|
659
- |----|----|-----------|
660
- |`revnetId`|`uint256`|The ID of the revnet to liquidate loans from.|
661
- |`startingLoanId`|`uint256`|The ID of the loan to start iterating from.|
662
- |`count`|`uint256`|The amount of loans iterate over since the last liquidated loan.|
663
-
664
-
665
- ### reallocateCollateralFromLoan
666
-
667
- Refinances a loan by transferring extra collateral from an existing loan to a new loan.
668
-
669
- Useful if a loan's collateral has gone up in value since the loan was created.
670
-
671
- Refinancing a loan will burn the original and create two new loans.
672
-
673
- This function is intentionally not payable — it only moves existing collateral between loans and does
674
- not accept new funds. Any ETH sent with the call will be rejected by the EVM.
675
-
676
-
677
- ```solidity
678
- function reallocateCollateralFromLoan(
679
- uint256 loanId,
680
- uint256 collateralCountToTransfer,
681
- REVLoanSource calldata source,
682
- uint256 minBorrowAmount,
683
- uint256 collateralCountToAdd,
684
- address payable beneficiary,
685
- uint256 prepaidFeePercent
686
- )
687
- external
688
- override
689
- returns (uint256 reallocatedLoanId, uint256 newLoanId, REVLoan memory reallocatedLoan, REVLoan memory newLoan);
690
- ```
691
- **Parameters**
692
-
693
- |Name|Type|Description|
694
- |----|----|-----------|
695
- |`loanId`|`uint256`|The ID of the loan to reallocate collateral from.|
696
- |`collateralCountToTransfer`|`uint256`|The amount of collateral to transfer from the original loan.|
697
- |`source`|`REVLoanSource`|The source of the loan to create.|
698
- |`minBorrowAmount`|`uint256`|The minimum amount being borrowed, denominated in the token of the source's accounting context.|
699
- |`collateralCountToAdd`|`uint256`|The amount of collateral to add to the loan.|
700
- |`beneficiary`|`address payable`|The address that'll receive the borrowed funds and the tokens resulting from fee payments.|
701
- |`prepaidFeePercent`|`uint256`|The fee percent that will be charged upfront from the revnet being borrowed from.|
702
-
703
- **Returns**
704
-
705
- |Name|Type|Description|
706
- |----|----|-----------|
707
- |`reallocatedLoanId`|`uint256`|The ID of the loan being reallocated.|
708
- |`newLoanId`|`uint256`|The ID of the new loan.|
709
- |`reallocatedLoan`|`REVLoan`|The loan being reallocated.|
710
- |`newLoan`|`REVLoan`|The new loan created from reallocating collateral.|
711
-
712
-
713
- ### repayLoan
714
-
715
- Allows the owner of a loan to pay it back or receive returned collateral no longer necessary to support
716
- the loan.
717
-
718
-
719
- ```solidity
720
- function repayLoan(
721
- uint256 loanId,
722
- uint256 maxRepayBorrowAmount,
723
- uint256 collateralCountToReturn,
724
- address payable beneficiary,
725
- JBSingleAllowance calldata allowance
726
- )
727
- external
728
- payable
729
- override
730
- returns (uint256 paidOffLoanId, REVLoan memory paidOffloan);
731
- ```
732
- **Parameters**
733
-
734
- |Name|Type|Description|
735
- |----|----|-----------|
736
- |`loanId`|`uint256`|The ID of the loan being adjusted.|
737
- |`maxRepayBorrowAmount`|`uint256`|The maximum amount being paid off, denominated in the token of the source's accounting context.|
738
- |`collateralCountToReturn`|`uint256`|The amount of collateral being returned from the loan.|
739
- |`beneficiary`|`address payable`|The address receiving the returned collateral and any tokens resulting from paying fees.|
740
- |`allowance`|`JBSingleAllowance`|An allowance to faciliate permit2 interactions.|
741
-
742
- **Returns**
743
-
744
- |Name|Type|Description|
745
- |----|----|-----------|
746
- |`paidOffLoanId`|`uint256`|The ID of the loan after it's been paid off.|
747
- |`paidOffloan`|`REVLoan`|The loan after it's been paid off.|
748
-
749
-
750
- ### setTokenUriResolver
751
-
752
- Sets the address of the resolver used to retrieve the tokenURI of loans.
753
-
754
-
755
- ```solidity
756
- function setTokenUriResolver(IJBTokenUriResolver resolver) external override onlyOwner;
757
- ```
758
- **Parameters**
759
-
760
- |Name|Type|Description|
761
- |----|----|-----------|
762
- |`resolver`|`IJBTokenUriResolver`|The address of the new resolver.|
763
-
764
-
765
- ### _addCollateralTo
766
-
767
- Adds collateral to a loan by burning the collateral tokens permanently.
768
-
769
- The collateral tokens are burned via the controller, not held in escrow. They are only re-minted if the
770
- loan is repaid. If the loan expires and is liquidated, the burned collateral is permanently lost.
771
-
772
-
773
- ```solidity
774
- function _addCollateralTo(uint256 revnetId, uint256 amount) internal;
775
- ```
776
- **Parameters**
777
-
778
- |Name|Type|Description|
779
- |----|----|-----------|
780
- |`revnetId`|`uint256`|The ID of the revnet the loan is being added in.|
781
- |`amount`|`uint256`|The new amount of collateral being added to the loan.|
782
-
783
-
784
- ### _addTo
785
-
786
- Add a new amount to the loan that is greater than the previous amount.
787
-
788
-
789
- ```solidity
790
- function _addTo(
791
- REVLoan memory loan,
792
- uint256 revnetId,
793
- uint256 addedBorrowAmount,
794
- uint256 sourceFeeAmount,
795
- address payable beneficiary
796
- )
797
- internal;
798
- ```
799
- **Parameters**
800
-
801
- |Name|Type|Description|
802
- |----|----|-----------|
803
- |`loan`|`REVLoan`|The loan being added to.|
804
- |`revnetId`|`uint256`|The ID of the revnet the loan is being added in.|
805
- |`addedBorrowAmount`|`uint256`|The amount being added to the loan, denominated in the token of the source's accounting context.|
806
- |`sourceFeeAmount`|`uint256`|The amount of the fee being taken from the revnet acting as the source of the loan.|
807
- |`beneficiary`|`address payable`|The address receiving the returned collateral and any tokens resulting from paying fees.|
808
-
809
-
810
- ### _adjust
811
-
812
- Allows the owner of a loan to pay it back, add more, or receive returned collateral no longer necessary
813
- to support the loan.
814
-
815
-
816
- ```solidity
817
- function _adjust(
818
- REVLoan storage loan,
819
- uint256 revnetId,
820
- uint256 newBorrowAmount,
821
- uint256 newCollateralCount,
822
- uint256 sourceFeeAmount,
823
- address payable beneficiary
824
- )
825
- internal;
826
- ```
827
- **Parameters**
828
-
829
- |Name|Type|Description|
830
- |----|----|-----------|
831
- |`loan`|`REVLoan`|The loan being adjusted.|
832
- |`revnetId`|`uint256`|The ID of the revnet the loan is being adjusted in.|
833
- |`newBorrowAmount`|`uint256`|The new amount of the loan, denominated in the token of the source's accounting context.|
834
- |`newCollateralCount`|`uint256`|The new amount of collateral backing the loan.|
835
- |`sourceFeeAmount`|`uint256`|The amount of the fee being taken from the revnet acting as the source of the loan.|
836
- |`beneficiary`|`address payable`|The address receiving the returned collateral and any tokens resulting from paying fees.|
837
-
838
-
839
- ### _acceptFundsFor
840
-
841
- Accepts an incoming token.
842
-
843
-
844
- ```solidity
845
- function _acceptFundsFor(
846
- address token,
847
- uint256 amount,
848
- JBSingleAllowance memory allowance
849
- )
850
- internal
851
- returns (uint256);
852
- ```
853
- **Parameters**
854
-
855
- |Name|Type|Description|
856
- |----|----|-----------|
857
- |`token`|`address`|The token being accepted.|
858
- |`amount`|`uint256`|The number of tokens being accepted.|
859
- |`allowance`|`JBSingleAllowance`|The permit2 context.|
860
-
861
- **Returns**
862
-
863
- |Name|Type|Description|
864
- |----|----|-----------|
865
- |`<none>`|`uint256`|amount The number of tokens which have been accepted.|
866
-
867
-
868
- ### _beforeTransferTo
869
-
870
- Logic to be triggered before transferring tokens from this contract.
871
-
872
-
873
- ```solidity
874
- function _beforeTransferTo(address to, address token, uint256 amount) internal returns (uint256);
875
- ```
876
- **Parameters**
877
-
878
- |Name|Type|Description|
879
- |----|----|-----------|
880
- |`to`|`address`|The address the transfer is going to.|
881
- |`token`|`address`|The token being transferred.|
882
- |`amount`|`uint256`|The number of tokens being transferred, as a fixed point number with the same number of decimals as the token specifies.|
883
-
884
- **Returns**
885
-
886
- |Name|Type|Description|
887
- |----|----|-----------|
888
- |`<none>`|`uint256`|payValue The value to attach to the transaction being sent.|
889
-
890
-
891
- ### _repayLoan
892
-
893
- Pays down a loan.
894
-
895
-
896
- ```solidity
897
- function _repayLoan(
898
- uint256 loanId,
899
- REVLoan storage loan,
900
- uint256 revnetId,
901
- uint256 repayBorrowAmount,
902
- uint256 sourceFeeAmount,
903
- uint256 collateralCountToReturn,
904
- address payable beneficiary
905
- )
906
- internal
907
- returns (uint256, REVLoan memory);
908
- ```
909
- **Parameters**
910
-
911
- |Name|Type|Description|
912
- |----|----|-----------|
913
- |`loanId`|`uint256`|The ID of the loan being paid down.|
914
- |`loan`|`REVLoan`|The loan being paid down.|
915
- |`revnetId`|`uint256`||
916
- |`repayBorrowAmount`|`uint256`|The amount being paid down from the loan, denominated in the token of the source's accounting context.|
917
- |`sourceFeeAmount`|`uint256`|The amount of the fee being taken from the revnet acting as the source of the loan.|
918
- |`collateralCountToReturn`|`uint256`|The amount of collateral being returned that the loan no longer requires.|
919
- |`beneficiary`|`address payable`|The address receiving the returned collateral and any tokens resulting from paying fees.|
920
-
921
-
922
- ### _reallocateCollateralFromLoan
923
-
924
- Reallocates collateral from a loan by making a new loan based on the original, with reduced collateral.
925
-
926
-
927
- ```solidity
928
- function _reallocateCollateralFromLoan(
929
- uint256 loanId,
930
- uint256 revnetId,
931
- uint256 collateralCountToRemove
932
- )
933
- internal
934
- returns (uint256 reallocatedLoanId, REVLoan storage reallocatedLoan);
935
- ```
936
- **Parameters**
937
-
938
- |Name|Type|Description|
939
- |----|----|-----------|
940
- |`loanId`|`uint256`|The ID of the loan to reallocate collateral from.|
941
- |`revnetId`|`uint256`|The ID of the revnet the loan is from.|
942
- |`collateralCountToRemove`|`uint256`|The amount of collateral to remove from the loan.|
943
-
944
- **Returns**
945
-
946
- |Name|Type|Description|
947
- |----|----|-----------|
948
- |`reallocatedLoanId`|`uint256`|The ID of the loan.|
949
- |`reallocatedLoan`|`REVLoan`|The reallocated loan.|
950
-
951
-
952
- ### _removeFrom
953
-
954
- Pays off a loan.
955
-
956
-
957
- ```solidity
958
- function _removeFrom(REVLoan memory loan, uint256 revnetId, uint256 repaidBorrowAmount) internal;
959
- ```
960
- **Parameters**
961
-
962
- |Name|Type|Description|
963
- |----|----|-----------|
964
- |`loan`|`REVLoan`|The loan being paid off.|
965
- |`revnetId`|`uint256`|The ID of the revnet the loan is being paid off in.|
966
- |`repaidBorrowAmount`|`uint256`|The amount being paid off, denominated in the token of the source's accounting context.|
967
-
968
-
969
- ### _returnCollateralFrom
970
-
971
- Returns collateral from a loan.
972
-
973
-
974
- ```solidity
975
- function _returnCollateralFrom(uint256 revnetId, uint256 collateralCount, address payable beneficiary) internal;
976
- ```
977
- **Parameters**
978
-
979
- |Name|Type|Description|
980
- |----|----|-----------|
981
- |`revnetId`|`uint256`|The ID of the revnet the loan is being returned in.|
982
- |`collateralCount`|`uint256`|The amount of collateral being returned from the loan.|
983
- |`beneficiary`|`address payable`|The address receiving the returned collateral.|
984
-
985
-
986
- ### _transferFrom
987
-
988
- Transfers tokens.
989
-
990
-
991
- ```solidity
992
- function _transferFrom(address from, address payable to, address token, uint256 amount) internal virtual;
993
- ```
994
- **Parameters**
995
-
996
- |Name|Type|Description|
997
- |----|----|-----------|
998
- |`from`|`address`|The address to transfer tokens from.|
999
- |`to`|`address payable`|The address to transfer tokens to.|
1000
- |`token`|`address`|The address of the token being transfered.|
1001
- |`amount`|`uint256`|The amount of tokens to transfer, as a fixed point number with the same number of decimals as the token.|
1002
-
1003
-
1004
- ### fallback
1005
-
1006
-
1007
- ```solidity
1008
- fallback() external payable;
1009
- ```
1010
-
1011
- ### receive
1012
-
1013
-
1014
- ```solidity
1015
- receive() external payable;
1016
- ```
1017
-
1018
- ## Errors
1019
- ### REVLoans_CollateralExceedsLoan
1020
-
1021
- ```solidity
1022
- error REVLoans_CollateralExceedsLoan(uint256 collateralToReturn, uint256 loanCollateral);
1023
- ```
1024
-
1025
- ### REVLoans_InvalidPrepaidFeePercent
1026
-
1027
- ```solidity
1028
- error REVLoans_InvalidPrepaidFeePercent(uint256 prepaidFeePercent, uint256 min, uint256 max);
1029
- ```
1030
-
1031
- ### REVLoans_NotEnoughCollateral
1032
-
1033
- ```solidity
1034
- error REVLoans_NotEnoughCollateral();
1035
- ```
1036
-
1037
- ### REVLoans_OverflowAlert
1038
-
1039
- ```solidity
1040
- error REVLoans_OverflowAlert(uint256 value, uint256 limit);
1041
- ```
1042
-
1043
- ### REVLoans_OverMaxRepayBorrowAmount
1044
-
1045
- ```solidity
1046
- error REVLoans_OverMaxRepayBorrowAmount(uint256 maxRepayBorrowAmount, uint256 repayBorrowAmount);
1047
- ```
1048
-
1049
- ### REVLoans_PermitAllowanceNotEnough
1050
-
1051
- ```solidity
1052
- error REVLoans_PermitAllowanceNotEnough(uint256 allowanceAmount, uint256 requiredAmount);
1053
- ```
1054
-
1055
- ### REVLoans_NewBorrowAmountGreaterThanLoanAmount
1056
-
1057
- ```solidity
1058
- error REVLoans_NewBorrowAmountGreaterThanLoanAmount(uint256 newBorrowAmount, uint256 loanAmount);
1059
- ```
1060
-
1061
- ### REVLoans_NoMsgValueAllowed
1062
-
1063
- ```solidity
1064
- error REVLoans_NoMsgValueAllowed();
1065
- ```
1066
-
1067
- ### REVLoans_NothingToRepay
1068
-
1069
- ```solidity
1070
- error REVLoans_NothingToRepay();
1071
- ```
1072
-
1073
- ### REVLoans_LoanExpired
1074
-
1075
- ```solidity
1076
- error REVLoans_LoanExpired(uint256 timeSinceLoanCreated, uint256 loanLiquidationDuration);
1077
- ```
1078
-
1079
- ### REVLoans_ReallocatingMoreCollateralThanBorrowedAmountAllows
1080
-
1081
- ```solidity
1082
- error REVLoans_ReallocatingMoreCollateralThanBorrowedAmountAllows(uint256 newBorrowAmount, uint256 loanAmount);
1083
- ```
1084
-
1085
- ### REVLoans_SourceMismatch
1086
-
1087
- ```solidity
1088
- error REVLoans_SourceMismatch();
1089
- ```
1090
-
1091
- ### REVLoans_Unauthorized
1092
-
1093
- ```solidity
1094
- error REVLoans_Unauthorized(address caller, address owner);
1095
- ```
1096
-
1097
- ### REVLoans_UnderMinBorrowAmount
1098
-
1099
- ```solidity
1100
- error REVLoans_UnderMinBorrowAmount(uint256 minBorrowAmount, uint256 borrowAmount);
1101
- ```
1102
-
1103
- ### REVLoans_ZeroCollateralLoanIsInvalid
1104
-
1105
- ```solidity
1106
- error REVLoans_ZeroCollateralLoanIsInvalid();
1107
- ```
1108
-