@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,173 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity 0.8.25;
|
|
3
|
+
|
|
4
|
+
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
5
|
+
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
6
|
+
|
|
7
|
+
import { IResourceAdapter } from "../interfaces/IResourceAdapter.sol";
|
|
8
|
+
import { IFToken } from "../interfaces/external/IFToken.sol";
|
|
9
|
+
import { IFluidLendingResolver } from "../interfaces/external/IFluidLendingResolver.sol";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @title AdapterFlux
|
|
13
|
+
* @author Venus
|
|
14
|
+
* @notice Stateless adapter for Fluid lending fTokens (ERC-4626). ONE deployment serves every
|
|
15
|
+
* YieldGroupFlux that registers an fToken — there is no per-(YieldGroup, fToken) instance,
|
|
16
|
+
* no proxy, no clone factory.
|
|
17
|
+
* @dev Dispatch model: mutating functions (`deposit`, `withdraw`) MUST be invoked via DELEGATECALL
|
|
18
|
+
* from a YieldGroupFlux. They execute in the YieldGroup's storage context, so ERC-4626 share
|
|
19
|
+
* credits and debits land on the YieldGroup, not this adapter. View functions are invoked via
|
|
20
|
+
* normal CALL / STATICCALL with an explicit `holder` argument.
|
|
21
|
+
*
|
|
22
|
+
* Storage-safety invariants enforced by this contract:
|
|
23
|
+
* 1. Zero `internal`/`private`/`public` state variables are declared. Only `immutable` values
|
|
24
|
+
* are used (`_ADAPTER_SELF` and `LENDING_RESOLVER`). Immutables live in bytecode, not
|
|
25
|
+
* storage slots, so they're delegatecall-safe.
|
|
26
|
+
* 2. No inline assembly performs `sstore`.
|
|
27
|
+
* 3. External calls go to the supplied `resource` (fToken), its `asset()`, or the trusted,
|
|
28
|
+
* chain-fixed Fluid `LENDING_RESOLVER` (read-only). No arbitrary user-supplied target.
|
|
29
|
+
* 4. {onlyDelegateCall} reverts when a mutating function is invoked directly on the adapter,
|
|
30
|
+
* preventing accidents that would orphan shares here.
|
|
31
|
+
*
|
|
32
|
+
* No treasury-fee handling: a Fluid fToken delivers exactly the requested `assets` on
|
|
33
|
+
* withdraw (the Liquidity layer takes its revenue cut in the supply rate, not per-redeem).
|
|
34
|
+
* No gross-up needed.
|
|
35
|
+
*
|
|
36
|
+
* No lifecycle: fTokens are perpetual, so unlike `AdapterFRV` there is no state-machine
|
|
37
|
+
* pre-advance — the YieldGroup calls the adapter directly.
|
|
38
|
+
*/
|
|
39
|
+
contract AdapterFlux is IResourceAdapter {
|
|
40
|
+
using SafeERC20 for IERC20;
|
|
41
|
+
|
|
42
|
+
// ============================== State (immutable only) ====================
|
|
43
|
+
|
|
44
|
+
/// @notice This adapter's own address, captured at deployment. Used by {onlyDelegateCall} to
|
|
45
|
+
/// detect direct invocation. Immutables live in bytecode, not storage.
|
|
46
|
+
address private immutable _ADAPTER_SELF;
|
|
47
|
+
|
|
48
|
+
/// @notice Fluid periphery `LendingResolver` address (chain-fixed). Read-only yieldGroup for spot
|
|
49
|
+
/// supply APR + reward rate in `spotAPYBps`.
|
|
50
|
+
address public immutable LENDING_RESOLVER;
|
|
51
|
+
|
|
52
|
+
// ============================== Errors ===================================
|
|
53
|
+
|
|
54
|
+
/// @notice A mutating function was invoked directly (not via delegatecall).
|
|
55
|
+
error NotDelegateCall();
|
|
56
|
+
|
|
57
|
+
/// @notice The supplied resolver address was the zero address at construction.
|
|
58
|
+
error ZeroResolver();
|
|
59
|
+
|
|
60
|
+
// ============================== Modifiers ================================
|
|
61
|
+
|
|
62
|
+
/// @notice Reverts {NotDelegateCall} when the call is not arriving via delegatecall.
|
|
63
|
+
/// @dev During a delegatecall, `address(this)` is the caller; during a direct call it equals
|
|
64
|
+
/// `_ADAPTER_SELF` (captured at construction).
|
|
65
|
+
modifier onlyDelegateCall() {
|
|
66
|
+
if (address(this) == _ADAPTER_SELF) revert NotDelegateCall();
|
|
67
|
+
_;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ============================== Constructor ==============================
|
|
71
|
+
|
|
72
|
+
/// @param lendingResolver_ Fluid `LendingResolver` for this chain.
|
|
73
|
+
constructor(address lendingResolver_) {
|
|
74
|
+
if (lendingResolver_ == address(0)) revert ZeroResolver();
|
|
75
|
+
_ADAPTER_SELF = address(this);
|
|
76
|
+
LENDING_RESOLVER = lendingResolver_;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ============================== External — mutating =======================
|
|
80
|
+
|
|
81
|
+
/// @inheritdoc IResourceAdapter
|
|
82
|
+
/// @dev `address(this)` here is the YieldGroup (delegatecall context). The YieldGroup already
|
|
83
|
+
/// holds `amount` of underlying; we approve the fToken, which then pulls `amount` from the
|
|
84
|
+
/// YieldGroup via its `liquidityCallback`. Shares are minted to the YieldGroup.
|
|
85
|
+
function deposit(address resource, uint256 amount) external override onlyDelegateCall returns (uint256 deposited) {
|
|
86
|
+
IERC20 assetToken = IERC20(IFToken(resource).asset());
|
|
87
|
+
assetToken.forceApprove(resource, amount);
|
|
88
|
+
IFToken(resource).deposit(amount, address(this));
|
|
89
|
+
return amount;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// @inheritdoc IResourceAdapter
|
|
93
|
+
/// @dev `address(this)` here is the YieldGroup. `fToken.withdraw` burns its (YieldGroup's)
|
|
94
|
+
/// shares and delivers exactly `amount` of underlying directly to `to`.
|
|
95
|
+
function withdraw(address resource, uint256 amount, address to) external override onlyDelegateCall {
|
|
96
|
+
IFToken(resource).withdraw(amount, to, address(this));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// @inheritdoc IResourceAdapter
|
|
100
|
+
/// @dev No-op: Fluid's live `previewRedeem` leaves no block-lazy stored rate to freshen.
|
|
101
|
+
// solhint-disable-next-line no-empty-blocks
|
|
102
|
+
function accrue(address resource) external override { }
|
|
103
|
+
|
|
104
|
+
// ============================== External — view ==========================
|
|
105
|
+
|
|
106
|
+
/// @inheritdoc IResourceAdapter
|
|
107
|
+
function asset(address resource) external view override returns (address) {
|
|
108
|
+
return IFToken(resource).asset();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/// @inheritdoc IResourceAdapter
|
|
112
|
+
/// @dev `previewRedeem(balanceOf(holder))` — the per-holder position value (shares × token
|
|
113
|
+
/// exchange price, including accrued rewards).
|
|
114
|
+
function totalAssets(address resource, address holder) external view override returns (uint256) {
|
|
115
|
+
uint256 shares = IFToken(resource).balanceOf(holder);
|
|
116
|
+
if (shares == 0) return 0;
|
|
117
|
+
return IFToken(resource).previewRedeem(shares);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// @inheritdoc IResourceAdapter
|
|
121
|
+
/// @dev fToken headroom up to `int128.max` (effectively unbounded). The receiver param is
|
|
122
|
+
/// ignored by the fToken. The YieldGroup's per-resource cap is the binding control.
|
|
123
|
+
/// Pause-blind, like the fToken's own `maxDeposit`; a paused fToken is caught and skipped by
|
|
124
|
+
/// the YieldGroup deposit cascade, not gated here.
|
|
125
|
+
function maxDeposit(address resource) external view override returns (uint256) {
|
|
126
|
+
return IFToken(resource).maxDeposit(address(this));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/// @inheritdoc IResourceAdapter
|
|
130
|
+
/// @dev `min(Fluid withdrawal-limit, holder balance)`. No treasury-fee deduction — the fToken
|
|
131
|
+
/// delivers exactly the requested amount on redeem.
|
|
132
|
+
/// Intentionally pause-blind: the fToken's own `maxWithdraw` never reads Fluid's `IS_PAUSED`
|
|
133
|
+
/// bit (and no cheap getter exposes it), so this mirrors it. An underlying pause is caught
|
|
134
|
+
/// and skipped by the YieldGroup withdraw cascade's `try/catch` — where the real op reverts —
|
|
135
|
+
/// not gated here.
|
|
136
|
+
function maxWithdraw(address resource, address holder) external view override returns (uint256) {
|
|
137
|
+
return IFToken(resource).maxWithdraw(holder);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/// @inheritdoc IResourceAdapter
|
|
141
|
+
/// @dev Spot APY from the Fluid `LendingResolver`: base `supplyRate` (1e2 precision = already
|
|
142
|
+
/// basis points) + `rewardsRate` (1e12 precision, `/1e10` → bps). The `blocksPerYear`
|
|
143
|
+
/// parameter is unused — Fluid rates are pre-annualised APRs, not per-block.
|
|
144
|
+
function spotAPYBps(
|
|
145
|
+
address resource,
|
|
146
|
+
uint256 /* blocksPerYear */
|
|
147
|
+
)
|
|
148
|
+
external
|
|
149
|
+
view
|
|
150
|
+
override
|
|
151
|
+
returns (uint64)
|
|
152
|
+
{
|
|
153
|
+
IFluidLendingResolver.FTokenDetails memory details =
|
|
154
|
+
IFluidLendingResolver(LENDING_RESOLVER).getFTokenDetails(resource);
|
|
155
|
+
uint256 apyBps = details.supplyRate + (details.rewardsRate / 1e10);
|
|
156
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
157
|
+
return apyBps > type(uint64).max ? type(uint64).max : uint64(apyBps);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/// @inheritdoc IResourceAdapter
|
|
161
|
+
function receiptBalance(address resource, address holder) external view override returns (uint256) {
|
|
162
|
+
return IFToken(resource).balanceOf(holder);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/// @inheritdoc IResourceAdapter
|
|
166
|
+
/// @dev No-op: a Fluid fToken takes its revenue cut in the supply rate, not per-redeem, so
|
|
167
|
+
/// there is no unmodeled exit fee to guard against at registration.
|
|
168
|
+
function validateRegistration(address resource) external pure override {
|
|
169
|
+
// No Flux-specific registration precondition. `resource` validity is established by the
|
|
170
|
+
// YieldGroup's `asset()` probe and `code.length` check at registration time.
|
|
171
|
+
resource;
|
|
172
|
+
}
|
|
173
|
+
}
|