[DRAFT] Endowment permissions to KPK Update #10

Abstract

This proposal is a routine update to the Endowment Manager permissions. It expands the Endowment’s access to real-world-asset (RWA) and fixed-income positions, adds a set of curated Morpho yield vaults and the Aave v3 Horizon market, enables Maple (Syrup) swap routing, and introduces a dedicated reward-claim role. No permissions are removed.

Motivation

The update continues the diversification of the Endowment’s stable and ETH allocations into vetted yield and fixed-income venues while keeping all activity within the Investment Policy Statement (IPS). New access covers fixed-yield principal tokens via Pendle, curated lending and yield vaults on Morpho (kpk, Steakhouse, Smokehouse, and Sentora), and the RLUSD market on Aave v3 Horizon. A separate Harvest role is introduced so that protocol reward claims can be executed with payouts forced to the Endowment safe, without granting broader permissions.

Specification

Additions

1. Token Approvals

Token Functions Allowed Mainnet Address
sUSDS approve 0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD
PT-sUSDS-26NOV2026 approve 0xdc169abe56461a2e0c034da431ac2a3ebf596094
PayPal USD (PYUSD) approve 0x6c3ea9036406852006290770BEdFcAbA0e23A0e8
Ripple USD (RLUSD) approve 0x8292Bb45bf1Ee4d140127049757C2E0fF06317eD

2. RWA and Fixed-Income Positions

Contract Functions Allowed Contract Address
Pendle Router V4 swapExactTokenForPt swapExactPtForToken redeemPyToToken 0x888888888889758F76e7103c6CbF23ABbF58F946
kpk Euler RWA Vault deposit withdraw redeem 0x2B47c128b35DDDcB66Ce2FA5B33c95314a7de245

3. Morpho Yield Vaults

Vault Functions Allowed Contract Address
kpk USDC Yield (Vault V2) deposit withdraw redeem 0xD5cCe260E7a755DDf0Fb9cdF06443d593AaeaA13
kpk ETH Yield (Vault V2) deposit withdraw redeem 0x5dbf760b4fd0cDdDe0366b33aEb338b2A6d77725
Steakhouse High Yield USDC deposit withdraw redeem 0xbeeff2C5bF38f90e3482a8b19F12E5a6D2FCa757
Smokehouse USDC deposit withdraw redeem 0xBEeFFF209270748ddd194831b3fa287a5386f5bC
Sentora PYUSD Main deposit withdraw redeem 0xb576765fB15505433aF24FEe2c0325895C559FB2
Sentora RLUSD Main deposit withdraw redeem 0x6dC58a0FdfC8D694e571DC59B9A52EEEa780E6bf

4. Aave v3 Horizon Market

Contract Functions Allowed Contract Address
Aave v3 Horizon Pool (RLUSD) supply withdraw 0xAe05Cd22df81871bc7cC2a04BeCfb516bFe332C8

5. Swaps (CoW Protocol token lists)

Token Change Mainnet Address
syrupUSDC Add to sell and buy lists 0x80ac24aA929eaF5013f6436cdA2a7ba190f5Cc0b
syrupUSDT Add to sell and buy lists 0x356B8d89c1e1239Cbbb9dE4815c39A1474d5BA7D

6. Reward Claims (new Harvest role)

Distributor Functions Allowed Contract Address
Fluid Distributor claim 0x7060FE0Dd3E31be01EFAc6B28C8D38018fD163B0
Fluid GHO Distributor claim 0xF398E66B1273a34558AeBbEC550DccaF4AcC7714
Merkl Distributor claim 0x3Ef3D8bA38EBe18DB133cEc108f4D14CE00Dd9Ae

All token approvals are spender-pinned to the specific protocol contract they enable. A new Harvest role is created to isolate reward-claim permissions, with all claim payouts forced to the Endowment safe.

Removals

None in this update.

Reviewing the Permissions Policy

To review, the following resources are provided:

- Payload: https://github.com/karpatkey/client-configs/blob/ens-dao-manager-harvest-rwa-yield/clients/ens-dao/mainnet/payloads/ensPermissionsUpdate10.json

-Payload: client-configs/clients/ens-dao/mainnet/payloads/ENS_Switch_ZRM.json at main · karpatkey/client-configs · GitHub

Considerations

All positions conform to the Endowment’s risk tolerance under the Investment Policy Statement (IPS). All venues in this update are permissionless; the Aave v3 Horizon RLUSD position is on the stablecoin supply side, which requires no onboarding or whitelisting, and no other position in this update carries an onboarding precondition.

Next Steps

The proposal will be introduced in the next meta-governance call. Pending review from Blockful and no revisions following discussion during the meta-governance call, this proposal will progress to an on-chain executable vote.

Pre-draft calldata security verification: PUR #10

Verification result

We reconstructed all 54 transactions of the payload and compared the reconstruction against the published payload. The two are identical. Transactions described in the specification were derived from the specification and the public contract interfaces. All new permissions are correctly restricted: deposits, withdrawals, and reward payouts can only be directed to the Endowment Safe, approvals are limited to the named protocol contracts, and the Pendle Router cannot be used to route funds through external contracts. No existing permission is removed.

The simulation and tests can be found here.

Findings and questions for kpk

1. Item 6 is implemented through a new module that the proposal text should describe. Transactions 0 through 7 deploy a second Roles instance, place the Endowment Manager permission set behind it, and transfer its ownership to kpk; we understand it will host the Harvest role, configured by kpk after execution. The claims listed under item 6 are already permitted today, with payouts restricted to the Endowment Safe, so the practical effect of item 6 is a dedicated claim operator. Our simulation confirms that payouts cannot be redirected even if the module is misconfigured. Ownership of the module, however, allows kpk to grant third parties access to the Endowment Manager permission set without a DAO vote.

Question: please describe the module in the proposal text, confirm that its use is limited to the Harvest role, and identify its intended members.

2. Item 5 is not implemented. Adding syrupUSDC and syrupUSDT to the swap token lists does not appear in any of the 54 transactions.

Question: will the payload be amended to include it?

3. The specification lists an address that does not correspond to a deployed contract. The table entry for Steakhouse High Yield USDC gives 0xbeeff7aE5E00Aae3Db302e4B0d8C883810a58100, which holds no code on mainnet. The payload correctly uses 0xbeeff2C5bF38f90e3482a8b19F12E5a6D2FCa757.

Suggestion: correct the address in the proposal text.

Reproduction

  1. Clone: git clone https://github.com/blockful/dao-proposals.git

  2. Checkout: git checkout 337e300

  3. Run: forge test --match-path "src/ens/proposals/ep-kpk-update-10/*" -vv

We will re-run this verification once the payload is finalized and the draft is published.

1) Sub-Roles Modifier

The payload only deploys and wires the module. It does not create the HARVESTER role or add any member. The HARVESTER role and its member will be configured afterwards by the MANAGER Safe, which becomes the owner of the Sub-Roles Modifier in the last tx.

You can see exactly what the role will contain in client configs:

Its scope is limited to reward claims (Fluid FLUID, Fluid GHO, and Merkl/Morpho incentives), with the recipient hard pinned to the endowment Safe.

As for how it works, the Sub-Roles Modifier is a nested permission layer under the main Roles Modifier. Since it’s assigned the MANAGER role on the main Roles Modifier (setDefaultRole + assignRoles), every transaction it forwards is still checked against the MANAGER policy. So the effective permissions of a Sub-Role are always the intersection of its own scope and MANAGER.

It can never authorize anything that MANAGER doesn’t already allow.

To verify, the whole setup was recreated on a mainnet fork. The 8 tx setup ran cleanly, with the module deployed deterministically at 0xa5dd28EC…, owner set to the MANAGER Safe, and target set to the main Roles Modifier.

A test HARVESTER Sub-Role and verified both cases:

  • :white_check_mark: A claim action already allowed by MANAGER passes end to end.
  • :cross_mark: An action deliberately granted to the Sub-Role but not allowed by MANAGER (WETH.transfer) reverts at the main Roles Modifier.

So the firewall is working as expected. Even if we scope something on the Sub-Roles, the main MANAGER policy still has the final say.

VTNet: Tenderly Dashboard

2) The missing syrupUSDC / syrupUSDT swaps

This is a legitimate catch, regenerating the updated .json to include these.

3) Empty Address

Updated to correct the forum post.

2 Likes

PUR #10: revised execution

PUR #10, as reviewed by Blockful, has been modified in execution only: rather than applying the permission changes to the existing Zodiac Roles module, the proposal now swaps the Endowment to a new Roles module. The swap permanently resolves a security issue that was previously identified and mitigated.

The new module ships with the PUR #10 permissions already applied as reviewed. This combines the security fix and the permissions update into a single batch, with no change to the permissions themselves.

Why the Main is being replaced
Two reasons, and a single swap settles both.

  • A patched version of the module: every Roles Modifier runs on a shared implementation contract (its “mastercopy”). The current Main runs v2.1.0, the version flagged in a security disclosure earlier this year and the same Zodiac Roles component involved in the June 2026 Gnosis Pay incident. The Endowment’s exposure is limited because the affected behaviour isn’t reachable with the current MANAGER permissions, and an interim safeguard is already in place. Still, the correct permanent fix is to move off v2.1.0. The new Main runs the patched v2.1.1.
  • Transaction batching: batched actions are routed through a helper contract (MultiSend), and a Roles Modifier only accepts the MultiSend versions registered on it. The current Main accepts only the older version (1.3.0), while PUR #10’s Sub-Roles Modifier uses the current one (1.4.1). Once the Sub is live, every transaction passes through the Sub and then the Main, so the old Main and Sub would have no common MultiSend version and batches would revert. The new Main registers the current version on both required entrypoints, so batching works end to end.

1. The switch payload, ENS_Switch_ZRM.json
A single batch of two transactions, signed by the Endowment Safe:

  1. disableModule on the current Main, 0x703806E61847984346d2D7DDd853049627e50A40
  2. enableModule on the new Main, 0xa23BEBFD3628D6Dd7B0638c147db11d9B6FaBD59, already fully configured, Sub included

That is the whole of PUR #10 on ENS’s side: no further transactions and no additional signatures.

2. The diff page, ens-main-zrm-compare-eth.html
The diff compares the current Main against the new one. The differences are exactly the permissions requested in PUR #10 and nothing else. The new Main reproduces the live MANAGER policy as it stands today, plus the PUR #10 additions.
The swap payload and the diff are the two deliverables we are submitting for a second round of Blockful verification. They supersede ensPermissionsUpdate10.json, which is no longer the artefact to review.

On the Sub-Roles Modifier
PUR #10 originally carried the Sub-Roles setup inside its payload. That is now folded into the preconfiguration we deliver. The Sub is redeployed at a new deterministic address, 0x48dC0d88766a59E119e3f2585BC1dC5436Ee6ce0, replacing 0xa5dd28EC9C69627A96202897b35B88827854bd3b from the original payload. It is wired to the new Main and granted the MANAGER role during preparation, so it needs no separate setup step after the swap and still requires no extra signature from ENS.
The new Main is deployed on v2.1.1 and configured with the current policy, the PUR #10 additions, the members, both 1.4.1 MultiSend entrypoints (MultiSend and MultiSendCallOnly), and the Sub. The setup is verified on-chain.

A plain-English version of the permissions added are available in our original specification

The one step remaining on our side
This payload is pending review from Blockful. Once reviewed with no issues found, we will forward the payload to the ENS Foundation for final review and execution.

Revised execution: calldata security review

We reviewed the revised execution in post 4. We checked it at Ethereum block 26,045,296. No transaction is scheduled yet.

Recommendation: do not schedule the switch yet. kpk must first transfer ownership of the new Modifier. See action point 1.

What the transaction does

The Endowment Safe executes one batch with two calls:

# Call Effect
1 disableModule(0x1, 0x703806E6…) Removes the current Roles Modifier (0x703806E6…0A40, v2.1.0).
2 enableModule(0xa23BEBFD…) Adds the new Roles Modifier (0xa23BEBFD…FD59, v2.1.1).

The new Modifier contains the current MANAGER permissions and the PUR #10 additions. The Sub Roles Modifier 0x48dC0d88…6ce0 is one of its members.

The Endowment Timelock owns the Endowment Safe. The ENS Foundation must schedule the batch on the timelock. After nine days, anyone can execute it. The Security Council can cancel it during the nine days.

Result

  • The published batch is identical, byte for byte, to our independent encoding.
  • The new Modifier has the current policy plus the PUR #10 additions, and nothing more: 151 targets, 332 functions.
  • The new Modifier runs the verified Zodiac Roles v2.1.1 code. This version fixes the June 2026 signature issue.

The simulation and tests can be found here.

Action points

  1. kpk: transfer ownership of the new Modifier. Its owner is kpk’s 1-of-9 test Safe 0xC01318baB7ee1f5ba734172bF7718b5DC6Ec90E1. After the switch, one signer of that Safe could change the Endowment permissions with no delay and no veto. Only the test Safe can make the transfer. Send transferOwnership(0x4F2083f5fBede34C2714aFfb3105539775f7FE64) from the test Safe as a separate transaction, with no other change to the Modifier. You did the same for the current Modifier on 2 May 2024.
  2. ENS Foundation: schedule only after the transfer. Confirm on-chain that owner() of the new Modifier is the Endowment Safe. Share your transaction before you schedule it. Keep safeTxGas and gasPrice at 0. With other values, a failed switch can show as executed.
  3. kpk: confirm the Harvest delegation. Who controls the Harvest member 0x14C2d2D6…97de? Will the Sub hold only the Harvest role? The pod owns the Sub and can delegate any MANAGER permission through it.

We will run our check again after the ownership transfer, please let us know.

To verify locally:

  1. Clone: git clone https://github.com/blockful/dao-proposals.git
  2. Checkout: git checkout e45a573
  3. Run: forge test --match-path "src/ens/proposals/ep-kpk-update-10/*" -vv

Thanks for the review. Updates on the three action points:

1. Ownership of the new Modifier: done. Ownership of 0xa23BEBFD…FD59 has moved from our test Safe to the Endowment Safe (0x4F2083f5…FE64). ENS now controls the new Modifier exactly as it controls the current one today.

Tx: 0x869e902c…01aa

The remaining action is the two-call switch in ENS_Switch_ZRM.json: disableModule on the current Modifier, then enableModule on the new one.

2. Scheduling: owner() on the new Modifier can now be checked onchain before the batch is scheduled.

3. Harvest delegation: 0x14C2d2D6…97de is an EOA that was intended to be the member of a HARVESTER role. That role was never deployed. It exists only in our client configs, as work in progress that was never implemented onchain. The Sub Roles Modifier has no live HARVESTER role and no assigned member, so nothing controls it today.

On the wider point: kpk controls the Sub and can delegate through it, but no role in the Sub can hold more than the MANAGER role of the new Modifier already allows. Every Sub role is, by construction, a subset of MANAGER. The Sub’s own role on the new Modifier was set during preconfiguration, and only the Modifier’s owner can change it. That owner is now the Endowment Safe. kpk can distribute a slice of MANAGER through the Sub, but can’t widen it. The ceiling stays fixed at the MANAGER policy you review.

Whenever the Sub Roles Modifier is updated, including any change to its roles or members, we will inform Blockful and the ENS Foundation. Members will always be EOAs that sign the transactions our automations require.

Thank you. We verified the transfer on-chain.

Next steps for the foundation:

  1. Load the transaction on Safe.
  2. Share it with us so we can review what’s actually being signed.
  3. Complete the signatures and execute the transaction.
2 Likes