Skip to content

Commit 0fc4d93

Browse files
Add RewardsManager for pool units sync
Why: Create minimal manager to mirror ERC-4626 asset balances to Superfluid pool units. Test plan: - bunx hardhat compile - bunx hardhat test test/rewards.manager.test.ts
1 parent 9f22c5a commit 0fc4d93

File tree

1 file changed

+70
-0
lines changed

1 file changed

+70
-0
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.28;
3+
4+
// Rule 3 note:
5+
// This contract mirrors the minimal pattern described in Superfluid's Distribution Pools (GDA) docs
6+
// for updating pool units to match an external ERC-20 balance source. We avoid novel patterns and
7+
// only include functions we can mirror from examples. Pool creation is left to scripts (admin = this),
8+
// keeping on-chain logic minimal and example-aligned.
9+
//
10+
// References:
11+
// - Pools/GDA guide: https://docs.superfluid.org/docs/protocol/distributions/guides/pools
12+
// - Example operations: updateMemberUnits(member, units)
13+
// - We intentionally do not embed SuperTokenV1Library usage here to avoid guessing signatures.
14+
// A deploy script will create the pool with this contract as admin, then pass the pool address.
15+
16+
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
17+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
18+
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
19+
20+
interface ISuperfluidPool {
21+
// Mirrors the method name from Superfluid pool examples; return value (if any) is ignored.
22+
function updateMemberUnits(address member, uint128 units) external;
23+
}
24+
25+
/// @title RewardsManager
26+
/// @notice Mirrors ERC-4626 share balances into Superfluid Pool units (1:1, cast to uint128).
27+
/// Pool is expected to be created with this contract as admin by an external script.
28+
contract RewardsManager is AccessControl {
29+
using SafeCast for uint256;
30+
31+
/// @dev Super Token used as the pool payout asset (SENDx). Stored for reference/logging only in this phase.
32+
address public immutable sendx;
33+
34+
/// @dev ERC-20 share token (ERC-4626 shares) whose balances define pool units.
35+
IERC20 public immutable shareToken;
36+
37+
/// @dev Superfluid pool to update units on.
38+
ISuperfluidPool public immutable pool;
39+
40+
event Synced(address indexed who, uint128 units);
41+
42+
constructor(address _sendx, address _shareToken, address _pool, address admin) {
43+
require(_sendx != address(0), "sendx");
44+
require(_shareToken != address(0), "share");
45+
require(_pool != address(0), "pool");
46+
require(admin != address(0), "admin");
47+
sendx = _sendx;
48+
shareToken = IERC20(_shareToken);
49+
pool = ISuperfluidPool(_pool);
50+
_grantRole(DEFAULT_ADMIN_ROLE, admin);
51+
}
52+
53+
/// @notice Set pool units for `who` to their current share balance (cast to uint128).
54+
/// @dev Open to anyone; cannot arbitrarily set units — only mirrors on-chain share balance.
55+
function sync(address who) public {
56+
require(who != address(0), "zero");
57+
uint256 bal = shareToken.balanceOf(who);
58+
uint128 units = bal.toUint128();
59+
pool.updateMemberUnits(who, units);
60+
emit Synced(who, units);
61+
}
62+
63+
/// @notice Batch variant of sync.
64+
function batchSync(address[] calldata who) external {
65+
uint256 n = who.length;
66+
for (uint256 i = 0; i < n; i++) {
67+
sync(who[i]);
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)