@venusprotocol/liquidity-hub 0.0.0
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/LICENSE +98 -0
- package/README.md +422 -0
- package/contracts/Hub/Hub.sol +1614 -0
- package/contracts/Hub/HubStorage.sol +106 -0
- package/contracts/Hub/lib/HubAdminLib.sol +292 -0
- package/contracts/YieldGroup/YieldGroup.sol +128 -0
- package/contracts/YieldGroup/YieldGroupFRV.sol +107 -0
- package/contracts/YieldGroup/base/YieldGroupBase.sol +797 -0
- package/contracts/YieldGroup/base/YieldGroupBaseStorage.sol +73 -0
- package/contracts/adapters/AdapterCoreV1.sol +309 -0
- package/contracts/adapters/AdapterFRV.sol +276 -0
- package/contracts/adapters/AdapterFlux.sol +173 -0
- package/contracts/interfaces/IHub.sol +551 -0
- package/contracts/interfaces/IHubRegistry.sol +120 -0
- package/contracts/interfaces/IMigrator.sol +134 -0
- package/contracts/interfaces/IResourceAdapter.sol +154 -0
- package/contracts/interfaces/IYieldGroup.sol +119 -0
- package/contracts/interfaces/IYieldGroupBase.sol +507 -0
- package/contracts/interfaces/IYieldGroupFRV.sol +61 -0
- package/contracts/interfaces/external/IComptroller.sol +57 -0
- package/contracts/interfaces/external/IFRVVault.sol +113 -0
- package/contracts/interfaces/external/IFToken.sol +46 -0
- package/contracts/interfaces/external/IFluidLendingResolver.sol +63 -0
- package/contracts/interfaces/external/IVBep20.sol +39 -0
- package/contracts/interfaces/external/IVToken.sol +125 -0
- package/contracts/interfaces/external/IWBNB.sol +16 -0
- package/contracts/migrator/Migrator.sol +182 -0
- package/contracts/registry/HubRegistry.sol +179 -0
- package/deployments/bscmainnet/AdapterCoreV1.json +336 -0
- package/deployments/bscmainnet/AdapterFRV.json +225 -0
- package/deployments/bscmainnet/AdapterFlux.json +249 -0
- package/deployments/bscmainnet/CoreBeacon.json +110 -0
- package/deployments/bscmainnet/CoreSource_U.json +1083 -0
- package/deployments/bscmainnet/CoreSource_USDC.json +1083 -0
- package/deployments/bscmainnet/CoreSource_USDT.json +1083 -0
- package/deployments/bscmainnet/FRVBeacon.json +110 -0
- package/deployments/bscmainnet/FRVSource_U.json +978 -0
- package/deployments/bscmainnet/FRVSource_USDC.json +978 -0
- package/deployments/bscmainnet/FRVSource_USDT.json +978 -0
- package/deployments/bscmainnet/FluxBeacon.json +110 -0
- package/deployments/bscmainnet/FluxSource_U.json +1083 -0
- package/deployments/bscmainnet/FluxSource_USDC.json +1083 -0
- package/deployments/bscmainnet/FluxSource_USDT.json +1083 -0
- package/deployments/bscmainnet/HubBeacon.json +110 -0
- package/deployments/bscmainnet/HubImpl.json +2216 -0
- package/deployments/bscmainnet/HubRegistry.json +386 -0
- package/deployments/bscmainnet/HubRegistryImpl.json +386 -0
- package/deployments/bscmainnet/Hub_U.json +2216 -0
- package/deployments/bscmainnet/Hub_USDC.json +2216 -0
- package/deployments/bscmainnet/Hub_USDT.json +2216 -0
- package/deployments/bscmainnet/Migrator.json +375 -0
- package/deployments/bscmainnet/YieldGroupCoreImpl.json +1083 -0
- package/deployments/bscmainnet/YieldGroupFRVImpl.json +978 -0
- package/deployments/bscmainnet/YieldGroupFluxImpl.json +1083 -0
- package/deployments/bscmainnet_addresses.json +32 -0
- package/deployments/bsctestnet/AdapterCoreV1.json +336 -0
- package/deployments/bsctestnet/AdapterFRV.json +225 -0
- package/deployments/bsctestnet/AdapterFlux.json +249 -0
- package/deployments/bsctestnet/CoreBeacon.json +110 -0
- package/deployments/bsctestnet/CoreSource_USDT.json +1083 -0
- package/deployments/bsctestnet/FRVBeacon.json +110 -0
- package/deployments/bsctestnet/FRVSource_USDT.json +978 -0
- package/deployments/bsctestnet/FluxBeacon.json +110 -0
- package/deployments/bsctestnet/FluxSource_USDT.json +1083 -0
- package/deployments/bsctestnet/HubBeacon.json +110 -0
- package/deployments/bsctestnet/HubImpl.json +2216 -0
- package/deployments/bsctestnet/HubRegistry.json +386 -0
- package/deployments/bsctestnet/HubRegistryImpl.json +386 -0
- package/deployments/bsctestnet/HubRegistryProxyAdmin.json +157 -0
- package/deployments/bsctestnet/Hub_USDT.json +2216 -0
- package/deployments/bsctestnet/Migrator.json +375 -0
- package/deployments/bsctestnet/YieldGroupCoreImpl.json +1083 -0
- package/deployments/bsctestnet/YieldGroupFRVImpl.json +978 -0
- package/deployments/bsctestnet/YieldGroupFluxImpl.json +1083 -0
- package/deployments/bsctestnet_addresses.json +25 -0
- package/package.json +46 -0
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.25;
|
|
3
|
+
|
|
4
|
+
import { IERC4626Upgradeable } from "@openzeppelin/contracts-upgradeable/interfaces/IERC4626Upgradeable.sol";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @title IHub
|
|
8
|
+
* @author Venus
|
|
9
|
+
* @notice External interface for the per-asset Hub vault. Extends ERC-4626 with a YieldGroup
|
|
10
|
+
* registry, dual caps, asymmetric pause, Operator reallocation, and fee accrual.
|
|
11
|
+
* @dev Conventions:
|
|
12
|
+
* - Asset amounts are raw underlying units; BPS are out of `10_000`.
|
|
13
|
+
* - All mutating user-facing calls are atomic-or-revert. The Hub routes the full amount
|
|
14
|
+
* to / from YieldGroups (deposits route out, withdrawals pull exact, reallocate is balanced),
|
|
15
|
+
* so idle is normally zero; the only balance that persists is a direct `asset()` donation
|
|
16
|
+
* — which, since the underlying cannot be swept, is counted in `totalAssets()` (so it
|
|
17
|
+
* accrues to LPs) and consumed first by `withdraw`.
|
|
18
|
+
* - Permissions are gated by `AccessControlManagerV8`: each governance-gated function
|
|
19
|
+
* calls `_checkAccessAllowed` with its literal function-signature string (e.g.
|
|
20
|
+
* `"addYieldGroup(address,uint256,uint16)"`), which is the ACM role for that function.
|
|
21
|
+
* Each governance-gated function below names the role string that gates it; the
|
|
22
|
+
* Operator-vs-governance split is set by which addresses hold each role, not by a
|
|
23
|
+
* hard-coded branch. `deposit` / `mint` / `withdraw` / `redeem` and `accrueFees`
|
|
24
|
+
* are permissionless.
|
|
25
|
+
*/
|
|
26
|
+
interface IHub is IERC4626Upgradeable {
|
|
27
|
+
/**
|
|
28
|
+
* @notice Per-YieldGroup configuration.
|
|
29
|
+
* @param absoluteCap Hard cap on the YieldGroup's holdings, in asset units.
|
|
30
|
+
* @param percentageCapBps Cap as fraction of `totalAssets()` in BPS. The sentinel value
|
|
31
|
+
* `10_000` (100%) disables the percentage component — only `absoluteCap` binds.
|
|
32
|
+
* For any value `< 10_000`, effective cap = `min(absoluteCap,
|
|
33
|
+
* percentageCapBps × totalAssets() / 10_000)`. The `10_000` carve-out exists so
|
|
34
|
+
* a freshly-deployed Hub can take its first deposit (otherwise `pct × 0 / 10_000`
|
|
35
|
+
* collapses the cap to 0 at TA = 0 and the vault is un-bootstrappable).
|
|
36
|
+
* @param paused When true, routing skips this YieldGroup; existing balance still counts.
|
|
37
|
+
* @param registered True iff present in `registeredYieldGroups()`.
|
|
38
|
+
*/
|
|
39
|
+
struct YieldGroupConfig {
|
|
40
|
+
uint256 absoluteCap;
|
|
41
|
+
uint16 percentageCapBps;
|
|
42
|
+
bool paused;
|
|
43
|
+
bool registered;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @notice One leg of a `reallocate()` plan. The same shape is reused for both the
|
|
48
|
+
* withdraw (pull) and the deposit (push) arrays — direction-specific semantics
|
|
49
|
+
* are documented on `reallocate()`.
|
|
50
|
+
* @param yieldGroup YieldGroup to act on. Must be registered. Deposit (push) legs additionally
|
|
51
|
+
* require the YieldGroup to be unpaused and to have spare cap.
|
|
52
|
+
* @param resource Specific resource (market / vault) inside `yieldGroup`. The sentinel
|
|
53
|
+
* `address(0)` means "no target": the YieldGroup cascades through its inner queue —
|
|
54
|
+
* idle-first on a pull leg, capacity-order on a push leg. A non-zero value moves
|
|
55
|
+
* the full `amount` against that one resource and bypasses the queue.
|
|
56
|
+
* @param amount Asset units to move on this leg.
|
|
57
|
+
*/
|
|
58
|
+
struct ReallocateLeg {
|
|
59
|
+
address yieldGroup;
|
|
60
|
+
address resource;
|
|
61
|
+
uint256 amount;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// --------------------------------- Events --------------------------------
|
|
65
|
+
|
|
66
|
+
/// @notice Emitted when a YieldGroup is added to the registry
|
|
67
|
+
/// @param yieldGroup Newly-registered YieldGroup
|
|
68
|
+
/// @param absoluteCap Initial absolute cap in asset units
|
|
69
|
+
/// @param percentageCapBps Initial percentage cap in BPS
|
|
70
|
+
event YieldGroupAdded(address indexed yieldGroup, uint256 absoluteCap, uint16 percentageCapBps);
|
|
71
|
+
|
|
72
|
+
/// @notice Emitted when a YieldGroup is removed from the registry
|
|
73
|
+
/// @param yieldGroup Removed YieldGroup
|
|
74
|
+
event YieldGroupRemoved(address indexed yieldGroup);
|
|
75
|
+
|
|
76
|
+
/// @notice Emitted when a YieldGroup's caps are raised
|
|
77
|
+
/// @param yieldGroup YieldGroup whose caps were updated
|
|
78
|
+
/// @param absoluteCap New absolute cap in asset units
|
|
79
|
+
/// @param percentageCapBps New percentage cap in BPS
|
|
80
|
+
event YieldGroupCapRaised(address indexed yieldGroup, uint256 absoluteCap, uint16 percentageCapBps);
|
|
81
|
+
|
|
82
|
+
/// @notice Emitted when a YieldGroup's caps are lowered
|
|
83
|
+
/// @param yieldGroup YieldGroup whose caps were updated
|
|
84
|
+
/// @param absoluteCap New absolute cap in asset units
|
|
85
|
+
/// @param percentageCapBps New percentage cap in BPS
|
|
86
|
+
event YieldGroupCapLowered(address indexed yieldGroup, uint256 absoluteCap, uint16 percentageCapBps);
|
|
87
|
+
|
|
88
|
+
/// @notice Emitted when a YieldGroup's pause flag is flipped
|
|
89
|
+
/// @param yieldGroup YieldGroup whose flag flipped
|
|
90
|
+
/// @param paused New pause state
|
|
91
|
+
event YieldGroupPauseToggled(address indexed yieldGroup, bool paused);
|
|
92
|
+
|
|
93
|
+
/// @notice Emitted when the deposit routing order is replaced
|
|
94
|
+
/// @param queue Full replacement queue in deposit-priority order
|
|
95
|
+
event OuterDepositQueueSet(address[] queue);
|
|
96
|
+
|
|
97
|
+
/// @notice Emitted when the withdraw routing order is replaced
|
|
98
|
+
/// @param queue Full replacement queue in withdraw-priority order
|
|
99
|
+
event OuterWithdrawQueueSet(address[] queue);
|
|
100
|
+
|
|
101
|
+
/// @notice Emitted when the Hub pause flag is flipped
|
|
102
|
+
/// @param paused New Hub pause state
|
|
103
|
+
event HubPauseToggled(bool paused);
|
|
104
|
+
|
|
105
|
+
/// @notice Emitted when the per-request withdraw cap is raised
|
|
106
|
+
/// @param oldSize Previous cap in asset units
|
|
107
|
+
/// @param newSize New cap in asset units
|
|
108
|
+
event MaxWithdrawalSizeRaised(uint256 oldSize, uint256 newSize);
|
|
109
|
+
|
|
110
|
+
/// @notice Emitted when the per-request withdraw cap is lowered
|
|
111
|
+
/// @param oldSize Previous cap in asset units
|
|
112
|
+
/// @param newSize New cap in asset units
|
|
113
|
+
event MaxWithdrawalSizeLowered(uint256 oldSize, uint256 newSize);
|
|
114
|
+
|
|
115
|
+
/// @notice Emitted when assets are deposited into a YieldGroup on a deposit / mint / reallocate-push leg
|
|
116
|
+
/// @param yieldGroup YieldGroup that received the deposit
|
|
117
|
+
/// @param amount Asset units deposited
|
|
118
|
+
event DepositRouted(address indexed yieldGroup, uint256 amount);
|
|
119
|
+
|
|
120
|
+
/// @notice Emitted when assets are withdrawn from a YieldGroup on a withdraw / redeem / reallocate-pull leg
|
|
121
|
+
/// @param yieldGroup YieldGroup that was pulled from
|
|
122
|
+
/// @param amount Asset units withdrawn
|
|
123
|
+
event WithdrawRouted(address indexed yieldGroup, uint256 amount);
|
|
124
|
+
|
|
125
|
+
/// @notice Emitted when a deposit / withdraw cascade leg was skipped because the YieldGroup's mutating
|
|
126
|
+
/// call reverted (e.g. its external protocol paused it). The operation routes around the
|
|
127
|
+
/// YieldGroup instead of bubbling the revert; a healthy system emits this zero times.
|
|
128
|
+
/// @param yieldGroup YieldGroup whose leg was skipped
|
|
129
|
+
/// @param isDeposit True if the skipped leg was a deposit, false for a withdraw
|
|
130
|
+
event YieldGroupSkipped(address indexed yieldGroup, bool isDeposit);
|
|
131
|
+
|
|
132
|
+
/// @notice Emitted when the management fee rate is changed; pending fees accrued at OLD rate first
|
|
133
|
+
/// @param oldBps Previous rate in BPS
|
|
134
|
+
/// @param newBps New rate in BPS
|
|
135
|
+
event ManagementFeeBpsSet(uint16 oldBps, uint16 newBps);
|
|
136
|
+
|
|
137
|
+
/// @notice Emitted when the performance fee rate is changed; pending fees accrued at OLD rate first
|
|
138
|
+
/// @param oldBps Previous rate in BPS
|
|
139
|
+
/// @param newBps New rate in BPS
|
|
140
|
+
event PerformanceFeeBpsSet(uint16 oldBps, uint16 newBps);
|
|
141
|
+
|
|
142
|
+
/// @notice Emitted when the exit (withdraw/redeem) fee rate is changed
|
|
143
|
+
/// @param oldBps Previous rate in BPS
|
|
144
|
+
/// @param newBps New rate in BPS
|
|
145
|
+
event RedeemFeeBpsSet(uint16 oldBps, uint16 newBps);
|
|
146
|
+
|
|
147
|
+
/// @notice Emitted when the fee recipient is changed; pending fees minted to OLD recipient first
|
|
148
|
+
/// @param oldRecipient Previous recipient
|
|
149
|
+
/// @param newRecipient New recipient
|
|
150
|
+
event FeeRecipientSet(address oldRecipient, address newRecipient);
|
|
151
|
+
|
|
152
|
+
/// @notice Emitted when fee shares are minted in an accrual
|
|
153
|
+
/// @param managementShares Shares minted for the management fee
|
|
154
|
+
/// @param performanceShares Shares minted for the performance fee
|
|
155
|
+
/// @param totalShares Sum of the two
|
|
156
|
+
event FeesAccrued(uint256 managementShares, uint256 performanceShares, uint256 totalShares);
|
|
157
|
+
|
|
158
|
+
/// @notice Emitted when the performance HWM moves up. Units: `totalAssets × 1e18 / totalSupply`
|
|
159
|
+
/// @param oldHwm Previous HWM
|
|
160
|
+
/// @param newHwm New HWM
|
|
161
|
+
event HighWaterMarkUpdated(uint256 oldHwm, uint256 newHwm);
|
|
162
|
+
|
|
163
|
+
/// @notice Emitted when a stray-token balance is rescued via `sweep()`
|
|
164
|
+
/// @param token ERC-20 that was swept
|
|
165
|
+
/// @param to Recipient of the balance
|
|
166
|
+
/// @param amount Amount transferred
|
|
167
|
+
event Swept(address indexed token, address indexed to, uint256 amount);
|
|
168
|
+
|
|
169
|
+
/// @notice Emitted when a supplier records disclaimer consent alongside a deposit / mint
|
|
170
|
+
/// @param supplier Caller who consented (the depositor / minter)
|
|
171
|
+
/// @param receiver Address that received the minted shares
|
|
172
|
+
/// @param consentHash keccak256 hash of the disclaimer content the supplier consented to
|
|
173
|
+
event ConsentRecorded(address indexed supplier, address indexed receiver, bytes32 indexed consentHash);
|
|
174
|
+
|
|
175
|
+
// --------------------------------- Errors --------------------------------
|
|
176
|
+
|
|
177
|
+
/// @notice Error thrown when deposit / mint exceeds aggregate spare cap across unpaused YieldGroups
|
|
178
|
+
/// @param requested Asset units requested
|
|
179
|
+
/// @param maxAvailable Aggregate spare cap at revert time
|
|
180
|
+
error HubCapacityExceeded(uint256 requested, uint256 maxAvailable);
|
|
181
|
+
|
|
182
|
+
/// @notice Error thrown when withdraw / redeem exceeds aggregate liquid funds (withdraw queue plus Hub idle)
|
|
183
|
+
/// @param requested Asset units requested
|
|
184
|
+
/// @param available Aggregate liquid funds at revert time
|
|
185
|
+
error HubInsufficientLiquidity(uint256 requested, uint256 available);
|
|
186
|
+
|
|
187
|
+
/// @notice Error thrown when a YieldGroup returns fewer assets than requested on a deposit or withdraw leg
|
|
188
|
+
/// @param yieldGroup YieldGroup that under-filled
|
|
189
|
+
/// @param requested Asset units requested
|
|
190
|
+
/// @param actual Asset units delivered
|
|
191
|
+
error YieldGroupUnderfilled(address yieldGroup, uint256 requested, uint256 actual);
|
|
192
|
+
|
|
193
|
+
/// @notice Error thrown when withdraw / redeem exceeds the per-transaction cap
|
|
194
|
+
/// @param requested Asset units requested
|
|
195
|
+
/// @param perRequestCap Current value of `maxWithdrawalSize()`
|
|
196
|
+
error HubWithdrawCapExceeded(uint256 requested, uint256 perRequestCap);
|
|
197
|
+
|
|
198
|
+
/// @notice Error thrown when a user-facing mutating call is attempted while the Hub is paused
|
|
199
|
+
error HubPaused();
|
|
200
|
+
|
|
201
|
+
/// @notice Error thrown when a deposit or reallocate-deposit leg targets a paused YieldGroup
|
|
202
|
+
/// @param yieldGroup YieldGroup whose pause flag blocked the routing
|
|
203
|
+
error YieldGroupPaused(address yieldGroup);
|
|
204
|
+
|
|
205
|
+
/// @notice Error thrown when an operation targets a YieldGroup that is not in the registry
|
|
206
|
+
/// @param yieldGroup Address that failed the registry lookup
|
|
207
|
+
error YieldGroupNotRegistered(address yieldGroup);
|
|
208
|
+
|
|
209
|
+
/// @notice Error thrown when `addYieldGroup()` is called with an already-registered YieldGroup
|
|
210
|
+
/// @param yieldGroup Address that is already registered
|
|
211
|
+
error YieldGroupAlreadyRegistered(address yieldGroup);
|
|
212
|
+
|
|
213
|
+
/// @notice Error thrown when `removeYieldGroup()` is called while the YieldGroup still holds a non-zero balance
|
|
214
|
+
/// @param yieldGroup YieldGroup attempted to be removed
|
|
215
|
+
/// @param balance Current `yieldGroup.totalAssets()` preventing removal
|
|
216
|
+
error YieldGroupHasBalance(address yieldGroup, uint256 balance);
|
|
217
|
+
|
|
218
|
+
/// @notice Error thrown when a YieldGroup's `asset()` does not match the Hub's underlying
|
|
219
|
+
/// @param yieldGroup YieldGroup under inspection
|
|
220
|
+
/// @param yieldGroupAsset `asset()` reported by the YieldGroup
|
|
221
|
+
/// @param hubAsset Hub's own `asset()`
|
|
222
|
+
error YieldGroupAssetMismatch(address yieldGroup, address yieldGroupAsset, address hubAsset);
|
|
223
|
+
|
|
224
|
+
/// @notice Error thrown when a cap pair is invalid (e.g. percentage > 100%)
|
|
225
|
+
/// @param absoluteCap Offending absolute cap
|
|
226
|
+
/// @param percentageCapBps Offending percentage cap in BPS
|
|
227
|
+
error InvalidCap(uint256 absoluteCap, uint16 percentageCapBps);
|
|
228
|
+
|
|
229
|
+
/// @notice Error thrown when a queue contains duplicates or references an unregistered YieldGroup
|
|
230
|
+
error InvalidQueue();
|
|
231
|
+
|
|
232
|
+
/// @notice Error thrown when `reallocate()` withdraw and deposit sums do not match
|
|
233
|
+
/// @param withdrawSum Sum of withdraw-leg `amount` entries
|
|
234
|
+
/// @param depositSum Sum of deposit-leg `amount` entries
|
|
235
|
+
error ReallocateImbalanced(uint256 withdrawSum, uint256 depositSum);
|
|
236
|
+
|
|
237
|
+
/// @notice Error thrown when a `setOuterWithdrawQueue` replacement would drop a registered
|
|
238
|
+
/// YieldGroup that still custodies a balance, stranding its redeemable value. Drain the
|
|
239
|
+
/// YieldGroup via reallocate before removing it from the withdraw queue.
|
|
240
|
+
/// @param yieldGroup Funded YieldGroup missing from the candidate withdraw queue
|
|
241
|
+
error WithdrawQueueOmitsFundedYieldGroup(address yieldGroup);
|
|
242
|
+
|
|
243
|
+
/// @notice Error thrown when `sweep()` is called with `token == asset()`
|
|
244
|
+
error SweepProtectedAsset();
|
|
245
|
+
|
|
246
|
+
/// @notice Error thrown when a required non-zero address parameter was zero
|
|
247
|
+
error ZeroAddress();
|
|
248
|
+
|
|
249
|
+
/// @notice Error thrown when a required non-zero amount parameter was zero
|
|
250
|
+
error ZeroAmount();
|
|
251
|
+
|
|
252
|
+
/// @notice Error thrown when `decimalsOffset_` at `initialize()` exceeded `MAX_DECIMALS_OFFSET`
|
|
253
|
+
error InvalidDecimalsOffset();
|
|
254
|
+
|
|
255
|
+
/// @notice Error thrown when a fee rate exceeded `MAX_FEE_BPS`
|
|
256
|
+
/// @param bps Offending BPS rate
|
|
257
|
+
error InvalidFeeBps(uint16 bps);
|
|
258
|
+
|
|
259
|
+
/// @notice Error thrown when `raise*` is called with a value not strictly greater than the current one
|
|
260
|
+
error NotIncreasing();
|
|
261
|
+
|
|
262
|
+
/// @notice Error thrown when `lower*` is called with a value not strictly less than the current one
|
|
263
|
+
error NotDecreasing();
|
|
264
|
+
|
|
265
|
+
// ----------------------- YieldGroup registry (governance) --------------------
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* @notice Add a YieldGroup to the registry with initial caps
|
|
269
|
+
* @dev ACM role `"addYieldGroup(address,uint256,uint16)"` (VIP).
|
|
270
|
+
* @param yieldGroup YieldGroup contract address
|
|
271
|
+
* @param absoluteCap Initial absolute cap in asset units
|
|
272
|
+
* @param percentageCapBps Initial percentage cap in BPS
|
|
273
|
+
*/
|
|
274
|
+
function addYieldGroup(address yieldGroup, uint256 absoluteCap, uint16 percentageCapBps) external;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* @notice Remove a YieldGroup from the registry
|
|
278
|
+
* @dev ACM role `"removeYieldGroup(address)"` (VIP).
|
|
279
|
+
* @param yieldGroup YieldGroup to remove
|
|
280
|
+
*/
|
|
281
|
+
function removeYieldGroup(address yieldGroup) external;
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* @notice Raise a YieldGroup's caps
|
|
285
|
+
* @dev ACM role `"raiseYieldGroupCap(address,uint256,uint16)"` (Guardian or VIP) — raising is loosening.
|
|
286
|
+
* @param yieldGroup YieldGroup whose caps are being raised
|
|
287
|
+
* @param absoluteCap New absolute cap in asset units
|
|
288
|
+
* @param percentageCapBps New percentage cap in BPS
|
|
289
|
+
*/
|
|
290
|
+
function raiseYieldGroupCap(address yieldGroup, uint256 absoluteCap, uint16 percentageCapBps) external;
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @notice Lower a YieldGroup's caps
|
|
294
|
+
* @dev ACM role `"lowerYieldGroupCap(address,uint256,uint16)"` (Operator or VIP) — tightening.
|
|
295
|
+
* @param yieldGroup YieldGroup whose caps are being lowered
|
|
296
|
+
* @param absoluteCap New absolute cap in asset units
|
|
297
|
+
* @param percentageCapBps New percentage cap in BPS
|
|
298
|
+
*/
|
|
299
|
+
function lowerYieldGroupCap(address yieldGroup, uint256 absoluteCap, uint16 percentageCapBps) external;
|
|
300
|
+
|
|
301
|
+
// ----------------------- Outer queues (Operator) -------------------------
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* @notice Replace the deposit routing order
|
|
305
|
+
* @dev ACM role `"setOuterDepositQueue(address[])"` (Operator). Operator responsibility: keep
|
|
306
|
+
* every queue member in the outer withdraw queue. A member absent from the withdraw queue is
|
|
307
|
+
* funded by deposits but not reachable by the normal redeem path until it is (re)added there;
|
|
308
|
+
* recovery is one tx and lossless. Not enforced on-chain.
|
|
309
|
+
* @param queue Full replacement queue in deposit-priority order
|
|
310
|
+
*/
|
|
311
|
+
function setOuterDepositQueue(address[] calldata queue) external;
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* @notice Replace the withdraw routing order
|
|
315
|
+
* @dev ACM role `"setOuterWithdrawQueue(address[])"` (Operator). Reverts
|
|
316
|
+
* {WithdrawQueueOmitsFundedYieldGroup} if a candidate queue drops a YieldGroup still holding a
|
|
317
|
+
* balance.
|
|
318
|
+
* @param queue Full replacement queue in withdraw-priority order
|
|
319
|
+
*/
|
|
320
|
+
function setOuterWithdrawQueue(address[] calldata queue) external;
|
|
321
|
+
|
|
322
|
+
// ----------------------- Reallocate (Operator) ---------------------------
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* @notice Atomically rebalance assets across YieldGroups — and, optionally, across specific
|
|
326
|
+
* resources within a YieldGroup. Withdraw legs execute first, deposit legs second.
|
|
327
|
+
* `Σ withdraws == Σ deposits` is enforced.
|
|
328
|
+
* @dev ACM role `"reallocate((address,address,uint256)[],(address,address,uint256)[])"`
|
|
329
|
+
* (Operator). Each leg may name a specific `resource` to target one market/vault directly, or
|
|
330
|
+
* pass `address(0)` to route through the YieldGroup's inner queue (the original
|
|
331
|
+
* behavior). Setting both legs to the same `yieldGroup` performs an intra-YieldGroup move
|
|
332
|
+
* (e.g. vUSDT_v1 → vUSDT_v2). Honors per-YieldGroup caps and pause on the deposit side.
|
|
333
|
+
* Emits {WithdrawRouted} per pull and {DepositRouted} per push at the YieldGroup level;
|
|
334
|
+
* the targeted YieldGroup additionally emits its own resource-level routing event.
|
|
335
|
+
* @param withdraws Ordered list of (YieldGroup, resource, amount) legs to pull from.
|
|
336
|
+
* @param deposits Ordered list of (YieldGroup, resource, amount) legs to push into.
|
|
337
|
+
*/
|
|
338
|
+
function reallocate(ReallocateLeg[] calldata withdraws, ReallocateLeg[] calldata deposits) external;
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* @notice Emergency variant of {reallocate} that stays callable while the Hub is paused, so
|
|
342
|
+
* governance can wind down / rebalance a stressed position during a freeze.
|
|
343
|
+
* @dev ACM role `"emergencyReallocate((address,address,uint256)[],(address,address,uint256)[])"`
|
|
344
|
+
* (Guardian or VIP/governance — NOT the Operator: this is the one fund-moving lever that bypasses the
|
|
345
|
+
* Hub pause, so it carries a separate role the Operator does not hold). Same net-zero
|
|
346
|
+
* (`Σ withdraws == Σ deposits`) semantics as {reallocate}; fee accrual is skipped while the
|
|
347
|
+
* Hub is paused so the frozen window is not charged.
|
|
348
|
+
* @param withdraws Ordered list of (yieldGroup, resource, amount) legs to pull from.
|
|
349
|
+
* @param deposits Ordered list of (yieldGroup, resource, amount) legs to push into.
|
|
350
|
+
*/
|
|
351
|
+
function emergencyReallocate(ReallocateLeg[] calldata withdraws, ReallocateLeg[] calldata deposits) external;
|
|
352
|
+
|
|
353
|
+
// ----------------------- Pause (asymmetric) ------------------------------
|
|
354
|
+
|
|
355
|
+
/// @notice Pause the Hub
|
|
356
|
+
/// @dev ACM role `"pauseHub()"` (Operator, Guardian, or VIP).
|
|
357
|
+
function pauseHub() external;
|
|
358
|
+
|
|
359
|
+
/// @notice Unpause the Hub
|
|
360
|
+
/// @dev ACM role `"unpauseHub()"` (VIP).
|
|
361
|
+
function unpauseHub() external;
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* @notice Pause routing to a specific YieldGroup
|
|
365
|
+
* @dev ACM role `"pauseYieldGroup(address)"` (Operator or VIP).
|
|
366
|
+
* @param yieldGroup YieldGroup to pause
|
|
367
|
+
*/
|
|
368
|
+
function pauseYieldGroup(address yieldGroup) external;
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* @notice Unpause routing to a specific YieldGroup
|
|
372
|
+
* @dev ACM role `"unpauseYieldGroup(address)"` (VIP).
|
|
373
|
+
* @param yieldGroup YieldGroup to unpause
|
|
374
|
+
*/
|
|
375
|
+
function unpauseYieldGroup(address yieldGroup) external;
|
|
376
|
+
|
|
377
|
+
// ----------------------- Per-request withdraw cap ------------------------
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* @notice Raise the per-transaction withdraw cap
|
|
381
|
+
* @dev ACM role `"raiseMaxWithdrawalSize(uint256)"` (VIP) — raising is loosening.
|
|
382
|
+
* @param newSize New cap in asset units
|
|
383
|
+
*/
|
|
384
|
+
function raiseMaxWithdrawalSize(uint256 newSize) external;
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* @notice Lower the per-transaction withdraw cap
|
|
388
|
+
* @dev ACM role `"lowerMaxWithdrawalSize(uint256)"` (Operator or VIP) — tightening.
|
|
389
|
+
* @param newSize New cap in asset units
|
|
390
|
+
*/
|
|
391
|
+
function lowerMaxWithdrawalSize(uint256 newSize) external;
|
|
392
|
+
|
|
393
|
+
// --------------------------------- Fees ----------------------------------
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* @notice Set the management fee rate
|
|
397
|
+
* @dev ACM role `"setManagementFeeBps(uint16)"` (VIP). Pending fees accrue at the OLD rate
|
|
398
|
+
* first. Capped at `MAX_FEE_BPS`.
|
|
399
|
+
* @param bps New management fee rate in BPS
|
|
400
|
+
*/
|
|
401
|
+
function setManagementFeeBps(uint16 bps) external;
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* @notice Set the performance fee rate
|
|
405
|
+
* @dev ACM role `"setPerformanceFeeBps(uint16)"` (VIP). Pending fees accrue at the OLD rate
|
|
406
|
+
* first. Capped at `MAX_FEE_BPS`.
|
|
407
|
+
* @param bps New performance fee rate in BPS
|
|
408
|
+
*/
|
|
409
|
+
function setPerformanceFeeBps(uint16 bps) external;
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* @notice Set the exit (withdraw/redeem) fee rate, retained in the vault and socialised to
|
|
413
|
+
* remaining LPs. Anti-sandwich governance lever; default 0.
|
|
414
|
+
* @param bps New exit fee rate in BPS (≤ 5%)
|
|
415
|
+
*/
|
|
416
|
+
function setRedeemFeeBps(uint16 bps) external;
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* @notice Current exit (withdraw/redeem) fee rate in BPS.
|
|
420
|
+
* @return bps Exit fee rate in BPS (0 by default).
|
|
421
|
+
*/
|
|
422
|
+
function redeemFeeBps() external view returns (uint16 bps);
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* @notice Set the fee-share recipient
|
|
426
|
+
* @dev ACM role `"setFeeRecipient(address)"` (VIP). Pending fees mint to the OLD recipient
|
|
427
|
+
* first; `address(0)` disables fee minting.
|
|
428
|
+
* @param recipient New fee-share recipient
|
|
429
|
+
*/
|
|
430
|
+
function setFeeRecipient(address recipient) external;
|
|
431
|
+
|
|
432
|
+
/// @notice Public poke that brings fee state up to date
|
|
433
|
+
/// @dev Permissionless.
|
|
434
|
+
function accrueFees() external;
|
|
435
|
+
|
|
436
|
+
// --------------------------------- Sweep ----------------------------------
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* @notice Forward the Hub's full balance of an arbitrary ERC-20 to a recipient
|
|
440
|
+
* @dev ACM role `"sweep(address,address)"` (VIP). Reverts {SweepProtectedAsset} if
|
|
441
|
+
* `token == asset()` — the underlying can never be swept. Callable while paused.
|
|
442
|
+
* @param token ERC-20 to sweep
|
|
443
|
+
* @param to Recipient of the balance
|
|
444
|
+
*/
|
|
445
|
+
function sweep(address token, address to) external;
|
|
446
|
+
|
|
447
|
+
// ----------------------------- Supplier functions ------------------------
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* @notice Deposit assets and optionally record the supplier's disclaimer consent on-chain in the
|
|
451
|
+
* same transaction. Thin wrapper over {deposit}.
|
|
452
|
+
* @dev The consent hash is optional: passing `bytes32(0)` skips the emit and behaves like a plain
|
|
453
|
+
* {deposit}, so the frontend can use a single entry point whether or not a disclaimer applies.
|
|
454
|
+
* A non-zero hash emits {ConsentRecorded} before delegating, so it is rolled back with the
|
|
455
|
+
* transaction if the delegated {deposit} reverts. All cap / pause / accrual gating is enforced
|
|
456
|
+
* by {deposit}; this wrapper adds no other behaviour.
|
|
457
|
+
* @param assets Amount of underlying to deposit
|
|
458
|
+
* @param receiver Address to receive the minted shares
|
|
459
|
+
* @param consentHash keccak256 hash of the disclaimer content the supplier consented to;
|
|
460
|
+
* `bytes32(0)` skips recording (no event emitted)
|
|
461
|
+
* @return shares Shares minted to `receiver`
|
|
462
|
+
* @custom:event ConsentRecorded Emitted with the supplier, receiver, and hash when consentHash is non-zero
|
|
463
|
+
* @custom:error Throws HubPaused if the Hub is paused
|
|
464
|
+
* @custom:error Throws HubCapacityExceeded if aggregate spare cap across unpaused YieldGroups is insufficient
|
|
465
|
+
*/
|
|
466
|
+
function depositWithConsent(uint256 assets, address receiver, bytes32 consentHash) external returns (uint256 shares);
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* @notice Mint shares and optionally record the supplier's disclaimer consent on-chain in the
|
|
470
|
+
* same transaction. Thin wrapper over {mint}.
|
|
471
|
+
* @dev The consent hash is optional: passing `bytes32(0)` skips the emit and behaves like a plain
|
|
472
|
+
* {mint}, so the frontend can use a single entry point whether or not a disclaimer applies. A
|
|
473
|
+
* non-zero hash emits {ConsentRecorded} before delegating, so it is rolled back with the
|
|
474
|
+
* transaction if the delegated {mint} reverts. All cap / pause / accrual gating is enforced by
|
|
475
|
+
* {mint}; this wrapper adds no other behaviour.
|
|
476
|
+
* @param shares Amount of shares to mint
|
|
477
|
+
* @param receiver Address to receive the minted shares
|
|
478
|
+
* @param consentHash keccak256 hash of the disclaimer content the supplier consented to;
|
|
479
|
+
* `bytes32(0)` skips recording (no event emitted)
|
|
480
|
+
* @return assets Underlying pulled from the caller
|
|
481
|
+
* @custom:event ConsentRecorded Emitted with the supplier, receiver, and hash when consentHash is non-zero
|
|
482
|
+
* @custom:error Throws HubPaused if the Hub is paused
|
|
483
|
+
* @custom:error Throws HubCapacityExceeded if aggregate spare cap is insufficient for the shares requested
|
|
484
|
+
*/
|
|
485
|
+
function mintWithConsent(uint256 shares, address receiver, bytes32 consentHash) external returns (uint256 assets);
|
|
486
|
+
|
|
487
|
+
// --------------------------------- Views ---------------------------------
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* @notice Full config struct for a YieldGroup
|
|
491
|
+
* @param yieldGroup Address to look up
|
|
492
|
+
* @return config Stored config
|
|
493
|
+
*/
|
|
494
|
+
function yieldGroupConfig(address yieldGroup) external view returns (YieldGroupConfig memory config);
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* @notice Live effective cap for a YieldGroup
|
|
498
|
+
* @param yieldGroup Address to look up
|
|
499
|
+
* @return cap Effective cap in asset units
|
|
500
|
+
*/
|
|
501
|
+
function yieldGroupEffectiveCap(address yieldGroup) external view returns (uint256 cap);
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* @notice Registered YieldGroups
|
|
505
|
+
* @return yieldGroups Storage copy of the registry array
|
|
506
|
+
*/
|
|
507
|
+
function registeredYieldGroups() external view returns (address[] memory yieldGroups);
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* @notice Current deposit routing order
|
|
511
|
+
* @return queue Storage copy of the deposit queue
|
|
512
|
+
*/
|
|
513
|
+
function outerDepositQueue() external view returns (address[] memory queue);
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* @notice Current withdraw routing order
|
|
517
|
+
* @return queue Storage copy of the withdraw queue
|
|
518
|
+
*/
|
|
519
|
+
function outerWithdrawQueue() external view returns (address[] memory queue);
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* @notice Per-transaction withdraw cap in asset units
|
|
523
|
+
* @return size Cap value
|
|
524
|
+
*/
|
|
525
|
+
function maxWithdrawalSize() external view returns (uint256 size);
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* @notice Hub-level pause state
|
|
529
|
+
* @return paused True if `pauseHub()` is in effect
|
|
530
|
+
*/
|
|
531
|
+
function hubPaused() external view returns (bool paused);
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* @notice Recipient of newly-minted fee shares
|
|
535
|
+
* @return recipient Fee recipient
|
|
536
|
+
*/
|
|
537
|
+
function feeRecipient() external view returns (address recipient);
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* @notice Current fee rates in BPS
|
|
541
|
+
* @return managementBps Management fee rate
|
|
542
|
+
* @return performanceBps Performance fee rate
|
|
543
|
+
*/
|
|
544
|
+
function feeBps() external view returns (uint16 managementBps, uint16 performanceBps);
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* @notice Performance HWM in share-price units
|
|
548
|
+
* @return hwm HWM value
|
|
549
|
+
*/
|
|
550
|
+
function highWaterMarkPerShare() external view returns (uint256 hwm);
|
|
551
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.25;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @title IHubRegistry
|
|
6
|
+
* @author Venus
|
|
7
|
+
* @notice External interface for the chain-level Hub directory. The registry is the single
|
|
8
|
+
* on-chain discovery root for the Liquidity Hub topology: off-chain indexers watch
|
|
9
|
+
* {HubAdded} / {HubRemoved} here, then follow each Hub's own `YieldGroupAdded` /
|
|
10
|
+
* `YieldGroupRemoved` events to reconstruct the full hub → YieldGroup graph. One
|
|
11
|
+
* registry per chain; exactly one active Hub per asset.
|
|
12
|
+
* @dev Conventions:
|
|
13
|
+
* - Hubs are deployed outside the registry (the `deploy/06_DeployAssetVault` bootstrap
|
|
14
|
+
* script) and registered via `addHub`, which derives the asset key from
|
|
15
|
+
* `IHub(hub).asset()`.
|
|
16
|
+
* - Indexer correctness contract (NORMATIVE): on every {HubAdded}, an indexer MUST seed
|
|
17
|
+
* that Hub's YieldGroup set from state (`registeredYieldGroups()` + per-group config
|
|
18
|
+
* views). Event ordering — the onboarding VIP places `addHub` before the Hub's
|
|
19
|
+
* `addYieldGroup` calls in one atomic transaction, so {HubAdded} lands at a lower log
|
|
20
|
+
* index — is a latency optimization only, NOT a correctness requirement: it is a VIP
|
|
21
|
+
* convention that nothing on-chain enforces, and Hubs configured before registration
|
|
22
|
+
* (e.g. pre-registry deployments) emit `YieldGroupAdded` before {HubAdded} regardless.
|
|
23
|
+
* - The registry holds no funds and never routes assets.
|
|
24
|
+
* - Permissions are gated by `AccessControlManagerV8`: each governance-gated function
|
|
25
|
+
* calls `_checkAccessAllowed` with its literal function-signature string (e.g.
|
|
26
|
+
* `"addHub(address)"`), which is the ACM role for that function.
|
|
27
|
+
* - Replacing an asset's hub is an explicit `removeHub` followed by `addHub` — two
|
|
28
|
+
* events, so indexers never observe an implicit swap.
|
|
29
|
+
*/
|
|
30
|
+
interface IHubRegistry {
|
|
31
|
+
// --------------------------------- Events --------------------------------
|
|
32
|
+
|
|
33
|
+
/// @notice Emitted when a Hub is registered for its underlying asset
|
|
34
|
+
/// @param asset Underlying asset of the Hub (`IHub(hub).asset()`)
|
|
35
|
+
/// @param hub Newly-registered Hub
|
|
36
|
+
event HubAdded(address indexed asset, address indexed hub);
|
|
37
|
+
|
|
38
|
+
/// @notice Emitted when a Hub is removed from the registry
|
|
39
|
+
/// @param asset Underlying asset the Hub was registered under
|
|
40
|
+
/// @param hub Removed Hub
|
|
41
|
+
event HubRemoved(address indexed asset, address indexed hub);
|
|
42
|
+
|
|
43
|
+
// --------------------------------- Errors --------------------------------
|
|
44
|
+
|
|
45
|
+
/// @notice Error thrown when a required non-zero address parameter was zero
|
|
46
|
+
error ZeroAddress();
|
|
47
|
+
|
|
48
|
+
/// @notice Error thrown when `addHub()` is called with an already-registered Hub
|
|
49
|
+
/// @param hub Address that is already registered
|
|
50
|
+
error HubAlreadyRegistered(address hub);
|
|
51
|
+
|
|
52
|
+
/// @notice Error thrown when `addHub()` would register a second Hub for an asset that
|
|
53
|
+
/// already has one. Replace explicitly: `removeHub(existingHub)` then `addHub(hub)`.
|
|
54
|
+
/// @param asset Asset that is already served
|
|
55
|
+
/// @param existingHub Hub currently registered for `asset`
|
|
56
|
+
error AssetAlreadyHasHub(address asset, address existingHub);
|
|
57
|
+
|
|
58
|
+
/// @notice Error thrown when `removeHub()` is called with a Hub that is not in the registry
|
|
59
|
+
/// @param hub Address that failed the registry lookup
|
|
60
|
+
error HubNotRegistered(address hub);
|
|
61
|
+
|
|
62
|
+
// ----------------------------- Mutating (governance) ---------------------
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @notice Register an externally-deployed Hub under its underlying asset
|
|
66
|
+
* @dev ACM role `"addHub(address)"` (VIP). Reads `IHub(hub).asset()` to derive the key.
|
|
67
|
+
* In an onboarding VIP, order this call BEFORE the Hub's `addYieldGroup` calls so
|
|
68
|
+
* {HubAdded} precedes every `YieldGroupAdded` in the same transaction (a latency
|
|
69
|
+
* optimization — indexers MUST state-seed on {HubAdded} regardless; see the
|
|
70
|
+
* interface-level indexer contract).
|
|
71
|
+
* @param hub Hub contract address
|
|
72
|
+
*/
|
|
73
|
+
function addHub(address hub) external;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @notice Remove a Hub from the registry
|
|
77
|
+
* @dev ACM role `"removeHub(address)"` (VIP).
|
|
78
|
+
* @param hub Hub to remove
|
|
79
|
+
*/
|
|
80
|
+
function removeHub(address hub) external;
|
|
81
|
+
|
|
82
|
+
// --------------------------------- Views ---------------------------------
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @notice Active Hub for an asset
|
|
86
|
+
* @param asset Underlying asset to look up
|
|
87
|
+
* @return hub Registered Hub, or `address(0)` if the asset has none
|
|
88
|
+
*/
|
|
89
|
+
function hubForAsset(address asset) external view returns (address hub);
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @notice The asset a Hub is registered under (reverse of {hubForAsset})
|
|
93
|
+
* @dev Returns the registry's asset-of-record, `address(0)` if `hub` is not registered — so it
|
|
94
|
+
* doubles as a registration check without a STATICCALL into a possibly-bricked Hub, and is
|
|
95
|
+
* authoritative even after a Hub is removed (unlike `IHub(hub).asset()`, which still reports
|
|
96
|
+
* the underlying).
|
|
97
|
+
* @param hub Hub to look up
|
|
98
|
+
* @return asset Underlying asset the hub is registered under, or `address(0)` if not registered
|
|
99
|
+
*/
|
|
100
|
+
function assetForHub(address hub) external view returns (address asset);
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @notice All registered Hubs
|
|
104
|
+
* @return hubs Storage copy of the registry array
|
|
105
|
+
*/
|
|
106
|
+
function getHubs() external view returns (address[] memory hubs);
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @notice Number of registered Hubs
|
|
110
|
+
* @return count Length of the registry array
|
|
111
|
+
*/
|
|
112
|
+
function getHubsCount() external view returns (uint256 count);
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @notice Whether an address is a registered Hub
|
|
116
|
+
* @param hub Address to check
|
|
117
|
+
* @return registered True iff `hub` is present in `getHubs()`
|
|
118
|
+
*/
|
|
119
|
+
function isHub(address hub) external view returns (bool registered);
|
|
120
|
+
}
|