@rev-net/core-v6 0.0.7 → 0.0.8
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/foundry.toml +1 -1
- package/package.json +9 -6
- package/src/REVDeployer.sol +102 -68
- package/src/REVLoans.sol +161 -161
- package/src/interfaces/IREVDeployer.sol +110 -72
- package/src/interfaces/IREVLoans.sol +116 -76
- package/test/mock/MockBuybackDataHook.sol +8 -4
- package/test/mock/MockBuybackDataHookMintPath.sol +7 -3
package/foundry.toml
CHANGED
package/package.json
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rev-net/core-v6",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/rev-net/revnet-core-v6"
|
|
8
8
|
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=20.0.0"
|
|
11
|
+
},
|
|
9
12
|
"scripts": {
|
|
10
13
|
"postinstall": "find node_modules -name '*.sol' -type f | xargs grep -l 'pragma solidity 0.8.23;' 2>/dev/null | xargs sed -i '' 's/pragma solidity 0.8.23;/pragma solidity 0.8.26;/g' 2>/dev/null || true",
|
|
11
14
|
"test": "forge test",
|
|
12
|
-
"coverage
|
|
15
|
+
"coverage": "forge coverage --match-path \"./src/*.sol\" --report lcov --report summary",
|
|
13
16
|
"deploy:mainnets": "source ./.env && export START_TIME=$(date +%s) && npx sphinx propose ./script/Deploy.s.sol --networks mainnets",
|
|
14
17
|
"deploy:mainnets:1_1": "source ./.env && npx sphinx propose ./script/Deploy1_1.s.sol --networks mainnets",
|
|
15
18
|
"deploy:testnets": "source ./.env && export START_TIME=$(date +%s) && npx sphinx propose ./script/Deploy.s.sol --networks testnets",
|
|
@@ -19,14 +22,14 @@
|
|
|
19
22
|
"dependencies": {
|
|
20
23
|
"@bananapus/721-hook-v6": "^0.0.9",
|
|
21
24
|
"@bananapus/buyback-hook-v6": "^0.0.7",
|
|
22
|
-
"@bananapus/core-v6": "^0.0.
|
|
23
|
-
"@bananapus/permission-ids-v6": "^0.0.
|
|
24
|
-
"@bananapus/suckers-v6": "^0.0.
|
|
25
|
+
"@bananapus/core-v6": "^0.0.10",
|
|
26
|
+
"@bananapus/permission-ids-v6": "^0.0.5",
|
|
27
|
+
"@bananapus/suckers-v6": "^0.0.7",
|
|
25
28
|
"@bananapus/router-terminal-v6": "^0.0.6",
|
|
26
29
|
"@croptop/core-v6": "^0.0.6",
|
|
27
30
|
"@openzeppelin/contracts": "^5.2.0"
|
|
28
31
|
},
|
|
29
32
|
"devDependencies": {
|
|
30
|
-
"@sphinx-labs/plugins": "^0.33.
|
|
33
|
+
"@sphinx-labs/plugins": "^0.33.2"
|
|
31
34
|
}
|
|
32
35
|
}
|
package/src/REVDeployer.sol
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity 0.8.26;
|
|
3
3
|
|
|
4
|
+
import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
|
|
4
5
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
6
|
+
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
5
7
|
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
|
6
8
|
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
|
|
7
|
-
import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
|
|
8
|
-
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
9
9
|
import {mulDiv} from "@prb/math/src/Common.sol";
|
|
10
10
|
import {IJB721TiersHook} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHook.sol";
|
|
11
11
|
import {IJB721TiersHookDeployer} from "@bananapus/721-hook-v6/src/interfaces/IJB721TiersHookDeployer.sol";
|
|
12
12
|
import {IJBBuybackHook} from "@bananapus/buyback-hook-v6/src/interfaces/IJBBuybackHook.sol";
|
|
13
|
+
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
|
|
14
|
+
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
|
|
15
|
+
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
13
16
|
import {IJBCashOutHook} from "@bananapus/core-v6/src/interfaces/IJBCashOutHook.sol";
|
|
14
17
|
import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
15
18
|
import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
@@ -26,19 +29,19 @@ import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
|
26
29
|
import {JBSplitGroupIds} from "@bananapus/core-v6/src/libraries/JBSplitGroupIds.sol";
|
|
27
30
|
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
28
31
|
import {JBAfterCashOutRecordedContext} from "@bananapus/core-v6/src/structs/JBAfterCashOutRecordedContext.sol";
|
|
29
|
-
import {JBBeforePayRecordedContext} from "@bananapus/core-v6/src/structs/JBBeforePayRecordedContext.sol";
|
|
30
32
|
import {JBBeforeCashOutRecordedContext} from "@bananapus/core-v6/src/structs/JBBeforeCashOutRecordedContext.sol";
|
|
33
|
+
import {JBBeforePayRecordedContext} from "@bananapus/core-v6/src/structs/JBBeforePayRecordedContext.sol";
|
|
34
|
+
import {JBCashOutHookSpecification} from "@bananapus/core-v6/src/structs/JBCashOutHookSpecification.sol";
|
|
31
35
|
import {JBCurrencyAmount} from "@bananapus/core-v6/src/structs/JBCurrencyAmount.sol";
|
|
32
36
|
import {JBFundAccessLimitGroup} from "@bananapus/core-v6/src/structs/JBFundAccessLimitGroup.sol";
|
|
33
|
-
import {JBPermissionsData} from "@bananapus/core-v6/src/structs/JBPermissionsData.sol";
|
|
34
37
|
import {JBPayHookSpecification} from "@bananapus/core-v6/src/structs/JBPayHookSpecification.sol";
|
|
38
|
+
import {JBPermissionsData} from "@bananapus/core-v6/src/structs/JBPermissionsData.sol";
|
|
35
39
|
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
36
40
|
import {JBRulesetConfig} from "@bananapus/core-v6/src/structs/JBRulesetConfig.sol";
|
|
37
41
|
import {JBRulesetMetadata} from "@bananapus/core-v6/src/structs/JBRulesetMetadata.sol";
|
|
38
42
|
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
39
43
|
import {JBSplitGroup} from "@bananapus/core-v6/src/structs/JBSplitGroup.sol";
|
|
40
44
|
import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.sol";
|
|
41
|
-
import {JBCashOutHookSpecification} from "@bananapus/core-v6/src/structs/JBCashOutHookSpecification.sol";
|
|
42
45
|
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
43
46
|
import {IJBSuckerRegistry} from "@bananapus/suckers-v6/src/interfaces/IJBSuckerRegistry.sol";
|
|
44
47
|
import {CTPublisher} from "@croptop/core-v6/src/CTPublisher.sol";
|
|
@@ -67,11 +70,11 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
67
70
|
error REVDeployer_CashOutsCantBeTurnedOffCompletely(uint256 cashOutTaxRate, uint256 maxCashOutTaxRate);
|
|
68
71
|
error REVDeployer_MustHaveSplits();
|
|
69
72
|
error REVDeployer_NothingToAutoIssue();
|
|
73
|
+
error REVDeployer_NothingToBurn();
|
|
70
74
|
error REVDeployer_RulesetDoesNotAllowDeployingSuckers();
|
|
71
75
|
error REVDeployer_StageNotStarted(uint256 stageId);
|
|
72
76
|
error REVDeployer_StagesRequired();
|
|
73
77
|
error REVDeployer_StageTimesMustIncrease();
|
|
74
|
-
error REVDeployer_NothingToBurn();
|
|
75
78
|
error REVDeployer_Unauthorized(uint256 revnetId, address caller);
|
|
76
79
|
|
|
77
80
|
//*********************************************************************//
|
|
@@ -95,6 +98,10 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
95
98
|
/// @dev 10_000 = 1%. This is the standard fee tier for most project token pairs.
|
|
96
99
|
uint24 public constant DEFAULT_BUYBACK_POOL_FEE = 10_000;
|
|
97
100
|
|
|
101
|
+
/// @notice The default tick spacing used when auto-configuring buyback pools.
|
|
102
|
+
/// @dev 60 is the standard tick spacing for the 1% fee tier.
|
|
103
|
+
int24 public constant DEFAULT_BUYBACK_TICK_SPACING = 60;
|
|
104
|
+
|
|
98
105
|
/// @notice The default TWAP window used when auto-configuring buyback pools.
|
|
99
106
|
/// @dev 2 days provides robust manipulation resistance.
|
|
100
107
|
uint32 public constant DEFAULT_BUYBACK_TWAP_WINDOW = 2 days;
|
|
@@ -224,49 +231,6 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
224
231
|
// ------------------------- external views -------------------------- //
|
|
225
232
|
//*********************************************************************//
|
|
226
233
|
|
|
227
|
-
/// @notice Before a revnet processes an incoming payment, determine the weight and pay hooks to use.
|
|
228
|
-
/// @dev This function is part of `IJBRulesetDataHook`, and gets called before the revnet processes a payment.
|
|
229
|
-
/// @param context Standard Juicebox payment context. See `JBBeforePayRecordedContext`.
|
|
230
|
-
/// @return weight The weight which revnet tokens are minted relative to. This can be used to customize how many
|
|
231
|
-
/// tokens get minted by a payment.
|
|
232
|
-
/// @return hookSpecifications Amounts (out of what's being paid in) to be sent to pay hooks instead of being paid
|
|
233
|
-
/// into the revnet. Useful for automatically routing funds from a treasury as payments come in.
|
|
234
|
-
function beforePayRecordedWith(JBBeforePayRecordedContext calldata context)
|
|
235
|
-
external
|
|
236
|
-
view
|
|
237
|
-
override
|
|
238
|
-
returns (uint256 weight, JBPayHookSpecification[] memory hookSpecifications)
|
|
239
|
-
{
|
|
240
|
-
// Keep a reference to the specifications provided by the buyback hook.
|
|
241
|
-
JBPayHookSpecification[] memory buybackHookSpecifications;
|
|
242
|
-
|
|
243
|
-
// Read the weight and specifications from the buyback hook.
|
|
244
|
-
(weight, buybackHookSpecifications) = BUYBACK_HOOK.beforePayRecordedWith(context);
|
|
245
|
-
|
|
246
|
-
// Keep a reference to the revnet's tiered ERC-721 hook.
|
|
247
|
-
IJB721TiersHook tiered721Hook = tiered721HookOf[context.projectId];
|
|
248
|
-
|
|
249
|
-
// Is there a tiered ERC-721 hook?
|
|
250
|
-
bool usesTiered721Hook = address(tiered721Hook) != address(0);
|
|
251
|
-
|
|
252
|
-
// Did the buyback hook return any specifications? (It won't when direct minting is cheaper than swapping.)
|
|
253
|
-
bool usesBuybackHook = buybackHookSpecifications.length > 0;
|
|
254
|
-
|
|
255
|
-
// Initialize the returned specification array with only the hooks that are present.
|
|
256
|
-
hookSpecifications = new JBPayHookSpecification[]((usesTiered721Hook ? 1 : 0) + (usesBuybackHook ? 1 : 0));
|
|
257
|
-
|
|
258
|
-
// If we have a tiered ERC-721 hook, add it to the array.
|
|
259
|
-
if (usesTiered721Hook) {
|
|
260
|
-
hookSpecifications[0] =
|
|
261
|
-
JBPayHookSpecification({hook: IJBPayHook(address(tiered721Hook)), amount: 0, metadata: bytes("")});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Add the buyback hook specification if present.
|
|
265
|
-
if (usesBuybackHook) {
|
|
266
|
-
hookSpecifications[usesTiered721Hook ? 1 : 0] = buybackHookSpecifications[0];
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
234
|
/// @notice Determine how a cash out from a revnet should be processed.
|
|
271
235
|
/// @dev This function is part of `IJBRulesetDataHook`, and gets called before the revnet processes a cash out.
|
|
272
236
|
/// @dev If a sucker is cashing out, no taxes or fees are imposed.
|
|
@@ -339,6 +303,49 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
339
303
|
return (context.cashOutTaxRate, nonFeeCashOutCount, context.totalSupply, hookSpecifications);
|
|
340
304
|
}
|
|
341
305
|
|
|
306
|
+
/// @notice Before a revnet processes an incoming payment, determine the weight and pay hooks to use.
|
|
307
|
+
/// @dev This function is part of `IJBRulesetDataHook`, and gets called before the revnet processes a payment.
|
|
308
|
+
/// @param context Standard Juicebox payment context. See `JBBeforePayRecordedContext`.
|
|
309
|
+
/// @return weight The weight which revnet tokens are minted relative to. This can be used to customize how many
|
|
310
|
+
/// tokens get minted by a payment.
|
|
311
|
+
/// @return hookSpecifications Amounts (out of what's being paid in) to be sent to pay hooks instead of being paid
|
|
312
|
+
/// into the revnet. Useful for automatically routing funds from a treasury as payments come in.
|
|
313
|
+
function beforePayRecordedWith(JBBeforePayRecordedContext calldata context)
|
|
314
|
+
external
|
|
315
|
+
view
|
|
316
|
+
override
|
|
317
|
+
returns (uint256 weight, JBPayHookSpecification[] memory hookSpecifications)
|
|
318
|
+
{
|
|
319
|
+
// Keep a reference to the specifications provided by the buyback hook.
|
|
320
|
+
JBPayHookSpecification[] memory buybackHookSpecifications;
|
|
321
|
+
|
|
322
|
+
// Read the weight and specifications from the buyback hook.
|
|
323
|
+
(weight, buybackHookSpecifications) = BUYBACK_HOOK.beforePayRecordedWith(context);
|
|
324
|
+
|
|
325
|
+
// Keep a reference to the revnet's tiered ERC-721 hook.
|
|
326
|
+
IJB721TiersHook tiered721Hook = tiered721HookOf[context.projectId];
|
|
327
|
+
|
|
328
|
+
// Is there a tiered ERC-721 hook?
|
|
329
|
+
bool usesTiered721Hook = address(tiered721Hook) != address(0);
|
|
330
|
+
|
|
331
|
+
// Did the buyback hook return any specifications? (It won't when direct minting is cheaper than swapping.)
|
|
332
|
+
bool usesBuybackHook = buybackHookSpecifications.length > 0;
|
|
333
|
+
|
|
334
|
+
// Initialize the returned specification array with only the hooks that are present.
|
|
335
|
+
hookSpecifications = new JBPayHookSpecification[]((usesTiered721Hook ? 1 : 0) + (usesBuybackHook ? 1 : 0));
|
|
336
|
+
|
|
337
|
+
// If we have a tiered ERC-721 hook, add it to the array.
|
|
338
|
+
if (usesTiered721Hook) {
|
|
339
|
+
hookSpecifications[0] =
|
|
340
|
+
JBPayHookSpecification({hook: IJBPayHook(address(tiered721Hook)), amount: 0, metadata: bytes("")});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Add the buyback hook specification if present.
|
|
344
|
+
if (usesBuybackHook) {
|
|
345
|
+
hookSpecifications[usesTiered721Hook ? 1 : 0] = buybackHookSpecifications[0];
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
342
349
|
/// @notice A flag indicating whether an address has permission to mint a revnet's tokens on-demand.
|
|
343
350
|
/// @dev Required by the `IJBRulesetDataHook` interface.
|
|
344
351
|
/// @param revnetId The ID of the revnet to check permissions for.
|
|
@@ -459,18 +466,45 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
459
466
|
});
|
|
460
467
|
|
|
461
468
|
// Configure a buyback pool for this terminal token with default fee and TWAP window.
|
|
462
|
-
// slither-disable-next-line
|
|
463
|
-
|
|
464
|
-
.setPoolFor({
|
|
465
|
-
projectId: revnetId,
|
|
466
|
-
fee: DEFAULT_BUYBACK_POOL_FEE,
|
|
467
|
-
twapWindow: DEFAULT_BUYBACK_TWAP_WINDOW,
|
|
468
|
-
terminalToken: accountingContext.token
|
|
469
|
-
});
|
|
469
|
+
// slither-disable-next-line calls-loop
|
|
470
|
+
_trySetBuybackPoolFor(revnetId, accountingContext.token);
|
|
470
471
|
}
|
|
471
472
|
}
|
|
472
473
|
}
|
|
473
474
|
|
|
475
|
+
/// @notice Try to configure a buyback pool for a terminal token. Silently catches failures (e.g., if the Uniswap V4
|
|
476
|
+
/// pool isn't initialized yet).
|
|
477
|
+
/// @param revnetId The ID of the revnet.
|
|
478
|
+
/// @param terminalToken The terminal token to configure a buyback pool for.
|
|
479
|
+
function _trySetBuybackPoolFor(uint256 revnetId, address terminalToken) internal {
|
|
480
|
+
// Normalize the terminal token (use WETH for native) and get the project token.
|
|
481
|
+
address normalizedTerminalToken = terminalToken == JBConstants.NATIVE_TOKEN
|
|
482
|
+
? address(IJBBuybackHook(address(BUYBACK_HOOK)).WETH())
|
|
483
|
+
: terminalToken;
|
|
484
|
+
address projectToken = address(CONTROLLER.TOKENS().tokenOf(revnetId));
|
|
485
|
+
|
|
486
|
+
// Sort currencies numerically for the pool key (lower address = currency0).
|
|
487
|
+
(Currency currency0, Currency currency1) = normalizedTerminalToken < projectToken
|
|
488
|
+
? (Currency.wrap(normalizedTerminalToken), Currency.wrap(projectToken))
|
|
489
|
+
: (Currency.wrap(projectToken), Currency.wrap(normalizedTerminalToken));
|
|
490
|
+
|
|
491
|
+
// Try to set the pool — if the pool isn't initialized in the PoolManager yet, this will revert and be caught.
|
|
492
|
+
try IJBBuybackHook(address(BUYBACK_HOOK))
|
|
493
|
+
.setPoolFor({
|
|
494
|
+
projectId: revnetId,
|
|
495
|
+
poolKey: PoolKey({
|
|
496
|
+
currency0: currency0,
|
|
497
|
+
currency1: currency1,
|
|
498
|
+
fee: DEFAULT_BUYBACK_POOL_FEE,
|
|
499
|
+
tickSpacing: DEFAULT_BUYBACK_TICK_SPACING,
|
|
500
|
+
hooks: IHooks(address(0))
|
|
501
|
+
}),
|
|
502
|
+
twapWindow: DEFAULT_BUYBACK_TWAP_WINDOW,
|
|
503
|
+
terminalToken: terminalToken
|
|
504
|
+
}) {}
|
|
505
|
+
catch {} // Pool may not be initialized yet — that's OK.
|
|
506
|
+
}
|
|
507
|
+
|
|
474
508
|
/// @notice Make a ruleset configuration for a revnet's stage.
|
|
475
509
|
/// @param baseCurrency The base currency of the revnet.
|
|
476
510
|
/// @param stageConfiguration The stage configuration to make a ruleset for.
|
|
@@ -696,6 +730,17 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
696
730
|
return revnetId;
|
|
697
731
|
}
|
|
698
732
|
|
|
733
|
+
/// @notice Burn any of a revnet's tokens held by this contract.
|
|
734
|
+
/// @dev Project tokens can end up here from reserved token distribution when splits don't sum to 100%.
|
|
735
|
+
/// @param revnetId The ID of the revnet whose tokens should be burned.
|
|
736
|
+
function burnHeldTokensOf(uint256 revnetId) external override {
|
|
737
|
+
uint256 balance = CONTROLLER.TOKENS().totalBalanceOf({holder: address(this), projectId: revnetId});
|
|
738
|
+
if (balance == 0) revert REVDeployer_NothingToBurn();
|
|
739
|
+
CONTROLLER.burnTokensOf({holder: address(this), projectId: revnetId, tokenCount: balance, memo: ""});
|
|
740
|
+
// slither-disable-next-line reentrancy-events
|
|
741
|
+
emit BurnHeldTokens(revnetId, balance, _msgSender());
|
|
742
|
+
}
|
|
743
|
+
|
|
699
744
|
/// @notice Deploy new suckers for an existing revnet.
|
|
700
745
|
/// @dev Only the revnet's split operator can deploy new suckers.
|
|
701
746
|
/// @param revnetId The ID of the revnet to deploy suckers for.
|
|
@@ -777,17 +822,6 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IJBRulesetDataHook, IJBCas
|
|
|
777
822
|
return (revnetId, hook);
|
|
778
823
|
}
|
|
779
824
|
|
|
780
|
-
/// @notice Burn any of a revnet's tokens held by this contract.
|
|
781
|
-
/// @dev Project tokens can end up here from reserved token distribution when splits don't sum to 100%.
|
|
782
|
-
/// @param revnetId The ID of the revnet whose tokens should be burned.
|
|
783
|
-
function burnHeldTokensOf(uint256 revnetId) external override {
|
|
784
|
-
uint256 balance = CONTROLLER.TOKENS().totalBalanceOf({holder: address(this), projectId: revnetId});
|
|
785
|
-
if (balance == 0) revert REVDeployer_NothingToBurn();
|
|
786
|
-
CONTROLLER.burnTokensOf({holder: address(this), projectId: revnetId, tokenCount: balance, memo: ""});
|
|
787
|
-
// slither-disable-next-line reentrancy-events
|
|
788
|
-
emit BurnHeldTokens(revnetId, balance, _msgSender());
|
|
789
|
-
}
|
|
790
|
-
|
|
791
825
|
/// @notice Change a revnet's split operator.
|
|
792
826
|
/// @dev Only a revnet's current split operator can set a new split operator.
|
|
793
827
|
/// @param revnetId The ID of the revnet to set the split operator of.
|
package/src/REVLoans.sol
CHANGED
|
@@ -57,14 +57,14 @@ 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 REVLoans_OverflowAlert(uint256 value, uint256 limit);
|
|
62
|
-
error REVLoans_OverMaxRepayBorrowAmount(uint256 maxRepayBorrowAmount, uint256 repayBorrowAmount);
|
|
63
|
-
error REVLoans_PermitAllowanceNotEnough(uint256 allowanceAmount, uint256 requiredAmount);
|
|
60
|
+
error REVLoans_LoanExpired(uint256 timeSinceLoanCreated, uint256 loanLiquidationDuration);
|
|
64
61
|
error REVLoans_NewBorrowAmountGreaterThanLoanAmount(uint256 newBorrowAmount, uint256 loanAmount);
|
|
65
62
|
error REVLoans_NoMsgValueAllowed();
|
|
63
|
+
error REVLoans_NotEnoughCollateral();
|
|
66
64
|
error REVLoans_NothingToRepay();
|
|
67
|
-
error
|
|
65
|
+
error REVLoans_OverMaxRepayBorrowAmount(uint256 maxRepayBorrowAmount, uint256 repayBorrowAmount);
|
|
66
|
+
error REVLoans_OverflowAlert(uint256 value, uint256 limit);
|
|
67
|
+
error REVLoans_PermitAllowanceNotEnough(uint256 allowanceAmount, uint256 requiredAmount);
|
|
68
68
|
error REVLoans_ReallocatingMoreCollateralThanBorrowedAmountAllows(uint256 newBorrowAmount, uint256 loanAmount);
|
|
69
69
|
error REVLoans_SourceMismatch();
|
|
70
70
|
error REVLoans_Unauthorized(address caller, address owner);
|
|
@@ -257,6 +257,13 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
257
257
|
return _determineSourceFeeAmount(loan, amount);
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
/// @notice The revnet ID for the loan with the provided loan ID.
|
|
261
|
+
/// @param loanId The loan ID of the loan to get the revnet ID of.
|
|
262
|
+
/// @return The ID of the revnet.
|
|
263
|
+
function revnetIdOfLoanWith(uint256 loanId) public pure override returns (uint256) {
|
|
264
|
+
return loanId / _ONE_TRILLION;
|
|
265
|
+
}
|
|
266
|
+
|
|
260
267
|
/// @notice Returns the URI where the ERC-721 standard JSON of a loan is hosted.
|
|
261
268
|
/// @param loanId The ID of the loan to get a URI of.
|
|
262
269
|
/// @return The token URI to use for the provided `loanId`.
|
|
@@ -271,13 +278,6 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
271
278
|
return resolver.getUri(loanId);
|
|
272
279
|
}
|
|
273
280
|
|
|
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
281
|
//*********************************************************************//
|
|
282
282
|
// -------------------------- internal views ------------------------- //
|
|
283
283
|
//*********************************************************************//
|
|
@@ -839,6 +839,56 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
839
839
|
// --------------------- internal transactions ----------------------- //
|
|
840
840
|
//*********************************************************************//
|
|
841
841
|
|
|
842
|
+
/// @notice Accepts an incoming token.
|
|
843
|
+
/// @param token The token being accepted.
|
|
844
|
+
/// @param amount The number of tokens being accepted.
|
|
845
|
+
/// @param allowance The permit2 context.
|
|
846
|
+
/// @return amount The number of tokens which have been accepted.
|
|
847
|
+
function _acceptFundsFor(
|
|
848
|
+
address token,
|
|
849
|
+
uint256 amount,
|
|
850
|
+
JBSingleAllowance memory allowance
|
|
851
|
+
)
|
|
852
|
+
internal
|
|
853
|
+
returns (uint256)
|
|
854
|
+
{
|
|
855
|
+
// If the token is the native token, override `amount` with `msg.value`.
|
|
856
|
+
if (token == JBConstants.NATIVE_TOKEN) return msg.value;
|
|
857
|
+
|
|
858
|
+
// If the token is not native, revert if there is a non-zero `msg.value`.
|
|
859
|
+
if (msg.value != 0) revert REVLoans_NoMsgValueAllowed();
|
|
860
|
+
|
|
861
|
+
// Check if the metadata contains permit data.
|
|
862
|
+
if (allowance.amount != 0) {
|
|
863
|
+
// Make sure the permit allowance is enough for this payment. If not we revert early.
|
|
864
|
+
if (allowance.amount < amount) {
|
|
865
|
+
revert REVLoans_PermitAllowanceNotEnough(allowance.amount, amount);
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// Keep a reference to the permit rules.
|
|
869
|
+
IAllowanceTransfer.PermitSingle memory permitSingle = IAllowanceTransfer.PermitSingle({
|
|
870
|
+
details: IAllowanceTransfer.PermitDetails({
|
|
871
|
+
token: token, amount: allowance.amount, expiration: allowance.expiration, nonce: allowance.nonce
|
|
872
|
+
}),
|
|
873
|
+
spender: address(this),
|
|
874
|
+
sigDeadline: allowance.sigDeadline
|
|
875
|
+
});
|
|
876
|
+
|
|
877
|
+
// Set the allowance to `spend` tokens for the user.
|
|
878
|
+
try PERMIT2.permit({owner: _msgSender(), permitSingle: permitSingle, signature: allowance.signature}) {}
|
|
879
|
+
catch (bytes memory) {}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// Get a reference to the balance before receiving tokens.
|
|
883
|
+
uint256 balanceBefore = _balanceOf(token);
|
|
884
|
+
|
|
885
|
+
// Transfer tokens to this terminal from the msg sender.
|
|
886
|
+
_transferFrom({from: _msgSender(), to: payable(address(this)), token: token, amount: amount});
|
|
887
|
+
|
|
888
|
+
// The amount should reflect the change in balance.
|
|
889
|
+
return _balanceOf(token) - balanceBefore;
|
|
890
|
+
}
|
|
891
|
+
|
|
842
892
|
/// @notice Adds collateral to a loan by burning the collateral tokens permanently.
|
|
843
893
|
/// @dev The collateral tokens are burned via the controller, not held in escrow. They are only re-minted if the
|
|
844
894
|
/// loan is repaid. If the loan expires and is liquidated, the burned collateral is permanently lost.
|
|
@@ -1028,67 +1078,118 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
1028
1078
|
}
|
|
1029
1079
|
}
|
|
1030
1080
|
|
|
1031
|
-
/// @notice
|
|
1032
|
-
/// @param
|
|
1033
|
-
/// @param
|
|
1034
|
-
/// @param
|
|
1035
|
-
///
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1081
|
+
/// @notice Logic to be triggered before transferring tokens from this contract.
|
|
1082
|
+
/// @param to The address the transfer is going to.
|
|
1083
|
+
/// @param token The token being transferred.
|
|
1084
|
+
/// @param amount The number of tokens being transferred, as a fixed point number with the same number of decimals
|
|
1085
|
+
/// as the token specifies.
|
|
1086
|
+
/// @return payValue The value to attach to the transaction being sent.
|
|
1087
|
+
function _beforeTransferTo(address to, address token, uint256 amount) internal returns (uint256) {
|
|
1088
|
+
// If the token is the native token, no allowance needed.
|
|
1089
|
+
if (token == JBConstants.NATIVE_TOKEN) return amount;
|
|
1090
|
+
IERC20(token).safeIncreaseAllowance(to, amount);
|
|
1091
|
+
return 0;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
/// @notice Reallocates collateral from a loan by making a new loan based on the original, with reduced collateral.
|
|
1095
|
+
/// @param loanId The ID of the loan to reallocate collateral from.
|
|
1096
|
+
/// @param revnetId The ID of the revnet the loan is from.
|
|
1097
|
+
/// @param collateralCountToRemove The amount of collateral to remove from the loan.
|
|
1098
|
+
/// @return reallocatedLoanId The ID of the loan.
|
|
1099
|
+
/// @return reallocatedLoan The reallocated loan.
|
|
1100
|
+
function _reallocateCollateralFromLoan(
|
|
1101
|
+
uint256 loanId,
|
|
1102
|
+
uint256 revnetId,
|
|
1103
|
+
uint256 collateralCountToRemove
|
|
1040
1104
|
)
|
|
1041
1105
|
internal
|
|
1042
|
-
returns (uint256)
|
|
1106
|
+
returns (uint256 reallocatedLoanId, REVLoan storage reallocatedLoan)
|
|
1043
1107
|
{
|
|
1044
|
-
//
|
|
1045
|
-
|
|
1108
|
+
// Burn the original loan.
|
|
1109
|
+
_burn(loanId);
|
|
1046
1110
|
|
|
1047
|
-
//
|
|
1048
|
-
|
|
1111
|
+
// Keep a reference to loan having its collateral reduced.
|
|
1112
|
+
REVLoan storage loan = _loanOf[loanId];
|
|
1049
1113
|
|
|
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
|
-
}
|
|
1114
|
+
// Make sure there is enough collateral to transfer.
|
|
1115
|
+
if (collateralCountToRemove > loan.collateral) revert REVLoans_NotEnoughCollateral();
|
|
1056
1116
|
|
|
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
|
-
});
|
|
1117
|
+
// Keep a reference to the new collateral amount.
|
|
1118
|
+
uint256 newCollateralCount = loan.collateral - collateralCountToRemove;
|
|
1065
1119
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1120
|
+
// Keep a reference to the new borrow amount.
|
|
1121
|
+
uint256 borrowAmount = _borrowAmountFrom({loan: loan, revnetId: revnetId, collateralCount: newCollateralCount});
|
|
1122
|
+
|
|
1123
|
+
// Make sure the borrow amount is not less than the original loan's amount.
|
|
1124
|
+
if (borrowAmount < loan.amount) {
|
|
1125
|
+
revert REVLoans_ReallocatingMoreCollateralThanBorrowedAmountAllows(borrowAmount, loan.amount);
|
|
1069
1126
|
}
|
|
1070
1127
|
|
|
1071
|
-
// Get a reference to the
|
|
1072
|
-
|
|
1128
|
+
// Get a reference to the replacement loan ID.
|
|
1129
|
+
reallocatedLoanId = _generateLoanId({revnetId: revnetId, loanNumber: ++totalLoansBorrowedFor[revnetId]});
|
|
1073
1130
|
|
|
1074
|
-
//
|
|
1075
|
-
|
|
1131
|
+
// Get a reference to the loan being created.
|
|
1132
|
+
reallocatedLoan = _loanOf[reallocatedLoanId];
|
|
1076
1133
|
|
|
1077
|
-
//
|
|
1078
|
-
|
|
1134
|
+
// Set the reallocated loan's values the same as the original loan.
|
|
1135
|
+
reallocatedLoan.amount = loan.amount;
|
|
1136
|
+
reallocatedLoan.collateral = loan.collateral;
|
|
1137
|
+
reallocatedLoan.createdAt = loan.createdAt;
|
|
1138
|
+
reallocatedLoan.prepaidFeePercent = loan.prepaidFeePercent;
|
|
1139
|
+
reallocatedLoan.prepaidDuration = loan.prepaidDuration;
|
|
1140
|
+
reallocatedLoan.source = loan.source;
|
|
1141
|
+
|
|
1142
|
+
// Reduce the collateral of the reallocated loan.
|
|
1143
|
+
_adjust({
|
|
1144
|
+
loan: reallocatedLoan,
|
|
1145
|
+
revnetId: revnetId,
|
|
1146
|
+
newBorrowAmount: reallocatedLoan.amount, // Don't change the borrow amount.
|
|
1147
|
+
newCollateralCount: newCollateralCount,
|
|
1148
|
+
sourceFeeAmount: 0,
|
|
1149
|
+
beneficiary: payable(_msgSender()) // use the msgSender as the beneficiary, who will have the returned
|
|
1150
|
+
// collateral tokens debited from their balance for the new loan.
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
// Mint the replacement loan.
|
|
1154
|
+
_mint({to: _msgSender(), tokenId: reallocatedLoanId});
|
|
1155
|
+
|
|
1156
|
+
// Clear stale loan data for gas refund.
|
|
1157
|
+
delete _loanOf[loanId];
|
|
1158
|
+
|
|
1159
|
+
emit ReallocateCollateral({
|
|
1160
|
+
loanId: loanId,
|
|
1161
|
+
revnetId: revnetId,
|
|
1162
|
+
reallocatedLoanId: reallocatedLoanId,
|
|
1163
|
+
reallocatedLoan: reallocatedLoan,
|
|
1164
|
+
removedCollateralCount: collateralCountToRemove,
|
|
1165
|
+
caller: _msgSender()
|
|
1166
|
+
});
|
|
1079
1167
|
}
|
|
1080
1168
|
|
|
1081
|
-
/// @notice
|
|
1082
|
-
/// @param
|
|
1083
|
-
/// @param
|
|
1084
|
-
/// @param
|
|
1085
|
-
///
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1169
|
+
/// @notice Pays off a loan.
|
|
1170
|
+
/// @param loan The loan being paid off.
|
|
1171
|
+
/// @param revnetId The ID of the revnet the loan is being paid off in.
|
|
1172
|
+
/// @param repaidBorrowAmount The amount being paid off, denominated in the token of the source's accounting
|
|
1173
|
+
/// context.
|
|
1174
|
+
function _removeFrom(REVLoan memory loan, uint256 revnetId, uint256 repaidBorrowAmount) internal {
|
|
1175
|
+
// Decrement the total amount of a token being loaned out by the revnet from its terminal.
|
|
1176
|
+
totalBorrowedFrom[revnetId][loan.source.terminal][loan.source.token] -= repaidBorrowAmount;
|
|
1177
|
+
|
|
1178
|
+
// Increase the allowance for the beneficiary.
|
|
1179
|
+
uint256 payValue = _beforeTransferTo({
|
|
1180
|
+
to: address(loan.source.terminal), token: loan.source.token, amount: repaidBorrowAmount
|
|
1181
|
+
});
|
|
1182
|
+
|
|
1183
|
+
// Add the loaned amount back to the revnet.
|
|
1184
|
+
// slither-disable-next-line arbitrary-send-eth
|
|
1185
|
+
loan.source.terminal.addToBalanceOf{value: payValue}({
|
|
1186
|
+
projectId: revnetId,
|
|
1187
|
+
token: loan.source.token,
|
|
1188
|
+
amount: repaidBorrowAmount,
|
|
1189
|
+
shouldReturnHeldFees: false,
|
|
1190
|
+
memo: "Paying off loan",
|
|
1191
|
+
metadata: bytes(abi.encodePacked(REV_ID))
|
|
1192
|
+
});
|
|
1092
1193
|
}
|
|
1093
1194
|
|
|
1094
1195
|
/// @notice Pays down a loan.
|
|
@@ -1196,107 +1297,6 @@ contract REVLoans is ERC721, ERC2771Context, Ownable, IREVLoans {
|
|
|
1196
1297
|
}
|
|
1197
1298
|
}
|
|
1198
1299
|
|
|
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
1300
|
/// @notice Returns collateral from a loan.
|
|
1301
1301
|
/// @param revnetId The ID of the revnet the loan is being returned in.
|
|
1302
1302
|
/// @param collateralCount The amount of collateral being returned from the loan.
|
|
@@ -12,21 +12,37 @@ import {JBRulesetConfig} from "@bananapus/core-v6/src/structs/JBRulesetConfig.so
|
|
|
12
12
|
import {JBTerminalConfig} from "@bananapus/core-v6/src/structs/JBTerminalConfig.sol";
|
|
13
13
|
import {IJBSuckerRegistry} from "@bananapus/suckers-v6/src/interfaces/IJBSuckerRegistry.sol";
|
|
14
14
|
import {CTPublisher} from "@croptop/core-v6/src/CTPublisher.sol";
|
|
15
|
-
|
|
16
15
|
import {REVConfig} from "../structs/REVConfig.sol";
|
|
17
16
|
import {REVCroptopAllowedPost} from "../structs/REVCroptopAllowedPost.sol";
|
|
18
17
|
import {REVDeploy721TiersHookConfig} from "../structs/REVDeploy721TiersHookConfig.sol";
|
|
19
18
|
import {REVSuckerDeploymentConfig} from "../structs/REVSuckerDeploymentConfig.sol";
|
|
20
19
|
|
|
20
|
+
/// @notice Deploys and manages revnets -- Juicebox projects with pre-configured tokenomics.
|
|
21
21
|
interface IREVDeployer {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
/// @notice Emitted when tokens are auto-issued for a beneficiary during a stage.
|
|
23
|
+
/// @param revnetId The ID of the revnet.
|
|
24
|
+
/// @param stageId The ID of the stage.
|
|
25
|
+
/// @param beneficiary The address receiving the auto-issued tokens.
|
|
26
|
+
/// @param count The number of tokens auto-issued.
|
|
27
|
+
/// @param caller The address that triggered the auto-issuance.
|
|
28
|
+
event AutoIssue(
|
|
29
|
+
uint256 indexed revnetId, uint256 indexed stageId, address indexed beneficiary, uint256 count, address caller
|
|
28
30
|
);
|
|
29
31
|
|
|
32
|
+
/// @notice Emitted when held tokens are burned from the deployer contract.
|
|
33
|
+
/// @param revnetId The ID of the revnet whose tokens were burned.
|
|
34
|
+
/// @param count The number of tokens burned.
|
|
35
|
+
/// @param caller The address that triggered the burn.
|
|
36
|
+
event BurnHeldTokens(uint256 indexed revnetId, uint256 count, address caller);
|
|
37
|
+
|
|
38
|
+
/// @notice Emitted when a new revnet is deployed.
|
|
39
|
+
/// @param revnetId The ID of the deployed revnet.
|
|
40
|
+
/// @param configuration The revnet's configuration.
|
|
41
|
+
/// @param terminalConfigurations The terminals configured for the revnet.
|
|
42
|
+
/// @param suckerDeploymentConfiguration The sucker deployment configuration.
|
|
43
|
+
/// @param rulesetConfigurations The rulesets configured for the revnet.
|
|
44
|
+
/// @param encodedConfigurationHash The hash of the encoded configuration.
|
|
45
|
+
/// @param caller The address that deployed the revnet.
|
|
30
46
|
event DeployRevnet(
|
|
31
47
|
uint256 indexed revnetId,
|
|
32
48
|
REVConfig configuration,
|
|
@@ -37,42 +53,64 @@ interface IREVDeployer {
|
|
|
37
53
|
address caller
|
|
38
54
|
);
|
|
39
55
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
/// @notice Emitted when suckers are deployed for a revnet.
|
|
57
|
+
/// @param revnetId The ID of the revnet.
|
|
58
|
+
/// @param encodedConfigurationHash The hash of the encoded configuration.
|
|
59
|
+
/// @param suckerDeploymentConfiguration The sucker deployment configuration.
|
|
60
|
+
/// @param caller The address that deployed the suckers.
|
|
61
|
+
event DeploySuckers(
|
|
62
|
+
uint256 indexed revnetId,
|
|
63
|
+
bytes32 encodedConfigurationHash,
|
|
64
|
+
REVSuckerDeploymentConfig suckerDeploymentConfiguration,
|
|
65
|
+
address caller
|
|
44
66
|
);
|
|
45
67
|
|
|
68
|
+
/// @notice Emitted when the split operator of a revnet is replaced.
|
|
69
|
+
/// @param revnetId The ID of the revnet.
|
|
70
|
+
/// @param newSplitOperator The address of the new split operator.
|
|
71
|
+
/// @param caller The address that replaced the split operator.
|
|
72
|
+
event ReplaceSplitOperator(uint256 indexed revnetId, address indexed newSplitOperator, address caller);
|
|
73
|
+
|
|
74
|
+
/// @notice Emitted when the cash out delay is set for a revnet.
|
|
75
|
+
/// @param revnetId The ID of the revnet.
|
|
76
|
+
/// @param cashOutDelay The cash out delay in seconds.
|
|
77
|
+
/// @param caller The address that set the delay.
|
|
78
|
+
event SetCashOutDelay(uint256 indexed revnetId, uint256 cashOutDelay, address caller);
|
|
79
|
+
|
|
80
|
+
/// @notice Emitted when an auto-issuance amount is stored for a beneficiary during a stage.
|
|
81
|
+
/// @param revnetId The ID of the revnet.
|
|
82
|
+
/// @param stageId The ID of the stage.
|
|
83
|
+
/// @param beneficiary The address the tokens will be issued to.
|
|
84
|
+
/// @param count The number of tokens stored for auto-issuance.
|
|
85
|
+
/// @param caller The address that stored the amount.
|
|
46
86
|
event StoreAutoIssuanceAmount(
|
|
47
87
|
uint256 indexed revnetId, uint256 indexed stageId, address indexed beneficiary, uint256 count, address caller
|
|
48
88
|
);
|
|
49
89
|
|
|
50
|
-
|
|
90
|
+
/// @notice The number of revnet tokens that can be auto-minted for a beneficiary during a stage.
|
|
91
|
+
/// @param revnetId The ID of the revnet.
|
|
92
|
+
/// @param stageId The ID of the stage.
|
|
93
|
+
/// @param beneficiary The beneficiary of the auto-mint.
|
|
94
|
+
/// @return The number of tokens available to auto-issue.
|
|
95
|
+
function amountToAutoIssue(uint256 revnetId, uint256 stageId, address beneficiary) external view returns (uint256);
|
|
96
|
+
|
|
97
|
+
/// @notice The buyback hook used as a data hook to route payments through buyback pools.
|
|
98
|
+
/// @return The buyback hook contract.
|
|
99
|
+
function BUYBACK_HOOK() external view returns (IJBRulesetDataHook);
|
|
51
100
|
|
|
52
101
|
/// @notice The number of seconds until a revnet's participants can cash out after deploying to a new network.
|
|
53
102
|
/// @return The cash out delay in seconds.
|
|
54
103
|
function CASH_OUT_DELAY() external view returns (uint256);
|
|
55
104
|
|
|
105
|
+
/// @notice The timestamp when cash outs become available for a revnet's participants.
|
|
106
|
+
/// @param revnetId The ID of the revnet.
|
|
107
|
+
/// @return The cash out delay timestamp.
|
|
108
|
+
function cashOutDelayOf(uint256 revnetId) external view returns (uint256);
|
|
109
|
+
|
|
56
110
|
/// @notice The controller used to create and manage Juicebox projects for revnets.
|
|
57
111
|
/// @return The controller contract.
|
|
58
112
|
function CONTROLLER() external view returns (IJBController);
|
|
59
113
|
|
|
60
|
-
/// @notice The directory of terminals and controllers for Juicebox projects.
|
|
61
|
-
/// @return The directory contract.
|
|
62
|
-
function DIRECTORY() external view returns (IJBDirectory);
|
|
63
|
-
|
|
64
|
-
/// @notice The contract that mints ERC-721s representing project ownership.
|
|
65
|
-
/// @return The projects contract.
|
|
66
|
-
function PROJECTS() external view returns (IJBProjects);
|
|
67
|
-
|
|
68
|
-
/// @notice The contract that stores Juicebox project access permissions.
|
|
69
|
-
/// @return The permissions contract.
|
|
70
|
-
function PERMISSIONS() external view returns (IJBPermissions);
|
|
71
|
-
|
|
72
|
-
/// @notice The cash out fee as a fraction out of `JBConstants.MAX_FEE`.
|
|
73
|
-
/// @return The fee value.
|
|
74
|
-
function FEE() external view returns (uint256);
|
|
75
|
-
|
|
76
114
|
/// @notice The default Uniswap pool fee tier for auto-configured buyback pools.
|
|
77
115
|
/// @return The fee tier (10_000 = 1%).
|
|
78
116
|
function DEFAULT_BUYBACK_POOL_FEE() external view returns (uint24);
|
|
@@ -81,63 +119,52 @@ interface IREVDeployer {
|
|
|
81
119
|
/// @return The TWAP window in seconds.
|
|
82
120
|
function DEFAULT_BUYBACK_TWAP_WINDOW() external view returns (uint32);
|
|
83
121
|
|
|
84
|
-
/// @notice The
|
|
85
|
-
/// @return The
|
|
86
|
-
function
|
|
122
|
+
/// @notice The directory of terminals and controllers for Juicebox projects.
|
|
123
|
+
/// @return The directory contract.
|
|
124
|
+
function DIRECTORY() external view returns (IJBDirectory);
|
|
125
|
+
|
|
126
|
+
/// @notice The cash out fee as a fraction out of `JBConstants.MAX_FEE`.
|
|
127
|
+
/// @return The fee value.
|
|
128
|
+
function FEE() external view returns (uint256);
|
|
87
129
|
|
|
88
130
|
/// @notice The Juicebox project ID of the revnet that receives cash out fees.
|
|
89
131
|
/// @return The fee revnet ID.
|
|
90
132
|
function FEE_REVNET_ID() external view returns (uint256);
|
|
91
133
|
|
|
92
|
-
/// @notice The
|
|
93
|
-
/// @
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
/// @notice The buyback hook used as a data hook to route payments through buyback pools.
|
|
97
|
-
/// @return The buyback hook contract.
|
|
98
|
-
function BUYBACK_HOOK() external view returns (IJBRulesetDataHook);
|
|
134
|
+
/// @notice The hashed encoded configuration of each revnet.
|
|
135
|
+
/// @param revnetId The ID of the revnet.
|
|
136
|
+
/// @return The hashed encoded configuration.
|
|
137
|
+
function hashedEncodedConfigurationOf(uint256 revnetId) external view returns (bytes32);
|
|
99
138
|
|
|
100
139
|
/// @notice The deployer used to create tiered ERC-721 hooks for revnets.
|
|
101
140
|
/// @return The hook deployer contract.
|
|
102
141
|
function HOOK_DEPLOYER() external view returns (IJB721TiersHookDeployer);
|
|
103
142
|
|
|
143
|
+
/// @notice Whether an address is a revnet's split operator.
|
|
144
|
+
/// @param revnetId The ID of the revnet.
|
|
145
|
+
/// @param addr The address to check.
|
|
146
|
+
/// @return A flag indicating whether the address is the revnet's split operator.
|
|
147
|
+
function isSplitOperatorOf(uint256 revnetId, address addr) external view returns (bool);
|
|
148
|
+
|
|
104
149
|
/// @notice The loan contract used by all revnets.
|
|
105
150
|
/// @return The loans contract address.
|
|
106
151
|
function LOANS() external view returns (address);
|
|
107
152
|
|
|
108
|
-
/// @notice The
|
|
109
|
-
/// @
|
|
110
|
-
|
|
111
|
-
/// @param beneficiary The beneficiary of the auto-mint.
|
|
112
|
-
/// @return The number of tokens available to auto-issue.
|
|
113
|
-
function amountToAutoIssue(uint256 revnetId, uint256 stageId, address beneficiary) external view returns (uint256);
|
|
114
|
-
|
|
115
|
-
/// @notice The timestamp when cash outs become available for a revnet's participants.
|
|
116
|
-
/// @param revnetId The ID of the revnet.
|
|
117
|
-
/// @return The cash out delay timestamp.
|
|
118
|
-
function cashOutDelayOf(uint256 revnetId) external view returns (uint256);
|
|
153
|
+
/// @notice The contract that stores Juicebox project access permissions.
|
|
154
|
+
/// @return The permissions contract.
|
|
155
|
+
function PERMISSIONS() external view returns (IJBPermissions);
|
|
119
156
|
|
|
120
|
-
/// @notice
|
|
121
|
-
/// @
|
|
122
|
-
|
|
123
|
-
/// @return suckers The addresses of the deployed suckers.
|
|
124
|
-
function deploySuckersFor(
|
|
125
|
-
uint256 revnetId,
|
|
126
|
-
REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
|
|
127
|
-
)
|
|
128
|
-
external
|
|
129
|
-
returns (address[] memory suckers);
|
|
157
|
+
/// @notice The contract that mints ERC-721s representing project ownership.
|
|
158
|
+
/// @return The projects contract.
|
|
159
|
+
function PROJECTS() external view returns (IJBProjects);
|
|
130
160
|
|
|
131
|
-
/// @notice The
|
|
132
|
-
/// @
|
|
133
|
-
|
|
134
|
-
function hashedEncodedConfigurationOf(uint256 revnetId) external view returns (bytes32);
|
|
161
|
+
/// @notice The croptop publisher revnets can use to publish ERC-721 posts to their tiered ERC-721 hooks.
|
|
162
|
+
/// @return The publisher contract.
|
|
163
|
+
function PUBLISHER() external view returns (CTPublisher);
|
|
135
164
|
|
|
136
|
-
/// @notice
|
|
137
|
-
/// @
|
|
138
|
-
|
|
139
|
-
/// @return A flag indicating whether the address is the revnet's split operator.
|
|
140
|
-
function isSplitOperatorOf(uint256 revnetId, address addr) external view returns (bool);
|
|
165
|
+
/// @notice The registry that deploys and tracks suckers for revnets.
|
|
166
|
+
/// @return The sucker registry contract.
|
|
167
|
+
function SUCKER_REGISTRY() external view returns (IJBSuckerRegistry);
|
|
141
168
|
|
|
142
169
|
/// @notice Each revnet's tiered ERC-721 hook.
|
|
143
170
|
/// @param revnetId The ID of the revnet.
|
|
@@ -150,6 +177,10 @@ interface IREVDeployer {
|
|
|
150
177
|
/// @param beneficiary The address to auto-mint tokens to.
|
|
151
178
|
function autoIssueFor(uint256 revnetId, uint256 stageId, address beneficiary) external;
|
|
152
179
|
|
|
180
|
+
/// @notice Burn any of a revnet's tokens held by this contract.
|
|
181
|
+
/// @param revnetId The ID of the revnet whose tokens should be burned.
|
|
182
|
+
function burnHeldTokensOf(uint256 revnetId) external;
|
|
183
|
+
|
|
153
184
|
/// @notice Deploy a revnet, or initialize an existing Juicebox project as a revnet.
|
|
154
185
|
/// @param revnetId The ID of the Juicebox project to initialize. Send 0 to deploy a new revnet.
|
|
155
186
|
/// @param configuration Core revnet configuration.
|
|
@@ -165,6 +196,17 @@ interface IREVDeployer {
|
|
|
165
196
|
external
|
|
166
197
|
returns (uint256);
|
|
167
198
|
|
|
199
|
+
/// @notice Deploy new suckers for an existing revnet.
|
|
200
|
+
/// @param revnetId The ID of the revnet to deploy suckers for.
|
|
201
|
+
/// @param suckerDeploymentConfiguration The suckers to set up for the revnet.
|
|
202
|
+
/// @return suckers The addresses of the deployed suckers.
|
|
203
|
+
function deploySuckersFor(
|
|
204
|
+
uint256 revnetId,
|
|
205
|
+
REVSuckerDeploymentConfig calldata suckerDeploymentConfiguration
|
|
206
|
+
)
|
|
207
|
+
external
|
|
208
|
+
returns (address[] memory suckers);
|
|
209
|
+
|
|
168
210
|
/// @notice Deploy a revnet with tiered ERC-721s and optional croptop posting support.
|
|
169
211
|
/// @param revnetId The ID of the Juicebox project to initialize. Send 0 to deploy a new revnet.
|
|
170
212
|
/// @param configuration Core revnet configuration.
|
|
@@ -189,8 +231,4 @@ interface IREVDeployer {
|
|
|
189
231
|
/// @param revnetId The ID of the revnet.
|
|
190
232
|
/// @param newSplitOperator The new split operator's address.
|
|
191
233
|
function setSplitOperatorOf(uint256 revnetId, address newSplitOperator) external;
|
|
192
|
-
|
|
193
|
-
/// @notice Burn any of a revnet's tokens held by this contract.
|
|
194
|
-
/// @param revnetId The ID of the revnet whose tokens should be burned.
|
|
195
|
-
function burnHeldTokensOf(uint256 revnetId) external;
|
|
196
234
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
|
-
import {IPermit2} from "@uniswap/permit2/src/interfaces/IPermit2.sol";
|
|
5
4
|
import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
6
5
|
import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
7
6
|
import {IJBPayoutTerminal} from "@bananapus/core-v6/src/interfaces/IJBPayoutTerminal.sol";
|
|
@@ -9,11 +8,22 @@ import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
|
|
|
9
8
|
import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
|
|
10
9
|
import {IJBTokenUriResolver} from "@bananapus/core-v6/src/interfaces/IJBTokenUriResolver.sol";
|
|
11
10
|
import {JBSingleAllowance} from "@bananapus/core-v6/src/structs/JBSingleAllowance.sol";
|
|
12
|
-
|
|
11
|
+
import {IPermit2} from "@uniswap/permit2/src/interfaces/IPermit2.sol";
|
|
13
12
|
import {REVLoan} from "./../structs/REVLoan.sol";
|
|
14
13
|
import {REVLoanSource} from "./../structs/REVLoanSource.sol";
|
|
15
14
|
|
|
15
|
+
/// @notice Manages loans against revnet token collateral.
|
|
16
16
|
interface IREVLoans {
|
|
17
|
+
/// @notice Emitted when a loan is created by borrowing from a revnet.
|
|
18
|
+
/// @param loanId The ID of the newly created loan.
|
|
19
|
+
/// @param revnetId The ID of the revnet being borrowed from.
|
|
20
|
+
/// @param loan The loan data.
|
|
21
|
+
/// @param source The source of the loan (terminal and token).
|
|
22
|
+
/// @param borrowAmount The amount borrowed.
|
|
23
|
+
/// @param collateralCount The amount of collateral tokens locked.
|
|
24
|
+
/// @param sourceFeeAmount The fee amount charged by the source.
|
|
25
|
+
/// @param beneficiary The address receiving the borrowed funds.
|
|
26
|
+
/// @param caller The address that created the loan.
|
|
17
27
|
event Borrow(
|
|
18
28
|
uint256 indexed loanId,
|
|
19
29
|
uint256 indexed revnetId,
|
|
@@ -25,7 +35,41 @@ interface IREVLoans {
|
|
|
25
35
|
address payable beneficiary,
|
|
26
36
|
address caller
|
|
27
37
|
);
|
|
38
|
+
|
|
39
|
+
/// @notice Emitted when a loan is liquidated after exceeding the liquidation duration.
|
|
40
|
+
/// @param loanId The ID of the liquidated loan.
|
|
41
|
+
/// @param revnetId The ID of the revnet the loan was from.
|
|
42
|
+
/// @param loan The liquidated loan data.
|
|
43
|
+
/// @param caller The address that triggered the liquidation.
|
|
28
44
|
event Liquidate(uint256 indexed loanId, uint256 indexed revnetId, REVLoan loan, address caller);
|
|
45
|
+
|
|
46
|
+
/// @notice Emitted when collateral is reallocated from one loan to a new loan.
|
|
47
|
+
/// @param loanId The ID of the original loan.
|
|
48
|
+
/// @param revnetId The ID of the revnet.
|
|
49
|
+
/// @param reallocatedLoanId The ID of the loan after reallocation.
|
|
50
|
+
/// @param reallocatedLoan The reallocated loan data.
|
|
51
|
+
/// @param removedCollateralCount The amount of collateral removed from the original loan.
|
|
52
|
+
/// @param caller The address that triggered the reallocation.
|
|
53
|
+
event ReallocateCollateral(
|
|
54
|
+
uint256 indexed loanId,
|
|
55
|
+
uint256 indexed revnetId,
|
|
56
|
+
uint256 indexed reallocatedLoanId,
|
|
57
|
+
REVLoan reallocatedLoan,
|
|
58
|
+
uint256 removedCollateralCount,
|
|
59
|
+
address caller
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
/// @notice Emitted when a loan is repaid.
|
|
63
|
+
/// @param loanId The ID of the loan being repaid.
|
|
64
|
+
/// @param revnetId The ID of the revnet.
|
|
65
|
+
/// @param paidOffLoanId The ID of the loan after repayment.
|
|
66
|
+
/// @param loan The original loan data.
|
|
67
|
+
/// @param paidOffLoan The loan data after repayment.
|
|
68
|
+
/// @param repayBorrowAmount The amount repaid.
|
|
69
|
+
/// @param sourceFeeAmount The fee amount charged by the source.
|
|
70
|
+
/// @param collateralCountToReturn The amount of collateral returned.
|
|
71
|
+
/// @param beneficiary The address receiving the returned collateral.
|
|
72
|
+
/// @param caller The address that repaid the loan.
|
|
29
73
|
event RepayLoan(
|
|
30
74
|
uint256 indexed loanId,
|
|
31
75
|
uint256 indexed revnetId,
|
|
@@ -38,55 +82,11 @@ interface IREVLoans {
|
|
|
38
82
|
address payable beneficiary,
|
|
39
83
|
address caller
|
|
40
84
|
);
|
|
41
|
-
event ReallocateCollateral(
|
|
42
|
-
uint256 indexed loanId,
|
|
43
|
-
uint256 indexed revnetId,
|
|
44
|
-
uint256 indexed reallocatedLoanId,
|
|
45
|
-
REVLoan reallocatedLoan,
|
|
46
|
-
uint256 removedCollateralCount,
|
|
47
|
-
address caller
|
|
48
|
-
);
|
|
49
|
-
event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);
|
|
50
|
-
|
|
51
|
-
/// @notice The duration after which a loan expires and its collateral is permanently lost.
|
|
52
|
-
/// @return The loan liquidation duration in seconds.
|
|
53
|
-
function LOAN_LIQUIDATION_DURATION() external view returns (uint256);
|
|
54
|
-
|
|
55
|
-
/// @notice The permit2 utility used for token transfers.
|
|
56
|
-
/// @return The permit2 contract.
|
|
57
|
-
function PERMIT2() external view returns (IPermit2);
|
|
58
85
|
|
|
59
|
-
/// @notice
|
|
60
|
-
/// @
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
/// @notice The directory of terminals and controllers for revnets.
|
|
64
|
-
/// @return The directory contract.
|
|
65
|
-
function DIRECTORY() external view returns (IJBDirectory);
|
|
66
|
-
|
|
67
|
-
/// @notice The contract that stores prices for each revnet.
|
|
68
|
-
/// @return The prices contract.
|
|
69
|
-
function PRICES() external view returns (IJBPrices);
|
|
70
|
-
|
|
71
|
-
/// @notice The contract that mints ERC-721s representing project ownership.
|
|
72
|
-
/// @return The projects contract.
|
|
73
|
-
function PROJECTS() external view returns (IJBProjects);
|
|
74
|
-
|
|
75
|
-
/// @notice The ID of the REV revnet that receives protocol fees from loans.
|
|
76
|
-
/// @return The REV revnet ID.
|
|
77
|
-
function REV_ID() external view returns (uint256);
|
|
78
|
-
|
|
79
|
-
/// @notice The fee percent charged by the REV revnet on each loan, in terms of `JBConstants.MAX_FEE`.
|
|
80
|
-
/// @return The REV prepaid fee percent.
|
|
81
|
-
function REV_PREPAID_FEE_PERCENT() external view returns (uint256);
|
|
82
|
-
|
|
83
|
-
/// @notice The minimum fee percent that must be prepaid when borrowing, in terms of `JBConstants.MAX_FEE`.
|
|
84
|
-
/// @return The minimum prepaid fee percent.
|
|
85
|
-
function MIN_PREPAID_FEE_PERCENT() external view returns (uint256);
|
|
86
|
-
|
|
87
|
-
/// @notice The maximum fee percent that can be prepaid when borrowing, in terms of `JBConstants.MAX_FEE`.
|
|
88
|
-
/// @return The maximum prepaid fee percent.
|
|
89
|
-
function MAX_PREPAID_FEE_PERCENT() external view returns (uint256);
|
|
86
|
+
/// @notice Emitted when the token URI resolver is changed.
|
|
87
|
+
/// @param resolver The new token URI resolver.
|
|
88
|
+
/// @param caller The address that set the resolver.
|
|
89
|
+
event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);
|
|
90
90
|
|
|
91
91
|
/// @notice The amount that can be borrowed from a revnet given a certain amount of collateral.
|
|
92
92
|
/// @param revnetId The ID of the revnet to check for borrowable assets from.
|
|
@@ -104,6 +104,10 @@ interface IREVLoans {
|
|
|
104
104
|
view
|
|
105
105
|
returns (uint256);
|
|
106
106
|
|
|
107
|
+
/// @notice The controller that manages revnets using this loans contract.
|
|
108
|
+
/// @return The controller contract.
|
|
109
|
+
function CONTROLLER() external view returns (IJBController);
|
|
110
|
+
|
|
107
111
|
/// @notice Determines the source fee amount for a loan being paid off a certain amount.
|
|
108
112
|
/// @param loan The loan having its source fee amount determined.
|
|
109
113
|
/// @param amount The amount being paid off.
|
|
@@ -116,6 +120,10 @@ interface IREVLoans {
|
|
|
116
120
|
view
|
|
117
121
|
returns (uint256 sourceFeeAmount);
|
|
118
122
|
|
|
123
|
+
/// @notice The directory of terminals and controllers for revnets.
|
|
124
|
+
/// @return The directory contract.
|
|
125
|
+
function DIRECTORY() external view returns (IJBDirectory);
|
|
126
|
+
|
|
119
127
|
/// @notice Whether a revnet currently has outstanding loans from the specified terminal in the specified token.
|
|
120
128
|
/// @param revnetId The ID of the revnet issuing the loan.
|
|
121
129
|
/// @param terminal The terminal that the loan is issued from.
|
|
@@ -123,6 +131,10 @@ interface IREVLoans {
|
|
|
123
131
|
/// @return A flag indicating if the revnet has an active loan source.
|
|
124
132
|
function isLoanSourceOf(uint256 revnetId, IJBPayoutTerminal terminal, address token) external view returns (bool);
|
|
125
133
|
|
|
134
|
+
/// @notice The duration after which a loan expires and its collateral is permanently lost.
|
|
135
|
+
/// @return The loan liquidation duration in seconds.
|
|
136
|
+
function LOAN_LIQUIDATION_DURATION() external view returns (uint256);
|
|
137
|
+
|
|
126
138
|
/// @notice Get a loan's details.
|
|
127
139
|
/// @param loanId The ID of the loan to retrieve.
|
|
128
140
|
/// @return The loan data.
|
|
@@ -136,13 +148,33 @@ interface IREVLoans {
|
|
|
136
148
|
/// @return The array of loan sources.
|
|
137
149
|
function loanSourcesOf(uint256 revnetId) external view returns (REVLoanSource[] memory);
|
|
138
150
|
|
|
139
|
-
/// @notice The
|
|
140
|
-
/// @
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
/// @
|
|
144
|
-
/// @return The
|
|
145
|
-
function
|
|
151
|
+
/// @notice The maximum fee percent that can be prepaid when borrowing, in terms of `JBConstants.MAX_FEE`.
|
|
152
|
+
/// @return The maximum prepaid fee percent.
|
|
153
|
+
function MAX_PREPAID_FEE_PERCENT() external view returns (uint256);
|
|
154
|
+
|
|
155
|
+
/// @notice The minimum fee percent that must be prepaid when borrowing, in terms of `JBConstants.MAX_FEE`.
|
|
156
|
+
/// @return The minimum prepaid fee percent.
|
|
157
|
+
function MIN_PREPAID_FEE_PERCENT() external view returns (uint256);
|
|
158
|
+
|
|
159
|
+
/// @notice The permit2 utility used for token transfers.
|
|
160
|
+
/// @return The permit2 contract.
|
|
161
|
+
function PERMIT2() external view returns (IPermit2);
|
|
162
|
+
|
|
163
|
+
/// @notice The contract that stores prices for each revnet.
|
|
164
|
+
/// @return The prices contract.
|
|
165
|
+
function PRICES() external view returns (IJBPrices);
|
|
166
|
+
|
|
167
|
+
/// @notice The contract that mints ERC-721s representing project ownership.
|
|
168
|
+
/// @return The projects contract.
|
|
169
|
+
function PROJECTS() external view returns (IJBProjects);
|
|
170
|
+
|
|
171
|
+
/// @notice The ID of the REV revnet that receives protocol fees from loans.
|
|
172
|
+
/// @return The REV revnet ID.
|
|
173
|
+
function REV_ID() external view returns (uint256);
|
|
174
|
+
|
|
175
|
+
/// @notice The fee percent charged by the REV revnet on each loan, in terms of `JBConstants.MAX_FEE`.
|
|
176
|
+
/// @return The REV prepaid fee percent.
|
|
177
|
+
function REV_PREPAID_FEE_PERCENT() external view returns (uint256);
|
|
146
178
|
|
|
147
179
|
/// @notice The revnet ID for the loan with the provided loan ID.
|
|
148
180
|
/// @param loanId The loan ID to get the revnet ID of.
|
|
@@ -172,6 +204,14 @@ interface IREVLoans {
|
|
|
172
204
|
/// @return The total collateral count.
|
|
173
205
|
function totalCollateralOf(uint256 revnetId) external view returns (uint256);
|
|
174
206
|
|
|
207
|
+
/// @notice The cumulative number of loans ever created for a revnet, used as a loan ID sequence counter.
|
|
208
|
+
/// @dev This counter only increments and never decrements. It does NOT represent the count of currently active
|
|
209
|
+
/// loans -- repaid and liquidated loans leave permanent gaps in the sequence. Do not use this value to determine
|
|
210
|
+
/// how many loans are currently outstanding.
|
|
211
|
+
/// @param revnetId The ID of the revnet to get the cumulative loan count for.
|
|
212
|
+
/// @return The cumulative number of loans ever created.
|
|
213
|
+
function totalLoansBorrowedFor(uint256 revnetId) external view returns (uint256);
|
|
214
|
+
|
|
175
215
|
/// @notice Open a loan by borrowing from a revnet. Collateral tokens are burned and only re-minted upon repayment.
|
|
176
216
|
/// @param revnetId The ID of the revnet being borrowed from.
|
|
177
217
|
/// @param source The source of the loan (terminal and token).
|
|
@@ -198,25 +238,6 @@ interface IREVLoans {
|
|
|
198
238
|
/// @param count The number of loans to iterate over.
|
|
199
239
|
function liquidateExpiredLoansFrom(uint256 revnetId, uint256 startingLoanId, uint256 count) external;
|
|
200
240
|
|
|
201
|
-
/// @notice Repay a loan or return excess collateral no longer needed to support the loan.
|
|
202
|
-
/// @param loanId The ID of the loan being repaid.
|
|
203
|
-
/// @param maxRepayBorrowAmount The maximum amount to repay, denominated in the source's token.
|
|
204
|
-
/// @param collateralCountToReturn The amount of collateral to return from the loan.
|
|
205
|
-
/// @param beneficiary The address receiving the returned collateral and fee payment tokens.
|
|
206
|
-
/// @param allowance A permit2 allowance to facilitate the repayment transfer.
|
|
207
|
-
/// @return paidOffLoanId The ID of the loan after it has been paid off.
|
|
208
|
-
/// @return paidOffloan The loan after it has been paid off.
|
|
209
|
-
function repayLoan(
|
|
210
|
-
uint256 loanId,
|
|
211
|
-
uint256 maxRepayBorrowAmount,
|
|
212
|
-
uint256 collateralCountToReturn,
|
|
213
|
-
address payable beneficiary,
|
|
214
|
-
JBSingleAllowance calldata allowance
|
|
215
|
-
)
|
|
216
|
-
external
|
|
217
|
-
payable
|
|
218
|
-
returns (uint256 paidOffLoanId, REVLoan memory paidOffloan);
|
|
219
|
-
|
|
220
241
|
/// @notice Refinance a loan by transferring extra collateral from an existing loan to a new loan.
|
|
221
242
|
/// @param loanId The ID of the loan to reallocate collateral from.
|
|
222
243
|
/// @param collateralCountToTransfer The amount of collateral to transfer from the original loan.
|
|
@@ -241,6 +262,25 @@ interface IREVLoans {
|
|
|
241
262
|
external
|
|
242
263
|
returns (uint256 reallocatedLoanId, uint256 newLoanId, REVLoan memory reallocatedLoan, REVLoan memory newLoan);
|
|
243
264
|
|
|
265
|
+
/// @notice Repay a loan or return excess collateral no longer needed to support the loan.
|
|
266
|
+
/// @param loanId The ID of the loan being repaid.
|
|
267
|
+
/// @param maxRepayBorrowAmount The maximum amount to repay, denominated in the source's token.
|
|
268
|
+
/// @param collateralCountToReturn The amount of collateral to return from the loan.
|
|
269
|
+
/// @param beneficiary The address receiving the returned collateral and fee payment tokens.
|
|
270
|
+
/// @param allowance A permit2 allowance to facilitate the repayment transfer.
|
|
271
|
+
/// @return paidOffLoanId The ID of the loan after it has been paid off.
|
|
272
|
+
/// @return paidOffloan The loan after it has been paid off.
|
|
273
|
+
function repayLoan(
|
|
274
|
+
uint256 loanId,
|
|
275
|
+
uint256 maxRepayBorrowAmount,
|
|
276
|
+
uint256 collateralCountToReturn,
|
|
277
|
+
address payable beneficiary,
|
|
278
|
+
JBSingleAllowance calldata allowance
|
|
279
|
+
)
|
|
280
|
+
external
|
|
281
|
+
payable
|
|
282
|
+
returns (uint256 paidOffLoanId, REVLoan memory paidOffloan);
|
|
283
|
+
|
|
244
284
|
/// @notice Sets the address of the resolver used to retrieve the token URI of loans.
|
|
245
285
|
/// @param resolver The new token URI resolver.
|
|
246
286
|
function setTokenUriResolver(IJBTokenUriResolver resolver) external;
|
|
@@ -4,13 +4,14 @@ pragma solidity 0.8.26;
|
|
|
4
4
|
import {IJBRulesetDataHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetDataHook.sol";
|
|
5
5
|
import {IJBPayHook} from "@bananapus/core-v6/src/interfaces/IJBPayHook.sol";
|
|
6
6
|
import {IJBBuybackHook} from "@bananapus/buyback-hook-v6/src/interfaces/IJBBuybackHook.sol";
|
|
7
|
+
import {IWETH9} from "@bananapus/buyback-hook-v6/src/interfaces/external/IWETH9.sol";
|
|
7
8
|
import {JBBeforePayRecordedContext} from "@bananapus/core-v6/src/structs/JBBeforePayRecordedContext.sol";
|
|
8
9
|
import {JBBeforeCashOutRecordedContext} from "@bananapus/core-v6/src/structs/JBBeforeCashOutRecordedContext.sol";
|
|
9
10
|
import {JBPayHookSpecification} from "@bananapus/core-v6/src/structs/JBPayHookSpecification.sol";
|
|
10
11
|
import {JBCashOutHookSpecification} from "@bananapus/core-v6/src/structs/JBCashOutHookSpecification.sol";
|
|
11
12
|
import {JBAfterPayRecordedContext} from "@bananapus/core-v6/src/structs/JBAfterPayRecordedContext.sol";
|
|
12
13
|
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
13
|
-
import {
|
|
14
|
+
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
14
15
|
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
15
16
|
|
|
16
17
|
/// @notice A minimal mock buyback data hook for tests. Returns the default weight and a no-op pay hook specification.
|
|
@@ -49,11 +50,14 @@ contract MockBuybackDataHook is IJBRulesetDataHook, IJBPayHook {
|
|
|
49
50
|
|
|
50
51
|
function afterPayRecordedWith(JBAfterPayRecordedContext calldata) external payable override {}
|
|
51
52
|
|
|
52
|
-
/// @notice
|
|
53
|
-
function
|
|
54
|
-
return
|
|
53
|
+
/// @notice Returns a dummy WETH address for tests.
|
|
54
|
+
function WETH() external pure returns (IWETH9) {
|
|
55
|
+
return IWETH9(address(1));
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
/// @notice No-op pool configuration for tests.
|
|
59
|
+
function setPoolFor(uint256, PoolKey calldata, uint256, address) external pure {}
|
|
60
|
+
|
|
57
61
|
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
|
|
58
62
|
return interfaceId == type(IJBRulesetDataHook).interfaceId || interfaceId == type(IJBPayHook).interfaceId
|
|
59
63
|
|| interfaceId == type(IERC165).interfaceId;
|
|
@@ -3,13 +3,14 @@ pragma solidity 0.8.26;
|
|
|
3
3
|
|
|
4
4
|
import {IJBRulesetDataHook} from "@bananapus/core-v6/src/interfaces/IJBRulesetDataHook.sol";
|
|
5
5
|
import {IJBPayHook} from "@bananapus/core-v6/src/interfaces/IJBPayHook.sol";
|
|
6
|
+
import {IWETH9} from "@bananapus/buyback-hook-v6/src/interfaces/external/IWETH9.sol";
|
|
6
7
|
import {JBBeforePayRecordedContext} from "@bananapus/core-v6/src/structs/JBBeforePayRecordedContext.sol";
|
|
7
8
|
import {JBBeforeCashOutRecordedContext} from "@bananapus/core-v6/src/structs/JBBeforeCashOutRecordedContext.sol";
|
|
8
9
|
import {JBPayHookSpecification} from "@bananapus/core-v6/src/structs/JBPayHookSpecification.sol";
|
|
9
10
|
import {JBCashOutHookSpecification} from "@bananapus/core-v6/src/structs/JBCashOutHookSpecification.sol";
|
|
10
11
|
import {JBAfterPayRecordedContext} from "@bananapus/core-v6/src/structs/JBAfterPayRecordedContext.sol";
|
|
11
12
|
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
12
|
-
import {
|
|
13
|
+
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
13
14
|
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
14
15
|
|
|
15
16
|
/// @notice Mock buyback hook that simulates the "mint path" — returns EMPTY hookSpecifications.
|
|
@@ -50,10 +51,13 @@ contract MockBuybackDataHookMintPath is IJBRulesetDataHook, IJBPayHook {
|
|
|
50
51
|
|
|
51
52
|
function afterPayRecordedWith(JBAfterPayRecordedContext calldata) external payable override {}
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
/// @notice Returns a dummy WETH address for tests.
|
|
55
|
+
function WETH() external pure returns (IWETH9) {
|
|
56
|
+
return IWETH9(address(1));
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
function setPoolFor(uint256, PoolKey calldata, uint256, address) external pure {}
|
|
60
|
+
|
|
57
61
|
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
|
|
58
62
|
return interfaceId == type(IJBRulesetDataHook).interfaceId || interfaceId == type(IJBPayHook).interfaceId
|
|
59
63
|
|| interfaceId == type(IERC165).interfaceId;
|