Skip to content

fix: preserve emode isolation on parameter updates - #6

Merged
Kogaroshi merged 1 commit into
aave-dao:mainfrom
llama-risk:fix/emode-v37-isolated
Aug 18, 2026
Merged

Kogaroshi merged 1 commit into
aave-dao:mainfrom
llama-risk:fix/emode-v37-isolated

Conversation

@mo-anon

@mo-anon mo-anon commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Context

Aave v3.7 added an isolated field to the ConfigEngine EModeCategoryUpdate ABI. AaveEModeAgent must provide this field when injecting LTV, liquidation-threshold, or liquidation-bonus updates.

This change passes EngineFlags.KEEP_CURRENT, preserving the category's governance-configured isolation state while applying the requested eMode parameter update.

Summary

  • pin aave-helpers to its Aave v3.7 compatibility revision
  • pass isolated: EngineFlags.KEEP_CURRENT to the ConfigEngine
  • verify that injections preserve both isolated and non-isolated category states
  • keep the RiskOracle payload and CRE workflow schema unchanged

Changes

  • update the aave-helpers submodule and foundry.lock
  • extend the existing AaveEModeAgent injection test with isolation-state coverage

Test plan

  • forge test --match-path tests/agent/AaveEModeAgent.t.sol -vv — 10 passed
  • forge test -vv — 51 passed, 0 failed

Refs: no related issue linked -- add one (owner/repo#N or URL) or create an issue

@mo-anon
mo-anon marked this pull request as ready for review August 17, 2026 12:36
zekiblue added a commit to llama-risk/aave-proposals-v3 that referenced this pull request Aug 17, 2026
Both agents were named as pre-deployed placeholder constants, which meant
governance approved an address rather than the code behind it. The payload
now constructs AaveDiscountRateAgent and AaveEModeAgent in execute() and
registers what it just built, so the code reviewed is the code registered
and there is no window in which a registered agent points at something the
proposal did not deploy.

aave-risk-agents is added as a submodule to compile them, pinned to the head
of aave-dao/aave-risk-agents#6, which restores the isolated field that
AaveEModeAgent must pass to the current config engine. That pull request has
to merge, and this pin move to a commit on main, before submission.

LLAMARISK_RISK_ORACLE is filled in with the deployed address, read back from
mainnet: owner is the LlamaRisk multisig and its update types are
PendleDiscountRateUpdate and EModeCategoryUpdate. It stays a constant because
it is shared across every PT this instance onboards rather than being an
artifact of this proposal.
@Kogaroshi
Kogaroshi merged commit dec4cc7 into aave-dao:main Aug 18, 2026
1 check passed
Kogaroshi pushed a commit to aave-dao/aave-proposals-v3 that referenced this pull request Aug 28, 2026
…Ethereum Core (#1184)

* feat: onboard PT-srUSDe-22OCT2026 to the LlamaRisk PT Risk Oracle on Ethereum Core

Registers a discount rate agent and an eMode agent on MiscEthereum.AGENT_HUB,
grants both RISK_ADMIN, and bounds every parameter step they can inject.

The role grants are the part most easily missed. The discount agent resolves the
PT price source through the Aave oracle and calls setDiscountRatePerYear on the
PendlePriceCapAdapter, which gates on isRiskAdmin || isPoolAdmin. The eMode agent
delegatecalls the config engine, and delegatecall preserves the caller, so the
PoolConfigurator sees the agent rather than the engine and the role has to sit on
the agent there too.

The range configs are equally not optional. A freshly assigned agent id inherits
no default config and the module reads a missing one as a zero bound, which
rejects every injection, so omitting them would register two permanently inert
agents. They are absolute rather than relative, because a relative cap is measured
against a previous injection that a fresh id does not have.

Agent ids are captured from registerAgent rather than assumed. agentCount++
decides them, anything registered between drafting and execution shifts them, and
the range configs are keyed by them.

The three LlamaRisk addresses are placeholders until the stack is deployed. Every
Aave address comes from the address book. Update types are unsuffixed, matching
agents built with an empty updateTypeSuffix against a RiskOracle dedicated to this
stack.

Tests assert registration fields, the agent context resolving to the current
config engine, isRiskAdmin for both, and all four range configs. The snapshot diff
is empty by design: the payload changes no reserve configuration.

* feat: deploy the risk agents in the payload

Both agents were named as pre-deployed placeholder constants, which meant
governance approved an address rather than the code behind it. The payload
now constructs AaveDiscountRateAgent and AaveEModeAgent in execute() and
registers what it just built, so the code reviewed is the code registered
and there is no window in which a registered agent points at something the
proposal did not deploy.

aave-risk-agents is added as a submodule to compile them, pinned to the head
of aave-dao/aave-risk-agents#6, which restores the isolated field that
AaveEModeAgent must pass to the current config engine. That pull request has
to merge, and this pin move to a commit on main, before submission.

LLAMARISK_RISK_ORACLE is filled in with the deployed address, read back from
mainnet: owner is the LlamaRisk multisig and its update types are
PendleDiscountRateUpdate and EModeCategoryUpdate. It stays a constant because
it is shared across every PT this instance onboards rather than being an
artifact of this proposal.

* fix: unblock PT oracle AIP after agent merge

* fix: address PT oracle AIP review comments

* fix: use predeployed PT oracle agents

* docs: simplify PT oracle payload comments

* test: cover PT oracle agent injections

* refactor: extract reusable Agent Hub activation config

* fix: source LlamaRisk agents from address book + update PR description

* feat: set agent admin to the protocol guardian

Registers both PT oracle agents with the protocol guardian as agent admin
rather than the governance executor, so a misbehaving agent can be disabled
without waiting on a governance cycle.

The split holds because the AgentHub guards these separately: setAgentEnabled
is onlyOwnerOrAgentAdmin, while registerAgent and setAgentAdmin stay onlyOwner.
The guardian can therefore stop an agent but never register one or reassign
the admin role.

Note this also grants the guardian setDefaultRangeConfig on the
RangeValidationModule, which shares the same modifier.

* docs: point the discussion link at the ARFC thread

Replaces the placeholder URL in the payload header, the AIP write-up
(frontmatter and references) and config.ts.

* refactor: drop the constant aliases from the agent hub base payload

AgentHubAgentActivationPayload is generic, so it should not carry
discount/eMode specific constants. The aliases were pure pass-throughs to
AgentHubConfigs and only existed as a getter surface for the tests, which
now read the library directly.

* chore: drop the two proposals that fail to compile

Both fail against the address book this branch pins, where
UmbrellaEthereumAssets.STK_* is IUmbrellaStakeToken rather than address:

- 20260701_AaveV3Ethereum_UmbrellaParameterUpdate...: implicit conversion
  to address (9553)
- 20260720_Multi_RiskStewardsCooldownReduction...: no matching assertEq
  overload for the token type (9322), in the test file

Removed rather than fixed, to keep this PR to the PT oracle onboarding.
Both are already-executed proposals and neither is referenced elsewhere.

---------

Co-authored-by: zekiblue <11241839+zekiblue@users.noreply.github.com>
Co-authored-by: samtin0x <40127309+samtin0x@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants