feat(llm): Yearn timelock context — nested executions, allowlist scope, timelock ops - #414
Merged
Merged
Conversation
…ope and timelock ops - Feed the inner calls of executed timelock batches to protocol-context adapters and address labelling, so a nested add_strategy is no longer reported as an inactive-strategy revert. - Label the executing Safe in the reference table. - Yearn V3: track the default queue through the batch, flag removed strategies that still hold debt, and describe allocator vaults (auto_allocate, overlap). - New permission-grant adapter: from verified source, list what an allowlist entry (keeper/executor) unlocks, flag arbitrary-call forwarders, describe the holder and show enumerable members before/after. - New timelock-execution adapter: operation ID, min delay and readiness for execute/executeBatch, including through forwarding executors. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…batch membership, gate timelock queue claim Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Strategy setters live in the shared TokenizedStrategy implementation, so the generic before-state reader missed them. The new adapter reads management, keeper, emergency admin, performance fee and recipient, unlock time, last report and the deposit gate, then renders each call in batch order as old → new. It explains setProfitMaxUnlockTime(0) (the self-held share burn and the profit credited at once), report() timing, and custom report triggers with their minReportDelay. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…xt bits, trim tests - utils/eth_view.call_view replaces three private eth_call helpers (strategy, timelock, control-transfer contexts). - utils/formatting gains format_asset_amount and format_utc. The strategy and timelock contexts now use the existing format_duration instead of local copies. - Yearn context: removed StrategyState.in_default_queue (never read), the strategy adapter's setAllowed path (the generic before-state reader already covers it) and the TriggerInfo dataclass. - Tests: dropped unit tests duplicated by resolve-level tests, folded single-assert variants together, and removed context tests that only re-check the batch model's arithmetic (covered in test_yearn_v3_batch). Co-Authored-By: Claude Opus 5.5 (1M context) <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.
Why
Two YEARN_MS AI alerts had wrong or thin summaries:
update_debt(Flex)would revert on an inactive strategy. Flex is registered in the same transaction, by anadd_strategynested inside the timelockexecuteBatch, which the adapters never saw. The report also left the WETH-2 Spark Looper unlabeled, and it never mentioned that call 2 releases an already-queued timelock operation (0x25864e54465a13f34e204660f5803e80ec9cd14c0d5b82bdbfffd2859b2b377d).forwardCall(address,bytes), an arbitrary call made as the relayer.What
expand_executed_calls(protocol_context.py,wrappers.py): adapters and address labelling see the inner calls of executedexecute/executeBatch/executeTransactionwrappers, recursively, after the wrapper. Scheduled-only wrappers are not expanded.set_default_queueshows the running queue → the new queue and flags removed strategies that still hold debt;auto_allocateand whether they route back into a strategy the vault already funds.permission_grant_context.py: for keeper/executor/allowlist setters it reads the verified source and reports:timelock_execution_context.py: forexecute/executeBatchit gives the operation ID, the timelock's min delay, and the status (not scheduled / done / not ready / ready since X, i.e. scheduled by X − delay). It also follows forwarding executors viaTIMELOCK().Testing
test_permission_grant_context.pytest_timelock_execution_context.py: the operation ID matches the on-chain hash.test_yearn_v3_context.py.TestExpandExecutedCallsandTestUnwrapExecutedCalls.ruff format,ruff checkandty checkpass.tests/test_safe_main.py::TestSafeApiQuota. They fail without this change too: a localSAFE_API_KEY_3leaks into those tests.Follow-ups in this PR
Review fixes (
permission_grant_context.py,timelock_execution_context.py):bytesargument to its ownaddressargument. If arequire/ifor a modifier argument checks the target or calldata, it is reported as a restricted forward instead, with those checks quoted.require(!blocked[msg.sender])makes a denylist: "BLOCKS" / "Entry points it closes". Lists whose checks disagree or can't be read are skipped.New
yearn_strategy_context.py(from Safe nonce 3359, two Grove compounders + a Spark compounder): the report had called the earlier strategy settings "not provided". The new adapter:setProfitMaxUnlockTime(0): the self-held share burn, the profit credited at once, the price-per-share change, and the deposit gate;report()timing, using the unlock time set earlier in the batch;minReportDelay).🤖 Generated with Claude Code