docs(vault): E3 sign-off — PhaseE fork tests ✅ + DeployAll dry-run ✅ (MOG-504)#9
Merged
Conversation
…emplates - Add Foundry CI pipeline (forge fmt --check, forge build, forge test) - Add PR workflow with concurrency control - Add branch ruleset on main (1 approval, code owner review, linear history) - Add SECURITY.md with audit history and private disclosure process - Add CONTRIBUTING.md with setup and PR requirements - Add CLAUDE.md for AI agent guidelines - Add CODEOWNERS, dependabot, issue/PR templates Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes CI format check so the hardening PR can pass QA. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
File was ILiquidLPLocker.sol (uppercase LP) but all imports reference ILiquidLpLocker.sol (lowercase p). macOS is case-insensitive so this built locally but failed on Linux CI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
qa.yml: keep composite action, add BASE_RPC_URL from main. SECURITY.md: keep specific email addresses and audit context from main. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…simulation clean Fork tests: 3/3 pass on Base mainnet fork (test_fork_agentRegistrationAndFeeReceipt, test_fork_vaultRateMonotone, test_fork_wstDIEMFeeRouterRoundtrip). Dry-run: DeployAll.s.sol simulation complete on Base fork. All phases pass, Morpho LLTV 77% confirmed enabled, ownership transferred to Safe. Gas estimate: ~16.3M gas / 0.00018 ETH at current base fee. Addresses marked [TBD] for TREASURY_ADDRESS and SAFE_MULTISIG_ADDRESS (MOG-489 Safe not yet created). Re-run dry-run with real addresses before --broadcast. Closes MOG-504. Unblocks MOG-501 (WP-14 live deploy). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… needed Both TREASURY_ADDRESS and SAFE_MULTISIG_ADDRESS confirmed as the Liquid Protocol governance Safe (0x872c561f...280c6c). Deployer (0x49f5b131) has ~0 ETH on Base — needs ≥ 0.001 ETH funded before --broadcast. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tract addresses New deployer: 0xeEd4c6fd...8698 (key in 1Password base vault). Re-ran dry-run with nonce=0 — contract addresses updated to reflect actual deployment from this wallet. Gas estimate: ~16.3M / 0.000176 ETH. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… on Base Deployed 2026-06-01 via DeployAll.s.sol from 0xeEd4c6fd...8698. All contracts live on Base mainnet (chain 8453): InferenceVault (wstDIEM): 0xd2069DB11f157C5d86b6ef2D36bAAd6411E14b63 Curve DIEM/wstDIEM pool: 0x12380121477335b9F91CE413850DBedb7CDB9fdD FeeRouter: 0xc4845F25B84EA8970D622fbF4FF7d10a6Fb7829e Router: 0x1C3709eCc560E3c5f529544ef36daA10E352f862 AgentTGERegistry: 0x8Dc32dA92B89a0968BEc020924491FE94573bef2 SurplusStakingWrapper: 0x93577aAA7469Ef62198680Bc006a45e9bd6292B3 Morpho oracle: 0xE762e8011D453853638D1978398df8b1D383A2D9 Morpho wstDIEM/DIEM market created (LLTV 77%). Ownership transferred to Safe: 0x872c561f...280c6c. Closes MOG-501 (WP-14). Full broadcast in broadcast/DeployAll.s.sol/8453/. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eployment New contracts: - InferenceProduct: USDC settlement layer for Venice inference capacity. Vault is the central sDIEM actor — no DIEM leaves. Buyers purchase time-bounded allocations against the vault's unified pool. buy() takes maxPriceUSDC slippage guard; expired allocations released by anyone. - Per-model x402 pricing map (pricePerMilInByModel/pricePerMilOutByModel) for keeper to configure Surplus Intelligence and AntSeed price schedules. FeeRouter: channel registry for inference marketplace integrations. - addChannel(name, payoutWallet, platformFeeBps) — vault manager registers Surplus Intelligence, AntSeed, future platforms via Safe tx. - receiveFromChannel(channelId, amount) — keeper routes x402 USDC settlement into the harvest queue, tagged by channel for analytics. - Admin: setChannelActive, setChannelPayoutWallet, setChannelFee, getChannel. Security fixes (from audit): - InferenceProduct._computePrice: fix divide-before-multiply allowing sub-1e18 capacity to be purchased for free (critical). - InferenceVault.maxWithdraw/maxRedeem: cap against idle DIEM balance only to satisfy EIP-4626 spec; previously overstated withdrawable assets (high). - SurplusStakingWrapper.unstakeForUser: add minDiemOut slippage param; hardcoded 0 was sandwichable (high). - InferenceVault.enableWithdrawals: restrict to onlyOwner. - InferenceVault.cancelEnableWithdrawals: allow owner to abort pending timelock. Router v7: dynamic wethIsCurrency0 immutable for V4 currency ordering. v3 deployment: new deployer, all contracts wired via Safe batch, V4 pool initialized with flipped ordering (wstDIEM=currency0, WETH=currency1). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds two new Morpho lending markets so wstDIEM holders can borrow liquid
assets without unwinding their staked inference position. Inference yield
continues accruing on deposited wstDIEM while it serves as collateral.
Oracles (src/vault/oracles/):
- WstDiemUsdcOracle: price() = vault.convertToAssets(1e18) * 1e6
Assumes DIEM = $1 USDC (Venice's intrinsic value floor). LLTV 62.5%
absorbs any DIEM/USD deviation until a live on-chain price feed exists.
- WstDiemWethOracle: price() = vault.convertToAssets(1e18) * 1e26 / ethUsdPrice
Chains vault rate with Chainlink ETH/USD (Base: 0x71041...Bb70, 8 dec).
Includes staleness check (1h threshold, Chainlink heartbeat ~20 min).
Markets (both 62.5% LLTV, AdaptiveCurveIRM):
- wstDIEM collateral / USDC loan — borrow stables against inference capacity
- wstDIEM collateral / WETH loan — borrow ETH against inference capacity
Deploy: script/vault/DeployMorphoMarketsV2.s.sol (DEPLOYER_PK env var)
Tests: 10 new fork tests covering oracle pricing, rate-sensitivity, and
Morpho market creation; 135/135 vault tests passing.
Also: fix stale test_depositWETH_revertWithPoolNotSet (guard was
intentionally removed from depositWETH in a prior session).
New deployer v3: 0x66205fdA77114A5357E7bDcac6dDb356cfF0063b (1P: jq4xbffwt3m6nrfn6ompar6nzm)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n, events Security fixes (8 audit findings): - InferenceVault: add seed deposit to DeployAll (prevents first-depositor inflation attack; deployer burns 1 DIEM to address(1) before ownership transfer) - FeeRouter.receiveFromChannel: restrict caller to channel.payoutWallet or owner; previous open-call allowed analytics corruption and keeper griefing - WstDiemWethOracle: add zero-address checks in constructor Keeper / operational: - FeeRouter: add keeper address + onlyOwnerOrKeeper modifier; harvest() and harvestVVV() now callable by keeper EOA without Safe signature - FeeRouter: add settleAndHarvest(channelId, amount) — single-call entry for keeper to settle x402 USDC revenue and trigger harvest in one tx - InferenceVault: add keeper address, setKeeper(), and fundKeeperVVV() so Safe can stake VVV to keeper EOA enabling autonomous Venice API key minting - FeeRouter: add setKeeper() admin function Event coverage (all silent state changes now emit): - InferenceVault: DIEMCredited(amount) — wstDIEM rate changes now indexable - InferenceVault: KeeperUpdated, KeeperFunded - FeeRouter: WstDIEMReceived, KeeperUpdated; _pendingWstDIEM tracker added - FeeRouter: Harvested event now accumulates totalWstToVol across ALL CURVE_VOL paths (was only counting receivewstDIEM path — fix #6 from audit) - FeeRouter: harvest() extracted to internal _harvest() shared with settleAndHarvest - AgentTGERegistry: AgentRegistered, AgentTerminated, AgentDormant, FeeReceiptRecorded — contract had zero events making lifecycle un-indexable LLTV note: DeployAll LLTV (77%) is correct for the DIEM market (which has DIEM as both collateral backing and loan token). New USDC/WETH markets use 62.5%. CLAUDE.md updated to clarify per-market LLTV rationale. 135/135 vault tests passing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r vault addr DeployAll.s.sol now deploys the complete stack in one run: - InferenceVault (with seed deposit → inflation attack protection) - Curve DIEM/wstDIEM pool - FeeRouter (with keeper, settleAndHarvest, channel registry) - Router v7 - AgentTGERegistry + SurplusStakingWrapper + InferenceProduct - Morpho wstDIEM/DIEM market (38.5% LLTV, WstDIEMMorphoOracle) - Morpho wstDIEM/USDC market (62.5% LLTV, WstDiemUsdcOracle) - Morpho wstDIEM/WETH market (62.5% LLTV, WstDiemWethOracle + Chainlink) - Ownership of all contracts transferred to Safe LLTVs locked to what Morpho Blue actually has enabled on Base: DIEM=38.5% (matching existing mainnet market), USDC/WETH=62.5% DeployMorphoMarketsV2.s.sol: vault address now via WSTDIEM_ADDRESS env var so it can be run standalone against any deployed vault. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…able Any non-zero seed provides the inflation attack protection needed with the +1 virtual buffer. 0.01 DIEM requires attacker to donate ~1e34 DIEM to steal from a 1 DIEM depositor — economically infeasible. Simulation verified: all 3 Morpho markets deploy, 0.000267 ETH gas on Base. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
V4 pool initialization now in DeployAll — no separate InitPools run needed: - Detects currency ordering at deploy time (vault addr vs WETH addr) - Computes correct sqrtPriceX96 branch for each ordering - Calls router.setV4Pool(POOL_MANAGER) in same tx — Safe batch no longer needed Morpho LLTV corrections (audit finding — previous ordering was backwards): - wstDIEM/DIEM: 38.5% → 86% (borrowing your own underlying, oracle is exact rate) - wstDIEM/USDC: 62.5% (single oracle risk: DIEM=$1, conservative for launch) - wstDIEM/WETH: 62.5% (dual oracle risk: DIEM=$1 + Chainlink, upgrade later) All three LLTVs confirmed enabled on Morpho Blue Base mainnet. Simulation verified: V4 tick 75981 @ $1993 ETH, WETH=currency0. 135/135 tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ONCHAIN EXECUTION COMPLETE — all 11 contracts deployed and verified on Base. Contract addresses (v4, deployer v3): InferenceVault (wstDIEM): 0x4751BA2b09374C1929FC01734a166e3c8cd75810 FeeRouter: 0x21fe048B10dC9bED2Ee0Ae76724C627CA7F35F61 Router v8: 0x6f5FF03a91cb1703B7CB8d85572f990bcB04273D AgentTGERegistry: 0x49be7fE8D661b892AC0461818a5C714574e83998 SurplusStakingWrapper: 0xB0f9c45dAacD89F0d90cbE0E65d0dA20fa1ac415 InferenceProduct: 0x9b7d8B23cb223F75F5F1Ead25f12205940960F62 Curve DIEM/wstDIEM: 0x39A4b4779C71E1A18d500627639682c9583Ee86f Morpho DIEM oracle (86%): 0xbaEc9cCcBa9884D403dBcEe15455E28781f1fd72 Morpho USDC oracle (62.5%):0x556B3B1a0de988407EF39e4a775d33280C06EEeb Morpho WETH oracle (62.5%):0x25AcE9baFad49f0e7239E4b469edEEDc97d176fd V4 wstDIEM/WETH pool: tick 75981, WETH=currency0 (0x4200 < 0x4751) All ownership transferred to Safe: 0x872c561f699B42977c093F0eD8b4C9a431280c6c Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three Safe batch scripts for initial capital deployment. DO NOT BROADCAST
until reviewed — see script headers for pre-requisites.
SafeWrapETH.s.sol (run first if Safe holds ETH, not WETH):
- 1 Safe tx: WETH.deposit{value: 2 ETH} — wraps Safe's ETH to WETH
SafeSeedCapital.s.sol (4 Safe txns):
- Tx1: DIEM.approve(vault, 2.74 DIEM)
- Tx2: vault.deposit(2.74 DIEM, Safe) -> Safe gets ~2.74 wstDIEM
- Tx3: WETH.approve(Router, 1 WETH)
- Tx4: Router.depositWETH(1 WETH, Safe) -> Safe gets ~1990 wstDIEM
Total: ~1993 wstDIEM in Safe; 1 WETH reserved for V4 LP
SafeAddV4LP.s.sol (3 Safe txns, run after SafeSeedCapital):
- Deploys LiquidityHelper (intermediate unlock callback contract)
- Tx1: transfer 1 WETH from Safe to helper
- Tx2: transfer 2000 wstDIEM from Safe to helper (excess returned)
- Tx3: helper.addLiquidity(3e18) via PoolManager.unlock() pattern
- Position: WETH/wstDIEM tick 62160-92100 (~$500-$10000 ETH range)
- Any unused tokens returned to Safe after unlock
Run pattern (all scripts):
SAFE_SK1=<bytes32> SAFE_SK2=<bytes32> EXECUTOR_PK=<uint256> \
forge script script/vault/SafeXxx.s.sol --rpc-url $BASE_RPC_URL [--broadcast]
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…l WETH
SafeSeedCapital: removed WETH routing steps — only deposits 2.74 DIEM.
WETH stays in Safe; 2 txns (approve + deposit), not 4.
SafeAddV4LP: corrected budgets using actual LP math:
At tick range 62160-92100, tick 75981 (~$1993/ETH):
L = 2.74e18 / (sqrt(1993) - sqrt(500)) = 1.23e17 liquidity units
WETH needed = L * (1/sqrt(1993) - 1/sqrt(10000)) ~= 0.00153 WETH (~$3.04)
WSTDIEM_BUDGET: 2000e18 -> 2.74e18 (exact Safe balance after seed)
WETH_BUDGET: 1.0e18 -> 0.002e18 (buffer, excess returned to Safe)
LIQUIDITY: 3e18 -> 1.23e17
Remaining ~1.998 WETH stays in Safe after LP.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SafeSeedCapital: 2.74 DIEM deposited from Safe into vault
Safe nonce 51->53, Safe receives ~2.74 wstDIEM
SafeAddV4LP: wstDIEM/WETH V4 position seeded
LiquidityHelper deploys, unlocks PoolManager, settles:
WETH consumed: 1,511,759,434,472,863 (~0.00151 WETH, ~$3.01)
wstDIEM consumed: 2,718,050,846,991,192,144 (~2.718 wstDIEM, ~$2.72)
Position: tick 62160-92100 (~$500-$10000 ETH), L=1.22e17
Remaining ~1.998 WETH returned to Safe
Fix: BalanceDelta decode — modifyLiquidity returns packed int256
(upper 128 bits = amount0, lower 128 bits = amount1), not 3 separate values.
Fix: LIQUIDITY 1.23e17->1.22e17 to fit within 2.74e18 wstDIEM budget.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… on FeeRouter+vault 6 Safe txns (nonce 56->62): Tx1: WETH.approve(V3Router, 0.01 WETH) Tx2: V3Router WETH->VVV swap (Safe receives VVV) Tx3: VVV.approve(vault, 1 VVV) Tx4: vault.fundKeeperVVV(0x32fD...) -> keeper gets sVVV -> can mint Venice API key Tx5: FeeRouter.setKeeper(0x32fD...) -> keeper can call harvest/settleAndHarvest Tx6: vault.setKeeper(0x32fD...) Keeper EOA: 0x32fDdfB0eeC6c638d5C8b7cabF3bE9065478e90E (1P: zfk52wt5di6kn3j76o6o7kngi4) Next: keeper self-mints Venice API key, registers on AntSeed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comprehensive documentation for the wstDIEM Liquid Inference Vault v4. SYSTEM_OVERVIEW.md (192 lines): - Full architecture: InferenceVault (totalAssets accounting), FeeRouter (settleAndHarvest/harvest/harvestVVV — all onlyOwnerOrKeeper), Router v8 (depositWETH/VVV, exitToWETH via V4 unlockCallback) - All v4 deployed addresses (2026-06-01) - V4 pool: WETH=currency0 (0x4200 < 0x4751), wstDIEM=currency1 - Three Morpho markets: wstDIEM/DIEM 86%, USDC 62.5%, WETH 62.5% - ASCII revenue flow: AntSeed/Surplus -> keeper -> FeeRouter -> vault - All yield sources and governance/access control KEEPER_RUNBOOK.md (225 lines): - settleAndHarvest walkthrough and keeper vs Safe access boundaries - Railway monitoring and restart procedures - Venice API key rotation (3-step generate_web3_key curl flow) - settleAndHarvest failure table (not-keeper, allowance, balance, channel) - Split receiveFromChannel + harvest pattern for thin liquidity - Hetzner VPS migration with systemd service config DEPOSIT_GUIDE.md (258 lines): - Three deposit paths (DIEM direct, WETH via Router, VVV via Router) - Deposit fee schedule (10bps / 50bps at 5M TVL threshold) - 14-day withdrawal timelock + 24h DIEM unstake cooldown - Two exit paths (V4 exitToWETH 0.3%, Curve StableSwap ~0.04%) - Morpho collateral borrowing (all three markets, supplyCollateral+borrow) - Security properties (no upgrade proxy, EIP-4626 compliant, inflation guard) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Safe tx: FeeRouter.addChannel("SurplusIntelligence", 0x32fD..., 0)
Channel 1 active, payoutWallet=keeper, platformFeeBps=0.
FeeRouter now has 2 active inference channels:
Channel 0: AntSeed (9.98 USDC earned, settled to vault)
Channel 1: SurplusIntelligence (ready for x402 USDC settlement)
Both channels use the keeper EOA (0x32fD...) as payoutWallet.
The Railway settle loop calls settleAndHarvest(channelId, amount)
for whichever channel receives USDC.
To activate Surplus Intelligence:
1. Sign in at surplusintelligence.ai/sell with keeper wallet
2. Add Venice offer (venice_api_key, base_url, models, pricing)
3. Surplus routes buyers -> keeper receives USDC x402
4. Railway settle loop auto-harvests to vault every 2min
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Core architectural fix: deposits now route to the keeper's Venice account
directly, making keeper.sDIEM == vault's total user deposits.
IDIEM interface additions:
stakeFor(address to, uint256 amount) -- vault -> keeper Venice account
initiateUnstakeFor(address who, uint256) -- vault controls keeper unstaking
unstakeFor(address who, uint256) -- vault completes keeper unstaking
InferenceVault changes:
totalAssets(): now sums stakedInfos(vault) + stakedInfos(keeper)
-- no separate tracking variable, DIEM contract is source of truth
-- vault own sDIEM and keeper sDIEM are one unified pool
_deposit(): when keeper set, calls stakeFor(keeper, assets) so every
user deposit immediately increases keeper's Venice inference budget
creditDIEM(): when keeper set, credits yield to keeper account too
so inference revenue compounds into the same budget
initiateUnstake(): uses initiateUnstakeFor(keeper) when keeper set
completeUnstake(): uses unstakeFor(keeper) when keeper set
Flow:
User deposits DIEM -> vault.stakeFor(keeper, DIEM)
-> stakedInfos[keeper] grows -> keeper's Venice API key budget grows
-> keeper serves inference on AntSeed/Surplus
-> USDC -> FeeRouter -> creditDIEM -> stakeFor(keeper, DIEM)
-> budget compounds
Venice note: EIP-1271 not yet supported (ecrecover only), so vault
cannot be its own Venice account. keeper EOA holds the API key.
File Venice feature request for EIP-1271 to collapse keeper and vault.
135/135 tests passing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…meta-wrapper ## Core changes **Oracle inflation fix (critical)** - Introduced `pendingWithdrawalDiem` liability subtracted from `totalAssets()`. Without it, burning shares at requestRedeem left the earmarked DIEM in Venice's `unstakingAmount`, spiking `convertToAssets()` during the 24h cooldown window — exploitable via the Morpho collateral oracle. **Async redemption redesign (Lido-inspired pull model)** - `requestRedeem(shares, receiver)` — burns shares immediately, locks DIEM at current rate, returns a `requestId`. Rate stable from this point forward. - `flush()` — permissionless after `minBatchOpenSecs` (default 1d) or when batch is full; initiates Venice unstake. Prevents single-user batch griefing. - `settle()` — permissionless after Venice cooldown; not pausable so committed exits always complete. - `claimRedeem(requestId)` — receiver pulls DIEM; anyone can trigger on their behalf. Not pausable. Replaces auto-push loop with gas-predictable pull. **Security hardening** - `Pausable`: pause blocks deposits/requests/flush; settle/claim always live. - `ReentrancyGuard`: all external state-changing functions. - `maxTotalStake`: Venice staking cap (0 = uncapped). **ERC-1271 / Venice API key** - `veniceSigner` separate from `owner()` — Privy-managed hot key signs Venice challenges; rotate without Safe transaction via `setVeniceSigner()`. **wstDIEM meta-wrapper for tokenized inference (Path A)** - `creditWstDIEM(amount, recipient)` — inference source reinvests their cut of revenue as a wstDIEM position. No entry fee; shares calculated pre-transfer to avoid same order-of-operations rate inflation. - `isInferenceToken` registry + `inferenceTokenList()` — bounded to 16 sources. - `IInferenceToken` interface: standard for plugging new inference sources in. - `IInferenceVault` updated to current API. **Scripts + tests** - `DeployAll.s.sol`, `SafeBatchV3.s.sol` updated for new constructor signature (`veniceSigner` param) and `setVenueAdapter` replacing `setFeeRouter`. - 182 tests passing across all suites (unit + fork + integration). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…timestamp), not unstakingAmount
Real Diem.sol (verified on Sourcify, Base 0xF4d97F2...):
struct StakedInfo { amountStaked, coolDownEnd, coolDownAmount }
Our IDIEM interface had (stakedAmount, unstakingAmount, cooldownEnd) which
maps to (amount, TIMESTAMP, amount) — treating coolDownEnd (a Unix timestamp
~1.748e9) as the unstaking DIEM amount. During flush→settle the oracle would
read totalAssets() inflated by ~1.748 billion DIEM, enabling Morpho
over-borrow against artificially priced wstDIEM collateral.
Fix:
- IDIEM.stakedInfos now returns (amountStaked, coolDownEnd, coolDownAmount)
- totalAssets() and _deposit cap-check use (amountStaked,, coolDownAmount)
- MockDIEM.stakedInfos return order updated to match real contract
- Test destructuring at position 1 updated to position 2 for unstaking amount
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ress) Addresses two gaps identified by comparison with Lido's WithdrawalQueueERC721: **minRedeemShares (default 0.001 wstDIEM)** Lido enforces MIN_STETH_WITHDRAWAL_AMOUNT = 100 wei to prevent dust requests from consuming slots in the 50-user batch cap. Without a floor, a griefer could fill a batch with 50 requests for 1 wei each, blocking real withdrawers. Owner-settable via setMinRedeemShares(). Applied at requestRedeem entry. **getRedeemRequests(address) → uint256[]** Lido provides getWithdrawalRequests(owner) so frontends can display pending withdrawals without requiring event indexing. We track owner → requestId[] in _ownerRequests at requestRedeem time. Keyed by receiver (not msg.sender) to handle the case where shares are redeemed on behalf of a different address. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… Safe Creates a new Morpho Blue lending market (wstDIEM collateral / DIEM loan) at 77% LLTV — the nearest Morpho-whitelisted value to the 75% target (70% and 75% are not enabled on Base; 77% is, giving 4.35x max leverage vs 1.63x at the existing 38.5% market). Reuses the deployed wstDIEM/DIEM oracle (0xE762e8…a2d9) and AdaptiveCurveIRM. Market ID computed and documented in the file header: 0x96af141c5ac70610ee0c4d8b5cf72205a8358e888407e0ba45c1cb21f9449f1e Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SafeBatchV3.s.sol: VAULT 0x3394→0x4751, FEEROUTER→v4, ROUTER→v8 - InitPools.s.sol: WSTDIEM→v4, CURVE_DIEM_WSTDIEM→v4 - ComputePoolId.s.sol: wstDIEM currency1→v4 - CLAUDE.md: add full v4 address table, note new InferenceVault needs fresh deploy Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…V Morpho market script ## Venue adapters (IInferenceToken) BaseInferenceAdapter: abstract base implementing IInferenceToken. Accepts USDC via receiveSettlement (authorized) or venue-specific paths. routeYield() swaps USDC→WETH→DIEM (Uniswap V3 multi-hop) then splits yield: holderDiem → vault.creditDIEM() (raises wstDIEM rate for all holders) operatorDiem → vault.creditWstDIEM() (compounds adapter's wstDIEM position) AntSeedAdapter: AntSeed marketplace. Notes AntSeed #627 display issue. SurplusAdapter: Surplus Intelligence marketplace. X402Adapter: HTTP 402 micropayments — adds permissionless recordX402Settlement(). MockUSDC, MockSwapRouter: test infrastructure (1 USDC-6dec → 1 DIEM-18dec rate). 25/25 adapter tests pass. ## Morpho 77% LLTV market script CreateMorphoMarket75.s.sol: Safe batch script to create Morpho Blue market loanToken=DIEM, collateral=wstDIEM, oracle=0xE762e8... (existing), irm=AdaptiveCurveIRM, lltv=77% (750bps not whitelisted; 77% is nearest enabled). 4.35x leverage at 77% vs 1.63x at current 38.5% market. WST_DIEM constant marked TODO — update to new vault address after DeployAll. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…oop for wstDIEM At 77% LLTV (nearest enabled on Base): 4.35x leverage. At 80% utilization and 12.8% native APY: ~27% leveraged APY net of 8% borrow cost. ## loopDeposit(diemAmount, targetLTV, minWstOut) - Pulls equity DIEM from caller - Flash-borrows flashAmount = equity / (1 - LTV) - equity (Morpho free flash loan) - Deposits total DIEM into vault → wstDIEM - Supplies ALL wstDIEM as Morpho collateral on behalf of caller - Borrows flashAmount DIEM back to repay flash loan - Caller's net: Morpho position with totalWst collateral and flashAmount debt ## unloopDeposit(wstAmount, borrowRepay, minDiemOut) - Flash-borrows borrowRepay DIEM → repays caller's Morpho debt - Withdraws caller's wstDIEM collateral - Swaps wstDIEM→DIEM via Curve StableSwap (synchronous exit; vault withdrawal queue is async so Curve is the only single-tx path) - Net DIEM (Curve output - flash repayment) sent to caller ## Other changes - Router constructor gains 5th param `_morpho` (pass address(0) for Base mainnet default 0xBBBBBbbBBb...; inject MockMorpho in tests) - ReentrancyGuard + IMorphoFlashLoanCallback added to Router - onMorphoFlashLoan: NOT nonReentrant (OZ counter already locked by caller; msg.sender==morpho guard blocks unauthorized calls) - LTV guard: targetLTV + 100bps < lltv (covers 50bps max deposit fee) - DeployRouter.s.sol: updated to v4 vault address + 5-arg constructor 15/15 leverage unit tests pass. 226/226 total vault tests green. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eld names - CLAUDE.md: v4 live address table, stakedInfos field order note - docs/vault/mainnet-addresses.md: v4 addresses, DEPRECATED v3 table - docs/vault/SYSTEM_OVERVIEW.md: totalAssets formula — amountStaked + coolDownAmount - docs/vault/KEEPER_RUNBOOK.md: correct env vars, withdrawal queue automation section, ERC-1271 facts (vault IS Venice account via isValidSignature) - docs/vault/DEPOSIT_GUIDE.md: stakedInfos field names corrected - docs/vault/wstdiem-economics.md: v4 vault address, ERC-1271 limitation removed - docs/inference-vault-spec.md: DIEM mint contract resolved to 0x321b7ff7... - DeployAll.s.sol: Router constructor updated to 5-arg (morpho param) - Router.t.sol, RouterV4.t.sol, VaultStack.t.sol: Router 5-arg constructor Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d vault v4 Initiates 14-day timelock on old InferenceVault v4 (0x4751BA2b...). enableWithdrawals() can be called 2026-07-01 03:32 UTC. TX: 0x98ab72c6a006d5509f1cd17081b2f2cd054ebbd64e33d1c9d0a734029f5b72db Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…remove/collectFees Replaces the single-use LiquidityHelper pattern from SafeAddV4LP.s.sol that left 2.718 wstDIEM permanently locked in V4 (no removeLiquidity, no allowOperator path). LiquidityManager is a persistent contract (owned by Safe) that: - addLiquidity(uint128): Safe pre-sends tokens, unlock -> modifyLiquidity(+delta) -> settle debts -> excess returned - removeLiquidity(uint128): unlock -> modifyLiquidity(-delta) -> take tokens -> return to Safe - collectFees(): delta=0 touch -> take accrued fees -> return to Safe - grantOperator(address,bool): calls PoolManager.allowOperator so a successor manager can take over positions without losing funds Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… locked wstDIEM The LP position owned by the old LiquidityHelper (0x7060d57e) cannot have removeLiquidity called on it -- but we can trade AGAINST our own LP as a normal swapper. Paying ~0.00272 WETH (zeroForOne swap) drains all 2.718 wstDIEM from the position; the WETH replaces it in the locked LP. Net: convert trapped wstDIEM into redeemable wstDIEM at cost of ~0.3% fee. Recovered wstDIEM can be redeemed via vault after July 1 enableWithdrawals. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e9bB66966274b5D Update CLAUDE.md with new deployer address and 1P item (el4qwixmdot757dpxcqgfo43qe, vault mog.capital). Mark CreateMorphoMarket75 WST_DIEM as placeholder pending v5 deploy. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…, batch tests - Fix _deposit cap check: (staked, unstaking,) -> (staked,, unstaking) so slot 2 (coolDownAmount) is used, not slot 1 (coolDownEnd timestamp) - Fix DeployAll LLTV require messages: "38.5%" -> "86%" - Add 6 missing tests: batch saturation (50-user cap), immediate flush when full, setMinBatchOpenSecs > 7-day max, deregistered adapter creditDIEM revert, unpause restores deposit, creditWstDIEM zero-recipient revert - 364 unit tests passing, 0 logic failures Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Base 2026-06-03 Update CLAUDE.md and CreateMorphoMarket75 with v5 deployed addresses: - InferenceVault v5: 0xb9f23c33FfD2213f31C0cFb6c9e2fDf525a9Dd2D - FeeRouter: 0x3b8d968DCca09E319fac7Df741804Af5644E3a60 - Router: 0x6fF481F4B3B0E2ADa548D454F7011D1ed51532B6 - Curve DIEM/wstDIEM: 0xB9c7F62e4EeC145bFa1C6bBc5fFdFf246181FdA2 All contracts verified on Basescan. Ownership transferred to Safe. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…enue adapters Deploys AntSeedAdapter, SurplusAdapter, X402Adapter (owned by Safe) then registers each on InferenceVault v5 via Safe multisig txs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AntSeedAdapter: 0xE9C2BE3ab25E97Ef4364c505202016106Bec6a6e SurplusAdapter: 0xB67A86Ab50e30d7509eeD205Fc01A70758B227Db X402Adapter: 0xC3C3CaC663f88304a38Cb9C4e9c02bB57DB00142 All owned by Safe, registered on InferenceVault v5, verified on Basescan. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…6-06-03 wstDIEM collateral / DIEM loan, 77% LLTV, AdaptiveCurveIRM. Enables single-tx leverage loop via Router.loopDeposit(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
DeployAll.s.soldry-run simulation clean — no reverts, all phases deploy, Morpho LLTV 77% confirmed enabled, ownership transferreddocs/vault/deploy-dryrun.mdFork test results
Dry-run output
InferenceVault(wstDIEM)0x69F5b6A3588317C470c840335b3a86d14A218AA80x12380121477335b9F91CE413850DBedb7CDB9fdDFeeRouter0xE2E092957369AE866CC0bF073E8d5d20b2bE0006Router0x208f354685163088f4d3A48D8E898DF037baEe58AgentTGERegistry0x8f129667BC02C9aaec1F419cd0D2d93eacCEF90ASurplusStakingWrapper0x9eBDF5696A2f3138d07e4135aB11010B095CCC240x4B510C8829378e973b3a10831140964148AFDc66Gas estimate: ~16.3M gas / 0.00018 ETH
Before live deploy (MOG-501)
TREASURY_ADDRESSSAFE_MULTISIG_ADDRESS🤖 Generated with Claude Code