[BIP-885] Permissions Update Request #7

PR with payloads

Abstract

This proposal seeks BalancerDAO’s approval to add permissions required for:

  • Disassembling deprecated positions and reallocating assets in line with [BIP-850]
  • Staking and delegating POL to the Balancer Foundation, as outlined in [BIP-851]
  • Deploying sub-roles and enabling the Main Roles Modifier on Arbitrum, as defined in [BIP-842]

Motivation

In line with the mandates defined in the IPS and the categorization of positions for migration, the DAO’s treasury management requires permissions to:

  • Disassemble positions considered deprecated or classified as dust
  • Reallocate assets into strategic positions and stable reserves
  • Enable POL staking and delegation to Danko, who will act on behalf of the Balancer Foundation
  • Deploy and configure sub-roles on Arbitrum, ensuring modularity, better risk isolation, and alignment with the cross-chain architecture introduced in [BIP-842]

These permissions are temporary in nature and can be discarded once the migration, delegation, and sub-role configuration are complete.

Changes to the Permissions Policy

The following modifications are proposed for the Manager Role on each chain, in alignment with the post-migration plan and recent BIPs:

Ethereum Mainnet

  • vFJO: withdraw from Sablier and swap to USDC
  • sBAL on Silo: withdraw
  • MTA: swap to USDC
  • GTC: swap to USDC
  • POL: staking permissions
  • POL: delegate POL to Danko (acting on behalf of the Balancer Foundation)

Arbitrum One

  • USDC.e: swap to USDC on CoWswap and bridge to Ethereum Mainnet through CCTP
  • Zodiac Roles Modifier deployment:
    • Create the MANAGER role with the requested permissions
    • Configure the Sub Roles
    • Enable the Main Roles Modifier to point to the Avatar Safe

Zodiac Roles Modifier Permissions Policy

Ethereum Mainnet

Arbitrum One

References

3 Likes

Ethereum

POL Delegation

allow staking of $pol

NOTE: i would suggest to not limit the delegates bytes32 in setDelegation; it should be possible to choose any

- POL.approve(StakeManager, *)

- ValidatorShare.buyVoucherPOL(*, *)

- DelegateRegistry.setDelegation(“polygongovernancehub.eth”, [delegate, ratio], *)

- DelegateRegistry.clearDelegation(“polygongovernancehub.eth”)

USDS Migration xDAI Bridge (xDai Bridge - USDS migration | Gnosis Chain)

- SparkPSMLite: withdraw, redeem and deposit: receiver is limited to AVATAR

- GnosisBridgeRouter.executeSignatures with masks

- UsdsPsmWrapper buy and sell, user is limited to AVATAR

- sUSDC.deposit(*, AVATAR, *): allow for deposit with third referral arg

- SparkUSDC.approve(PsmUsdcSusds)

- DAI.approve(GnosisBridgeRouter)

- sDAI.approve: SparkPSMLite, AAVE_V3, BalancerVaultV2, COW_SWAP

- USDC.approve: SparkPSMLite, UsdsPsmWrapper, PsmUsdcSusds

- USDS.approve: UsdsPsmWrapper

- REMOVE sUSDC.deposit(*, AVATAR)

- REMOVE DAI.approve(XDaiForeignBridge)

- REMOVE XDaiForeignBridge.relayTokens (old)

CoW Swap

sell FJO/MTA/GTC for USDC via signOrder

Fjord

withdraw fjo from sablier and swap it

- FJO.approve(COWSWAP, *)

- Sablier.withdraw(*, AVATAR)

mStable

- MTA.approve(COWSWAP, *)

Silo

not sure why this needs to be through the router, we can just call Silo(0x92E7E77163FFed918421E3CB6e0A22F2Fe8B37FA).withdraw(0xba100000625a3754423978a60c9317c58a424e3D, 115792089237316195423570985008687907853269984665640564039457584007913129639935, 0) instead

- SiloRouter.execute(withdraw, siloBAL, AVATAR, *, *)

Gitcoin

- GTC.approve(COWSWAP, *)

CCTP

- CircleMessageTransmitterV2.receiveMessage with masks

Aave

- AaveRewardsController.claimRewards([*], *, AVATAR)

Lido

- REMOVE withdrawal queue’s requestWithdrawalsWstETHWithPermit and requestWithdrawalsWithPermit

2 Likes

Thanks for your detailed input!
Below is a summary of the final adjustments following your suggestions and our internal review:

POL Delegation
We’ll proceed with POL staking under the following scope:

  • POL.approve(StakeManager, *) → This permission in the policy is scoped as POL.approve(StakeManager, PoS Staking Contract) with PoS Staking Contract = 0x5e3Ef299fDDf15eAa0432E6e66473ace8c13D908. This can’t be changed since the PoS Staking Contract is the required entry point for staking POL. Besides, we can’t leave the _spender unscoped, as that would represent a serious security risk.
  • ValidatorShare.buyVoucherPOL(*, *) → Already included in the policy and valid as proposed.
  • DelegateRegistry.setDelegation("polygongovernancehub.eth", [delegate, ratio], *) → We don’t recommend leaving the delegation structure unscoped, as it poses a clear security risk. The safest approach would be to provide a list of possible delegates to scope the delegate field within the DelegationStruct. However, if you prefer to keep it unscoped, we can technically support that setup.
  • DelegateRegistry.clearDelegation("polygongovernancehub.eth") → Already included and OK as proposed.

Silo Router

We’ve decided to keep the Silo Router v2 call whitelisted, since without it we wouldn’t be able to use the Pilot extension — the router is the contract called directly from the UI. Whitelisting it also aligns with our standard guardrails and allows safe batching, since the execute() function is strictly scoped to call Silo(0x92E7E77163FFed918421E3CB6e0A22F2Fe8B37FA).withdraw().
That said, if you prefer to directly whitelist the Silo.withdraw() call, we can do it — though it would add a bit of overhead on our side.

Next Steps
Once you confirm:

  1. The list of possible delegate addresses to scope within the DelegationStruct.
  2. Whether to proceed with the router whitelisting or switch to the direct Silo.withdraw() call.

We’ll update the permission policy accordingly, regenerate the diff page, and publish the final payload.

1 Like

Ethereum

i think this is just a misunderstanding? the approve signature only allows for a spender (first arg) and amount (second arg). in your request the spender is the stake manager, and the amount is unscoped (*). no need for changes there imo; lgtm

this is quite minor and not worth the adjustment at this time imo; lgtm

ok this is just a technical limitation then. indeed no security risk, just a minor inefficiency (evm wise, i understand for your ops using the router is more efficient). no need for changes then imo; lgtm

Arbitrum

swap usdce to usdc and bridge to ethereum. lgtm

CoW Swap

  • sell USDC.e for USDC via signOrder
  • unsignOrder(*)

USDC.e

  • USDCe.approve(COWSWAP, *)

USDC

  • USDC.approve(CCTP, *)

CCTP

  • CCTP.burnToken(*, ETHEREUM, AVATAR, USDC)
1 Like

https://snapshot.box/#/s:balancer.eth/proposal/0x38db2412adce23237ff462a22faa2be0618a8b446937d56f33f2438edf83896f

1 Like