// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* LOGOSVault (skeleton)
* - ERC-4626 share token ($LOGOS), accounting in USDC
* - Deploys USDC into a target basket: WBTC, stETH/rETH, WLD
* - Streams mgmt fee; crystallizes performance fee vs high-water-mark
* - Rebalances within bands; harvests/reinvests yield
*/
import {ERC20} from "openzeppelin-contracts/token/ERC20/ERC20.sol";
import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";
import {ERC4626} from "openzeppelin-contracts/token/ERC20/extensions/ERC4626.sol";
import {Ownable} from "openzeppelin-contracts/access/Ownable.sol";
import {Pausable} from "openzeppelin-contracts/security/Pausable.sol";
import {ReentrancyGuard} from "openzeppelin-contracts/utils/ReentrancyGuard.sol";
interface IAggregatorV3 { // Chainlink-style
function latestRoundData() external view returns (
uint80, int256 answer, uint256, uint256, uint80
);
}
interface ISwapRouter {
// Replace with chosen DEX/aggregator interface (e.g., Uniswap V3 exactInput)
function swap(address tokenIn, address tokenOut, uint256 amountIn, uint256 minOut, address to) external returns (uint256);
}
contract LOGOSVault is ERC4626, Ownable, Pausable, ReentrancyGuard {
// ---------- constants & types ----------
uint256 private constant BPS = 10_000;
uint256 private constant YEAR = 365 days;
struct Target {
address token; // e.g., WBTC, stETH, rETH, WLD
uint16 weightBps; // sum(weights) == 10_000
bool harvestable; // true if we can claim/reinvest rewards
}
// ---------- config ----------
IERC20 public immutable USDC; // vault asset (accounting)
ISwapRouter public router; // whitelisted DEX aggregator
address public keeper; // Gelato/Chainlink caller
// token -> oracle (USDC price with 8 or 18 decimals; normalize inside)
mapping(address => IAggregatorV3) public oracle;
Target[] public targets; // allocation basket
mapping(address => bool) public isAllowedToken;
// ---------- fees ----------
uint256 public mgmtFeeBps; // e.g., 150 = 1.50%/yr
uint256 public perfFeeBps; // e.g., 1000 = 10%
address public feeRecipient;
uint256 public lastFeeAccrual; // timestamp
uint256 public highWaterMarkPPS; // price-per-share at last crystallization (1e18 scale)
// ---------- rebalance ----------
uint16 public bandBps = 500; // +/-5% drift band
uint256 public minTradeUSDC = 5_000e6; // skip tiny trades; adjust per chain
modifier onlyKeeper() {
require(msg.sender == keeper || msg.sender == owner(), "not keeper");
_;
}