@venusprotocol/liquidity-hub 1.0.0 → 2.0.0-dev.1
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/README.md +1 -1
- package/contracts/interfaces/IMigrator.sol +6 -8
- package/contracts/migrator/Migrator.sol +9 -21
- package/deployments/bscmainnet/Migrator.json +4 -28
- package/deployments/bscmainnet_addresses.json +1 -1
- package/deployments/bsctestnet/Migrator.json +4 -28
- package/deployments/bsctestnet_addresses.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -439,6 +439,6 @@ Ordering is guaranteed by the call-array index (`addHub` before any `addYieldGro
|
|
|
439
439
|
|
|
440
440
|
**Reconciliation:** a Hub is live the moment script 06 runs but discoverable only after its VIP — `deploy/ReconcileHubRegistry.s.sol` (read-only, unnumbered) diffs the committed `deployments/<network>/Hub_*.json` set against `registry.getHubs()` in both directions and reverts on any mismatch (shadow Hubs deployed-but-unregistered, or registered-but-untracked). Run it after every onboarding VIP and periodically from monitoring.
|
|
441
441
|
|
|
442
|
-
`deploy/config/<network>.json` holds only public addresses and parameters — `acm`, `governance`, `fluxLendingResolver`,
|
|
442
|
+
`deploy/config/<network>.json` holds only public addresses and parameters — `acm`, `governance`, `fluxLendingResolver`, `wbnb` / `vBNB` (the Migrator's native path; both keys are required, set them to `0x0` to deploy with that path disabled), and per-asset `key` / `asset` / `name` / `symbol` / `decimalsOffset` / `initialMaxWithdrawalSize` / `blocksPerYear` / `feeRecipient`. The committed `bscmainnet.json` ships with `0x0` placeholders for governance/acm/resolver/recipient and must be filled before a real deploy. Secrets (deployer key, RPC URLs, Etherscan key) live only in `.env` (see `.env.example`). Deployed addresses are committed under `deployments/<network>/<name>.json`; `broadcast/` is gitignored and is not the source of truth.
|
|
443
443
|
|
|
444
444
|
**Networks:** RPC aliases are pre-wired for `bsc_mainnet`, `bsc_testnet`, `ethereum`, `sepolia` (one Etherscan V2 key across chains). v1 targets BNB Chain.
|
|
@@ -7,10 +7,8 @@ pragma solidity 0.8.25;
|
|
|
7
7
|
* @notice One-click migration from an existing Venus Core position into a Liquidity Hub. In a
|
|
8
8
|
* single atomic transaction the Migrator pulls a user's Core vToken, redeems it to the
|
|
9
9
|
* underlying, and deposits that into the matching Hub, minting share tokens to `receiver`.
|
|
10
|
-
* @dev A single immutable, permissionless deployment serves every
|
|
11
|
-
*
|
|
12
|
-
* can only ever land in a governance-registered Hub. Two paths exist because Venus splits its
|
|
13
|
-
* markets by asset type:
|
|
10
|
+
* @dev A single immutable, permissionless deployment serves every Hub — the target is chosen per
|
|
11
|
+
* call via the `hub` argument. Two paths exist because Venus splits its markets by asset type:
|
|
14
12
|
* ERC-20-backed markets (vUSDT, vUSDC, ...) go through {migrateFromCore}; the native market
|
|
15
13
|
* (vBNB) redeems raw BNB and so has the dedicated {migrateFromCoreBNB} path that wraps to WBNB
|
|
16
14
|
* before depositing into the WBNB Hub.
|
|
@@ -38,8 +36,6 @@ interface IMigrator {
|
|
|
38
36
|
error ZeroAddress();
|
|
39
37
|
/// @notice A required amount argument was zero.
|
|
40
38
|
error ZeroAmount();
|
|
41
|
-
/// @notice The target `hub` is not a governance-registered Hub in the HubRegistry.
|
|
42
|
-
error HubNotRegistered(address hub);
|
|
43
39
|
/// @notice The vToken's underlying does not match the Hub's asset.
|
|
44
40
|
error AssetMismatch(address vTokenUnderlying, address hubAsset);
|
|
45
41
|
/// @notice The Core market returned a non-zero (failure) error code on redeem.
|
|
@@ -48,6 +44,8 @@ interface IMigrator {
|
|
|
48
44
|
error NothingReceived();
|
|
49
45
|
/// @notice The minted shares were below the caller's `minShares` floor.
|
|
50
46
|
error InsufficientShares(uint256 shares, uint256 minShares);
|
|
47
|
+
/// @notice The native (vBNB → WBNB) path is unavailable: this deployment has no WBNB/vBNB wired.
|
|
48
|
+
error BNBMigrationUnsupported();
|
|
51
49
|
/// @notice Native value was received from an address other than the configured vBNB market.
|
|
52
50
|
error OnlyVBNB();
|
|
53
51
|
|
|
@@ -97,8 +95,8 @@ interface IMigrator {
|
|
|
97
95
|
/**
|
|
98
96
|
* @notice Migrate a native vBNB position into the WBNB Hub.
|
|
99
97
|
* @dev Caller must first `approve` this Migrator to transfer `vBNBAmount` of the configured
|
|
100
|
-
* vBNB market. The redeemed BNB is wrapped to WBNB before deposit. Reverts unless
|
|
101
|
-
*
|
|
98
|
+
* vBNB market. The redeemed BNB is wrapped to WBNB before deposit. Reverts unless this
|
|
99
|
+
* deployment has WBNB/vBNB wired, `IHub(hub).asset() == WBNB`, and `shares >= minShares`.
|
|
102
100
|
* This is the no-consent path — use {migrateFromCoreBNBWithConsent} to record consent.
|
|
103
101
|
* @param vBNBAmount vBNB receipts to pull and redeem.
|
|
104
102
|
* @param hub The WBNB Hub to deposit into.
|
|
@@ -6,7 +6,6 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s
|
|
|
6
6
|
import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
|
|
7
7
|
|
|
8
8
|
import { IHub } from "../interfaces/IHub.sol";
|
|
9
|
-
import { IHubRegistry } from "../interfaces/IHubRegistry.sol";
|
|
10
9
|
import { IMigrator } from "../interfaces/IMigrator.sol";
|
|
11
10
|
import { IVBep20 } from "../interfaces/external/IVBep20.sol";
|
|
12
11
|
import { IWBNB } from "../interfaces/external/IWBNB.sol";
|
|
@@ -15,16 +14,12 @@ import { IWBNB } from "../interfaces/external/IWBNB.sol";
|
|
|
15
14
|
* @title Migrator
|
|
16
15
|
* @author Venus
|
|
17
16
|
* @notice One-click migration from a Venus Core position into a Liquidity Hub. A single immutable,
|
|
18
|
-
* permissionless deployment serves every
|
|
19
|
-
* and must be present in the HubRegistry.
|
|
17
|
+
* permissionless deployment serves every Hub; the target Hub is supplied per call.
|
|
20
18
|
* @dev Stateless by design — no proxy, no admin, no funds held between calls. Each migration is
|
|
21
19
|
* atomic: pull the user's vToken, redeem it to the underlying, deposit that into the Hub, and
|
|
22
20
|
* mint shares straight to the receiver. If any leg fails the whole call reverts and the user
|
|
23
21
|
* keeps their vToken.
|
|
24
22
|
*
|
|
25
|
-
* The target `hub` is checked against the immutable {HUB_REGISTRY} before any funds move, so a
|
|
26
|
-
* migration can only land in a Hub governance has registered.
|
|
27
|
-
*
|
|
28
23
|
* Accounting is done by balance delta, never by a self-reported amount: Core `redeem` returns
|
|
29
24
|
* a Compound error code (not the redeemed amount) and silently nets out any Comptroller
|
|
30
25
|
* treasury fee, so the Migrator measures what actually arrived and deposits exactly that. The
|
|
@@ -39,24 +34,16 @@ import { IWBNB } from "../interfaces/external/IWBNB.sol";
|
|
|
39
34
|
contract Migrator is IMigrator, ReentrancyGuard {
|
|
40
35
|
using SafeERC20 for IERC20;
|
|
41
36
|
|
|
42
|
-
/// @notice
|
|
43
|
-
IHubRegistry public immutable HUB_REGISTRY;
|
|
44
|
-
/// @notice Canonical wrapped-native token (WBNB).
|
|
37
|
+
/// @notice Canonical wrapped-native token; `address(0)` disables the native path.
|
|
45
38
|
IWBNB public immutable WBNB;
|
|
46
|
-
/// @notice Canonical Venus native market (vBNB).
|
|
39
|
+
/// @notice Canonical Venus native market (vBNB); `address(0)` disables the native path.
|
|
47
40
|
IVBep20 public immutable VBNB;
|
|
48
41
|
|
|
49
42
|
/**
|
|
50
|
-
* @param wbnb_ Wrapped-native token (
|
|
51
|
-
* @param vbnb_ Venus native market (vBNB)
|
|
52
|
-
* @param hubRegistry_ The HubRegistry every migration target is validated against. Mandatory;
|
|
53
|
-
* the constructor reverts on the zero address, since without it no Hub would be accepted.
|
|
43
|
+
* @param wbnb_ Wrapped-native token, or `address(0)` on chains/deployments with no WBNB Hub.
|
|
44
|
+
* @param vbnb_ Venus native market (vBNB), or `address(0)` to leave the native path disabled.
|
|
54
45
|
*/
|
|
55
|
-
constructor(IWBNB wbnb_, IVBep20 vbnb_
|
|
56
|
-
if (address(wbnb_) == address(0) || address(vbnb_) == address(0) || address(hubRegistry_) == address(0)) {
|
|
57
|
-
revert ZeroAddress();
|
|
58
|
-
}
|
|
59
|
-
HUB_REGISTRY = hubRegistry_;
|
|
46
|
+
constructor(IWBNB wbnb_, IVBep20 vbnb_) {
|
|
60
47
|
WBNB = wbnb_;
|
|
61
48
|
VBNB = vbnb_;
|
|
62
49
|
}
|
|
@@ -124,7 +111,6 @@ contract Migrator is IMigrator, ReentrancyGuard {
|
|
|
124
111
|
revert ZeroAddress();
|
|
125
112
|
}
|
|
126
113
|
if (vTokenAmount == 0) revert ZeroAmount();
|
|
127
|
-
if (!HUB_REGISTRY.isHub(hub)) revert HubNotRegistered(hub);
|
|
128
114
|
|
|
129
115
|
address asset = IHub(hub).asset();
|
|
130
116
|
address vTokenUnderlying = IVBep20(vToken).underlying();
|
|
@@ -149,9 +135,11 @@ contract Migrator is IMigrator, ReentrancyGuard {
|
|
|
149
135
|
private
|
|
150
136
|
returns (uint256 shares)
|
|
151
137
|
{
|
|
138
|
+
if (address(WBNB) == address(0) || address(VBNB) == address(0)) {
|
|
139
|
+
revert BNBMigrationUnsupported();
|
|
140
|
+
}
|
|
152
141
|
if (hub == address(0) || receiver == address(0)) revert ZeroAddress();
|
|
153
142
|
if (vBNBAmount == 0) revert ZeroAmount();
|
|
154
|
-
if (!HUB_REGISTRY.isHub(hub)) revert HubNotRegistered(hub);
|
|
155
143
|
|
|
156
144
|
address asset = IHub(hub).asset();
|
|
157
145
|
if (asset != address(WBNB)) revert AssetMismatch(address(WBNB), asset);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"address": "
|
|
3
|
-
"block":
|
|
2
|
+
"address": "0xfe6b8BEf1215C19Cd247FbF495ef560932F1Eb9B",
|
|
3
|
+
"block": 112781054,
|
|
4
4
|
"chainId": 56,
|
|
5
5
|
"contract": "Migrator",
|
|
6
6
|
"abi": [
|
|
@@ -16,11 +16,6 @@
|
|
|
16
16
|
"name": "vbnb_",
|
|
17
17
|
"type": "address",
|
|
18
18
|
"internalType": "contract IVBep20"
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
"name": "hubRegistry_",
|
|
22
|
-
"type": "address",
|
|
23
|
-
"internalType": "contract IHubRegistry"
|
|
24
19
|
}
|
|
25
20
|
],
|
|
26
21
|
"stateMutability": "nonpayable"
|
|
@@ -29,19 +24,6 @@
|
|
|
29
24
|
"type": "receive",
|
|
30
25
|
"stateMutability": "payable"
|
|
31
26
|
},
|
|
32
|
-
{
|
|
33
|
-
"type": "function",
|
|
34
|
-
"name": "HUB_REGISTRY",
|
|
35
|
-
"inputs": [],
|
|
36
|
-
"outputs": [
|
|
37
|
-
{
|
|
38
|
-
"name": "",
|
|
39
|
-
"type": "address",
|
|
40
|
-
"internalType": "contract IHubRegistry"
|
|
41
|
-
}
|
|
42
|
-
],
|
|
43
|
-
"stateMutability": "view"
|
|
44
|
-
},
|
|
45
27
|
{
|
|
46
28
|
"type": "function",
|
|
47
29
|
"name": "VBNB",
|
|
@@ -310,14 +292,8 @@
|
|
|
310
292
|
},
|
|
311
293
|
{
|
|
312
294
|
"type": "error",
|
|
313
|
-
"name": "
|
|
314
|
-
"inputs": [
|
|
315
|
-
{
|
|
316
|
-
"name": "hub",
|
|
317
|
-
"type": "address",
|
|
318
|
-
"internalType": "address"
|
|
319
|
-
}
|
|
320
|
-
]
|
|
295
|
+
"name": "BNBMigrationUnsupported",
|
|
296
|
+
"inputs": []
|
|
321
297
|
},
|
|
322
298
|
{
|
|
323
299
|
"type": "error",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"Hub_U": "0x0e5AA174d4F31b757a237eb1999DE151596788B0",
|
|
25
25
|
"Hub_USDC": "0x9D2D9592cF8DFbf59107fAab703d08494BE14617",
|
|
26
26
|
"Hub_USDT": "0x18AfDACF30F8671021dec4b78297E39d2FE87226",
|
|
27
|
-
"Migrator": "
|
|
27
|
+
"Migrator": "0xfe6b8BEf1215C19Cd247FbF495ef560932F1Eb9B",
|
|
28
28
|
"YieldGroupCoreImpl": "0x3BccED778CAaf97AE8ff8Bedc16d2165aA15771b",
|
|
29
29
|
"YieldGroupFRVImpl": "0x72D115b1Be69a2065fED0B0574F95B3E46BD4502",
|
|
30
30
|
"YieldGroupFluxImpl": "0xFD49a719E0bF7f588F77bBEdf10dd8E843774499"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"address": "
|
|
3
|
-
"block":
|
|
2
|
+
"address": "0x343D518d8C89f9B5D770000F1ed80f45bF1419f5",
|
|
3
|
+
"block": 119460060,
|
|
4
4
|
"chainId": 97,
|
|
5
5
|
"contract": "Migrator",
|
|
6
6
|
"abi": [
|
|
@@ -16,11 +16,6 @@
|
|
|
16
16
|
"name": "vbnb_",
|
|
17
17
|
"type": "address",
|
|
18
18
|
"internalType": "contract IVBep20"
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
"name": "hubRegistry_",
|
|
22
|
-
"type": "address",
|
|
23
|
-
"internalType": "contract IHubRegistry"
|
|
24
19
|
}
|
|
25
20
|
],
|
|
26
21
|
"stateMutability": "nonpayable"
|
|
@@ -29,19 +24,6 @@
|
|
|
29
24
|
"type": "receive",
|
|
30
25
|
"stateMutability": "payable"
|
|
31
26
|
},
|
|
32
|
-
{
|
|
33
|
-
"type": "function",
|
|
34
|
-
"name": "HUB_REGISTRY",
|
|
35
|
-
"inputs": [],
|
|
36
|
-
"outputs": [
|
|
37
|
-
{
|
|
38
|
-
"name": "",
|
|
39
|
-
"type": "address",
|
|
40
|
-
"internalType": "contract IHubRegistry"
|
|
41
|
-
}
|
|
42
|
-
],
|
|
43
|
-
"stateMutability": "view"
|
|
44
|
-
},
|
|
45
27
|
{
|
|
46
28
|
"type": "function",
|
|
47
29
|
"name": "VBNB",
|
|
@@ -310,14 +292,8 @@
|
|
|
310
292
|
},
|
|
311
293
|
{
|
|
312
294
|
"type": "error",
|
|
313
|
-
"name": "
|
|
314
|
-
"inputs": [
|
|
315
|
-
{
|
|
316
|
-
"name": "hub",
|
|
317
|
-
"type": "address",
|
|
318
|
-
"internalType": "address"
|
|
319
|
-
}
|
|
320
|
-
]
|
|
295
|
+
"name": "BNBMigrationUnsupported",
|
|
296
|
+
"inputs": []
|
|
321
297
|
},
|
|
322
298
|
{
|
|
323
299
|
"type": "error",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"HubRegistryImpl": "0x4D2C18fB4520c2e4f7C754979e9a4F3BbC1BCe92",
|
|
18
18
|
"HubRegistryProxyAdmin": "0x9f8413eEE33D434F6D4f40C83181f32A831c9ef7",
|
|
19
19
|
"Hub_USDT": "0x7cE6ADF754D0eC81A6CF8ACd9C7454F45077dc61",
|
|
20
|
-
"Migrator": "
|
|
20
|
+
"Migrator": "0x343D518d8C89f9B5D770000F1ed80f45bF1419f5",
|
|
21
21
|
"YieldGroupCoreImpl": "0x96b839765b7bc062e354f57c8F9f7Be328C4fb63",
|
|
22
22
|
"YieldGroupFRVImpl": "0x4fC5cFafCa279777DfF65f7D7e19205d3785304C",
|
|
23
23
|
"YieldGroupFluxImpl": "0xEe52fb9ec5bcD6868a3D7f2FBb3e71e9D6Fc97dd"
|