IndexManager
0x475928c29f890658a6ebce28127d186e13d8e266
Verification
Verified
v0.8.24+commit.e11b9ed9
Type
Contract
8,479 bytes
ABI entries
68
20 read · 17 write
License
none
Contract information
- Address
- 0x475928c29f890658a6ebce28127d186e13d8e266
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.24+commit.e11b9ed9
- Optimization
- Enabled
- Creator
- 0x0d45254857…2E1FA4aF74
- Creation tx
- 0x7a98774b88…cea84c7591
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (20)
BPS() → uint16
adapter() → address
circulatingSupplyOverride(address) → uint256
constituents(uint256) → address, uint16, bool
constituentsLength() → uint256
indexOfToken(address) → uint256
isKeeper(address) → bool
lastRebalance() → uint64
maxBuyPerTx() → uint256
maxSlippageBps() → uint16
maxWeightBps() → uint16
minMcapWeth() → uint256
oracle() → address
owner() → address
pendingOwner() → address
rebalanceInterval() → uint64
tracker() → address
treasury() → address
treasuryIndexSkimBps() → uint16
weth() → address
Events (16)
AdapterSetBoughtCirculatingOverrideSetConstituentActiveConstituentAddedDistributedKeeperSetOracleSetOwnershipTransferStartedOwnershipTransferredParamsSetRebalancedTrackerSetTreasurySetWeightSetWeightingParamsSet
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "initialOwner",
"type": "address"
},
{
"internalType": "address",
"name": "weth_",
"type": "address"
},
{
"internalType": "address",
"name": "adapter_",
"type": "address"
},
{
"internalType": "address",
"name": "oracle_",
"type": "address"
},
{
"internalType": "address",
"name": "treasury_",
"type": "address"
},
{
"internalType": "uint16",
"name": "treasuryIndexSkimBps_",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "maxSlippageBps_",
"type": "uint16"
},
{
"internalType": "uint256",
"name": "maxBuyPerTx_",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "BadParam",
"type": "error"
},
{
"inputs": [],
"name": "BudgetExceeded",
"type": "error"
},
{
"inputs": [],
"name": "DuplicateConstituent",
"type": "error"
},
{
"inputs": [],
"name": "Inactive",
"type": "error"
},
{
"inputs": [],
"name": "NotKeeper",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "OwnableInvalidOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "OwnableUnauthorizedAccount",
"type": "error"
},
{
"inputs": [],
"name": "RebalanceTooSoon",
"type": "error"
},
{
"inputs": [],
"name": "ReentrancyGuardReentrantCall",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "SafeERC20FailedOperation",
"type": "error"
},
{
"inputs": [],
"name": "TrackerAlreadySet",
"type": "error"
},
{
"inputs": [],
"name": "TrackerNotSet",
"type": "error"
},
{
"inputs": [],
"name": "UnknownConstituent",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAddress",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "adapter",
"type": "address"
}
],
"name": "AdapterSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "wethIn",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amountOut",
"type": "uint256"
}
],
"name": "Bought",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "supply",
"type": "uint256"
}
],
"name": "CirculatingOverrideSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "active",
"type": "bool"
}
],
"name": "ConstituentActive",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "ConstituentAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "toTreasury",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "toHolders",
"type": "uint256"
}
],
"name": "Distributed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "keeper",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "enabled",
"type": "bool"
}
],
"name": "KeeperSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "oracle",
"type": "address"
}
],
"name": "OracleSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferStarted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint16",
"name": "skimBps",
"type": "uint16"
},
{
"indexed": false,
"internalType": "uint16",
"name": "slipBps",
"type": "uint16"
},
{
"indexed": false,
"internalType": "uint256",
"name": "maxBuyPerTx",
"type": "uint256"
}
],
"name": "ParamsSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint64",
"name": "timestamp",
"type": "uint64"
}
],
"name": "Rebalanced",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "tracker",
"type": "address"
}
],
"name": "TrackerSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "treasury",
"type": "address"
}
],
"name": "TreasurySet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint16",
"name": "weightBps",
"type": "uint16"
},
{
"indexed": false,
"internalType": "uint256",
"name": "mcapWeth",
"type": "uint256"
}
],
"name": "WeightSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint16",
"name": "maxWeightBps",
"type": "uint16"
},
{
"indexed": false,
"internalType": "uint256",
"name": "minMcapWeth",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint64",
"name": "rebalanceInterval",
"type": "uint64"
}
],
"name": "WeightingParamsSet",
"type": "event"
},
{
"inputs": [],
"name": "BPS",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "acceptOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "adapter",
"outputs": [
{
"internalType": "contract IDexAdapter",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "addConstituent",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "circulatingSupplyOverride",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "constituents",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint16",
"name": "weightBps",
"type": "uint16"
},
{
"internalType": "bool",
"name": "active",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "constituentsLength",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "distribute",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "wethAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "minOut",
"type": "uint256"
}
],
"name": "executeBuy",
"outputs": [
{
"internalType": "uint256",
"name": "amountOut",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "indexOfToken",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "tracker_",
"type": "address"
}
],
"name": "initTracker",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "isKeeper",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "lastRebalance",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxBuyPerTx",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxSlippageBps",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxWeightBps",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "minMcapWeth",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "oracle",
"outputs": [
{
"internalType": "contract IPriceOracle",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pendingOwner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "rebalance",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "rebalanceInterval",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "rescue",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "bool",
"name": "active",
"type": "bool"
}
],
"name": "setActive",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "adapter_",
"type": "address"
}
],
"name": "setAdapter",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "supply",
"type": "uint256"
}
],
"name": "setCirculatingOverride",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "keeper",
"type": "address"
},
{
"internalType": "bool",
"name": "enabled",
"type": "bool"
}
],
"name": "setKeeper",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "oracle_",
"type": "address"
}
],
"name": "setOracle",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "skimBps",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "slipBps",
"type": "uint16"
},
{
"internalType": "uint256",
"name": "maxBuy",
"type": "uint256"
}
],
"name": "setParams",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "treasury_",
"type": "address"
}
],
"name": "setTreasury",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "maxWeightBps_",
"type": "uint16"
},
{
"internalType": "uint256",
"name": "minMcapWeth_",
"type": "uint256"
},
{
"internalType": "uint64",
"name": "rebalanceInterval_",
"type": "uint64"
}
],
"name": "setWeightingParams",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "tracker",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "treasury",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "treasuryIndexSkimBps",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "weth",
"outputs": [
{
"internalType": "contract IERC20",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {Governed} from "./access/Governed.sol";
import {IDexAdapter} from "./interfaces/IDexAdapter.sol";
import {IPriceOracle} from "./interfaces/IPriceOracle.sol";
import {IDividendTracker} from "./interfaces/IDividendTracker.sol";
/// @title IndexManager
/// @notice Holds the memecoin index composition, weights each constituent by its LIVE market cap (TWAP price ×
/// circulating supply) via `rebalance()`, TWAP-buys constituents in small slippage-guarded chunks, and
/// forwards bought memes to the immutable DividendTracker for auto-distribution to $MEMEDEX holders.
///
/// Weights are dynamic: as memecoin market caps rise/fall relative to each other, `rebalance()`
/// recomputes the buy weights from the price oracle. An optional per-constituent cap keeps any single
/// meme from dominating, and a market-cap floor drops dust/dead constituents for the period.
contract IndexManager is Governed, ReentrancyGuard {
using SafeERC20 for IERC20;
uint16 public constant BPS = 10_000;
struct Constituent {
address token;
uint16 weightBps; // DERIVED by rebalance() from live market cap (not manually set)
bool active; // false = ejected: no new buys, held balance still distributed
}
IERC20 public immutable weth;
IDexAdapter public adapter; // v4 (or v2) swap adapter for buying constituents
IPriceOracle public oracle;
address public treasury;
address public tracker; // DividendTracker, set once
Constituent[] public constituents;
mapping(address => uint256) public indexOfToken; // token => index+1 (0 = absent)
mapping(address => uint256) public circulatingSupplyOverride; // 0 => use totalSupply() (FDV)
uint16 public treasuryIndexSkimBps; // % of each bought balance kept for the treasury on distribute
uint16 public maxSlippageBps; // on-chain floor guard for every buy
uint16 public maxWeightBps; // per-constituent cap (10000 = no cap)
uint256 public minMcapWeth; // market-cap floor (in WETH) to be included this period
uint256 public maxBuyPerTx; // cap on WETH spent per executeBuy (TWAP chunk ceiling)
uint64 public rebalanceInterval; // min seconds between rebalances
uint64 public lastRebalance;
event ConstituentAdded(address indexed token);
event ConstituentActive(address indexed token, bool active);
event CirculatingOverrideSet(address indexed token, uint256 supply);
event Rebalanced(uint64 timestamp);
event WeightSet(address indexed token, uint16 weightBps, uint256 mcapWeth);
event Bought(address indexed token, uint256 wethIn, uint256 amountOut);
event Distributed(address indexed token, uint256 toTreasury, uint256 toHolders);
event OracleSet(address oracle);
event AdapterSet(address adapter);
event TrackerSet(address tracker);
event TreasurySet(address treasury);
event ParamsSet(uint16 skimBps, uint16 slipBps, uint256 maxBuyPerTx);
event WeightingParamsSet(uint16 maxWeightBps, uint256 minMcapWeth, uint64 rebalanceInterval);
error ZeroAddress();
error BadParam();
error UnknownConstituent();
error Inactive();
error DuplicateConstituent();
error BudgetExceeded();
error TrackerAlreadySet();
error TrackerNotSet();
error RebalanceTooSoon();
constructor(
address initialOwner,
address weth_,
address adapter_,
address oracle_,
address treasury_,
uint16 treasuryIndexSkimBps_,
uint16 maxSlippageBps_,
uint256 maxBuyPerTx_
) Governed(initialOwner) {
if (weth_ == address(0) || adapter_ == address(0) || oracle_ == address(0) || treasury_ == address(0)) {
revert ZeroAddress();
}
if (treasuryIndexSkimBps_ > BPS || maxSlippageBps_ > BPS) revert BadParam();
weth = IERC20(weth_);
adapter = IDexAdapter(adapter_);
oracle = IPriceOracle(oracle_);
treasury = treasury_;
treasuryIndexSkimBps = treasuryIndexSkimBps_;
maxSlippageBps = maxSlippageBps_;
maxBuyPerTx = maxBuyPerTx_;
maxWeightBps = BPS; // no cap by default
}
// --- wiring / params (owner) -------------------------------------------
/// @notice Set the DividendTracker ONCE, permanently — fixes the holder-fund destination.
function initTracker(address tracker_) external onlyOwner {
if (tracker_ == address(0)) revert ZeroAddress();
if (tracker != address(0)) revert TrackerAlreadySet();
tracker = tracker_;
emit TrackerSet(tracker_);
}
function setOracle(address oracle_) external onlyOwner {
if (oracle_ == address(0)) revert ZeroAddress();
oracle = IPriceOracle(oracle_);
emit OracleSet(oracle_);
}
function setAdapter(address adapter_) external onlyOwner {
if (adapter_ == address(0)) revert ZeroAddress();
adapter = IDexAdapter(adapter_);
emit AdapterSet(adapter_);
}
function setTreasury(address treasury_) external onlyOwner {
if (treasury_ == address(0)) revert ZeroAddress();
treasury = treasury_;
emit TreasurySet(treasury_);
}
function setParams(uint16 skimBps, uint16 slipBps, uint256 maxBuy) external onlyOwner {
if (skimBps > BPS || slipBps > BPS) revert BadParam();
treasuryIndexSkimBps = skimBps;
maxSlippageBps = slipBps;
maxBuyPerTx = maxBuy;
emit ParamsSet(skimBps, slipBps, maxBuy);
}
function setWeightingParams(uint16 maxWeightBps_, uint256 minMcapWeth_, uint64 rebalanceInterval_)
external
onlyOwner
{
if (maxWeightBps_ == 0 || maxWeightBps_ > BPS) revert BadParam();
maxWeightBps = maxWeightBps_;
minMcapWeth = minMcapWeth_;
rebalanceInterval = rebalanceInterval_;
emit WeightingParamsSet(maxWeightBps_, minMcapWeth_, rebalanceInterval_);
}
function addConstituent(address token) external onlyOwner {
if (token == address(0)) revert ZeroAddress();
if (indexOfToken[token] != 0) revert DuplicateConstituent();
constituents.push(Constituent({token: token, weightBps: 0, active: true}));
indexOfToken[token] = constituents.length;
emit ConstituentAdded(token);
}
/// @notice Emergency eject / re-include. Ejected tokens get no new buys; any held balance is still
/// distributed to holders on the next distribute() so nobody is stranded.
function setActive(address token, bool active) external onlyOwner {
constituents[_idx(token)].active = active;
emit ConstituentActive(token, active);
}
/// @notice Override circulating supply used for the market-cap weight (e.g. exclude burns/locked). 0 =
/// use the token's full totalSupply (fully-diluted valuation).
function setCirculatingOverride(address token, uint256 supply) external onlyOwner {
circulatingSupplyOverride[token] = supply;
emit CirculatingOverrideSet(token, supply);
}
// --- dynamic market-cap weighting (keeper) -----------------------------
/// @notice Recompute every active constituent's weight from its live market cap (TWAP price × circulating
/// supply), apply the per-constituent cap and market-cap floor, and store the result. Keeper calls
/// this on a cadence; weights then track relative market caps automatically.
function rebalance() external onlyKeeper {
if (rebalanceInterval > 0 && block.timestamp < lastRebalance + rebalanceInterval) revert RebalanceTooSoon();
uint256 n = constituents.length;
uint256[] memory mcap = new uint256[](n);
bool[] memory capped = new bool[](n);
bool[] memory included = new bool[](n);
uint256[] memory weight = new uint256[](n);
for (uint256 i = 0; i < n; i++) {
if (!constituents[i].active) continue;
address token = constituents[i].token;
uint256 supply = circulatingSupplyOverride[token];
if (supply == 0) supply = IERC20(token).totalSupply();
uint256 m = oracle.valueInWeth(token, supply);
if (m >= minMcapWeth && m > 0) {
mcap[i] = m;
included[i] = true;
}
}
// Iterative capping ("water-filling"): repeatedly allocate remaining bps proportional to market cap
// among uncapped constituents; any that exceed maxWeightBps are clamped and their excess redistributed.
uint256 remainingBps = BPS;
for (uint256 pass = 0; pass < n; pass++) {
uint256 totalUncapped = 0;
for (uint256 i = 0; i < n; i++) {
if (included[i] && !capped[i]) totalUncapped += mcap[i];
}
if (totalUncapped == 0) break;
bool changed = false;
for (uint256 i = 0; i < n; i++) {
if (!included[i] || capped[i]) continue;
uint256 w = (remainingBps * mcap[i]) / totalUncapped;
if (w > maxWeightBps) {
capped[i] = true;
weight[i] = maxWeightBps;
changed = true;
}
}
if (changed) {
// recompute remaining after clamping this pass's over-cap entries
remainingBps = BPS;
for (uint256 i = 0; i < n; i++) {
if (capped[i]) remainingBps -= weight[i];
}
} else {
for (uint256 i = 0; i < n; i++) {
if (included[i] && !capped[i]) weight[i] = (remainingBps * mcap[i]) / totalUncapped;
}
break;
}
}
for (uint256 i = 0; i < n; i++) {
uint16 wBps = uint16(weight[i]);
constituents[i].weightBps = wBps;
emit WeightSet(constituents[i].token, wBps, mcap[i]);
}
lastRebalance = uint64(block.timestamp);
emit Rebalanced(uint64(block.timestamp));
}
// --- TWAP buying (keeper) ----------------------------------------------
/// @notice Buy `wethAmount` of one constituent. Called repeatedly in small chunks at randomized intervals
/// by the keeper to TWAP the treasury's entry and avoid predictable-sandwich MEV. Chunk sizing per
/// constituent is driven by the current `weightBps` (set by rebalance()).
function executeBuy(address token, uint256 wethAmount, uint256 minOut)
external
onlyKeeper
nonReentrant
returns (uint256 amountOut)
{
Constituent memory c = constituents[_idx(token)];
if (!c.active) revert Inactive();
if (wethAmount == 0 || (maxBuyPerTx > 0 && wethAmount > maxBuyPerTx)) revert BadParam();
if (wethAmount > weth.balanceOf(address(this))) revert BudgetExceeded();
// On-chain slippage floor from the oracle's smoothed price (WETH per 1e18 token). The keeper's `minOut`
// (from the v4 Quoter) and this floor are combined — the stricter wins. DEX-agnostic (v2 or v4).
uint256 pxPer1e18 = oracle.valueInWeth(token, 1e18);
uint256 floorOut;
if (pxPer1e18 > 0) {
uint256 expectedOut = (wethAmount * 1e18) / pxPer1e18;
floorOut = (expectedOut * (BPS - maxSlippageBps)) / BPS;
}
uint256 effMin = minOut > floorOut ? minOut : floorOut;
IERC20(address(weth)).forceApprove(address(adapter), wethAmount);
amountOut = adapter.buy(token, wethAmount, effMin, address(this));
emit Bought(token, wethAmount, amountOut);
}
// --- distribution to holders (keeper) ----------------------------------
/// @notice Send bought memes to the DividendTracker for auto-distribution. For every constituent (active
/// or ejected) with a balance: skim the treasury %, forward the rest to the tracker, and credit it
/// pro-rata. Skips entirely when there are no eligible holders yet (funds wait for the next call).
function distribute() external onlyKeeper nonReentrant {
if (tracker == address(0)) revert TrackerNotSet();
if (IDividendTracker(tracker).totalShares() == 0) return; // no holders yet; keep funds for later
uint256 n = constituents.length;
for (uint256 i = 0; i < n; i++) {
address token = constituents[i].token;
uint256 bal = IERC20(token).balanceOf(address(this));
if (bal == 0) continue;
uint256 toTreasury = (bal * treasuryIndexSkimBps) / BPS;
uint256 toHolders = bal - toTreasury;
if (toTreasury > 0) IERC20(token).safeTransfer(treasury, toTreasury);
if (toHolders > 0) {
IERC20(token).safeTransfer(tracker, toHolders);
IDividendTracker(tracker).distributeReward(token, toHolders);
}
emit Distributed(token, toTreasury, toHolders);
}
}
// --- views / helpers ---------------------------------------------------
function constituentsLength() external view returns (uint256) {
return constituents.length;
}
function _idx(address token) private view returns (uint256) {
uint256 pos = indexOfToken[token];
if (pos == 0) revert UnknownConstituent();
return pos - 1;
}
/// @notice Recover ONLY foreign tokens accidentally sent here. Cannot touch WETH (the buy budget) or any
/// index constituent (holder-destined memes) — so the owner can never siphon the distribution path.
function rescue(address token, address to, uint256 amount) external onlyOwner {
if (to == address(0)) revert ZeroAddress();
if (token == address(weth) || indexOfToken[token] != 0) revert BadParam();
IERC20(token).safeTransfer(to, amount);
}
}
Chain explorer3553msChain node77ms