Skip to content

Add Admin Role to Vault - #2973

Open
shahthepro wants to merge 6 commits into
masterfrom
shah/simplified-admin-unpause
Open

Add Admin Role to Vault #2973
shahthepro wants to merge 6 commits into
masterfrom
shah/simplified-admin-unpause

Conversation

@shahthepro

@shahthepro shahthepro commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Code Changes

  • Adds a new adminAddr slot for the OToken Vault
  • Adds deployment files for OUSD, OETH and OETHb Vaults
  • Set the admin address to 5/8
  • Changes the roles on pauseCapital/unpauseCapital and pauseRebase/unpauseRebase methods (2/8 can only call pause. 5/8 can unpause)
  • Adds a new PauseSafeModule that sits on top of 2/8 and can be used by HyperNative to call pause immediately on our contracts

Code Change Checklist

To be completed before internal review begins:

  • The contract code is complete
  • Executable deployment file
  • Fork tests that test after the deployment file runs
  • Unit tests *if needed
  • The owner has done a full checklist review of the code + tests

Internal review:

  • Two approvals by internal reviewers

Deploy checklist

Two reviewers complete the following checklist:

- [ ] All deployed contracts are listed in the deploy PR's description
- [ ] Deployed contract's verified code (and all dependencies) match the code in master
- [ ] Contract constructors have correct arguments
- [ ] The transactions that interacted with the newly deployed contract match the deploy script.
- [ ] Governance proposal matches the deploy script
- [ ] Smoke tests pass after fork test execution of the governance proposal

@sparrowDom sparrowDom left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left comments inline

/// Guardian Safe hosting this module) and the native staking strategies.
/// Any target exposing a no-argument `pause()` is reachable through
/// `pause(address)` below.
bytes4 internal constant PAUSE_SELECTOR = 0x8456cb59;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 confirmed

Comment thread contracts/contracts/vault/VaultAdmin.sol
@@ -0,0 +1,69 @@
const addresses = require("../../utils/addresses");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, will change it

function _execPause(address _target, bytes4 _selector) internal {
require(isPausableTarget[_target], "Target not allowed");

bool success = safeContract.execTransactionFromModule(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this doesn't fail if the target has no code (EOA account)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have added it to _allowTarget method. While it's true that self destruct can cause this to fail, but I feel that's okay since the Safe manually reviews the contract addresses before whitelisting and any revert due to self-destruct wouldn't cause any fund drains either

"OUSDVault",
[addresses.mainnet.USDC],
undefined,
true

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should cancel this script for favoring Foundry deploy. Still I think upgrade storage slot safety should pass

Comment thread contracts/test/vault/rebase.js
Comment thread contracts/utils/addresses.js Outdated
('origin-dollar', 'otoken_os_rebase', 'cd /app && pnpm exec tsx tasks/run.ts otokenOsRebase --network sonic', '45 11,23 * * *', 'UTC', false, NULL),
('origin-dollar', 'ogn_claimAndForwardRewards', 'cd /app && pnpm exec tsx tasks/run.ts ognClaimAndForwardRewards --network mainnet', '50 0 * * 2', 'UTC', false, NULL),
('origin-dollar', 'otoken_oethb_harvest', 'cd /app && pnpm exec tsx tasks/run.ts otokenOethbHarvest --network base', '55 11 * * *', 'UTC', false, NULL),
('origin-dollar', 'module_rebase_mainnet', 'cd /app && pnpm exec tsx tasks/run.ts permissionedRebase --network mainnet', '15 10,22 * * *', 'UTC', false, NULL),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: this won't delete the rows in Talos. Maybe a checklist item would be nice so that you remember to Archive them (a group in Talos for actions that aren't used anymore)

/// @dev `bytes4(keccak256("pause()"))`. Not taken from a project interface
/// because it is shared by contracts that have none in common: the ARMs
/// (`AbstractARM.pause()`, guarded by `onlyPauser`, which includes the
/// Guardian Safe hosting this module) and the native staking strategies.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure it is wired up to pause the native staking strategies.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't. I missed to fix the comment. Will change it

Comment thread contracts/deploy/base/056_pause_safe_module.js Outdated

@naddison36 naddison36 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial thought was why are we adding a Safe module so pause can be called when we can just allow the Vault Operator to pause directly? The reason is we want multiple Operators to pause so we can delegate pausing to third parties like Hypernative.

That then raises the question of why add the Operator to the Vault just to call rebase. We could use a Safe module. This would remove the Operator complexity from the Vault. If we were starting fresh, I'd remove the Operator role from the Vault and use a Safe module instead. But its in now so I'd prefer to just keep it.

Given the admin (5/8) can pause, I'd prefer the Admin multi-sig had the Safe module to pause so then we have a 5/8 approving third party Operators, not just a 2/8.

It is possible to not do any Vault code changes. We can change the Vault's Strategist to the Admin (5/8) and then use a Safe module to allow the Guardian (2/8) and Operator (EOA) to call the existing Strategist and Operator functions.

My current in two minds as to whether we:

  1. Keep this PR but move the Safe Module to the Admin (5/8) to allow Hypernative to pause.
  2. No Vault changes and change the Vault's Strategist to the Admin (5/8) with a larger Safe module

The PR's proposed mapping of functions to roles:

Function(s) Governor Strategist / Guardian Safe (2/8) Admin Safe (5/8) Vault Operator Pause-module Operator Anyone
pauseCapital() Direct Direct Direct Via Guardian Safe
pauseRebase() Direct Direct Direct Via Guardian Safe
unpauseCapital() Direct Direct
unpauseRebase() Direct Direct
rebase() Direct Direct Direct
setVaultBuffer() Direct Direct
setDefaultStrategy() Direct Direct
setRebaseRateMax() Direct Direct
setDripDuration() Direct Direct
depositToStrategy() Direct Direct
withdrawFromStrategy() Direct Direct
withdrawAllFromStrategy() Direct Direct
withdrawAllFromStrategies() Direct Direct
setAutoAllocateThreshold() Direct
setStrategistAddr() Direct
setOperatorAddr() Direct
setAdminAddr() Direct
setWithdrawalClaimDelay() Direct
approveStrategy() Direct
removeStrategy() Direct
addStrategyToMintWhitelist() Direct
removeStrategyFromMintWhitelist() Direct
setMaxSupplyDiff() Direct
setTrusteeAddress() Direct
setTrusteeFeeBps() Direct
transferToken() Direct
allocate() Direct Direct Direct Direct Direct Direct
mint() / mintFor() Direct Direct Direct Direct Direct Direct
redeem() Direct Direct Direct Direct Direct Direct
requestWithdrawal() Direct Direct Direct Direct Direct Direct
claimWithdrawal() Direct Direct Direct Direct Direct Direct

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.

3 participants