Skip to content

Commit d248009

Browse files
Add propose_vault_strategy_moves actions for Ethereum and Base (#2945)
* add propose_vault_strategy_moves actions for ethereum and base * Get rid of hardhat --------- Co-authored-by: Shahul Hameed <10547529+shahthepro@users.noreply.github.com>
1 parent 8b86cd7 commit d248009

10 files changed

Lines changed: 2171 additions & 0 deletions

File tree

contracts/README.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,147 @@ Building the runner image installs the optional `@oplabs/talos-client` peer
317317
dependency from GitHub Packages. Set `TALOS_PACKAGE_TOKEN` to a PAT with
318318
`read:packages` access before running `docker compose build`.
319319

320+
Actions that propose transactions through the Safe Transaction Service require
321+
`SAFE_API_KEY`. The active Talos signer must be registered separately on each
322+
chain as a delegate for the target Safe. A delegate can submit a proposal but
323+
does not provide an owner confirmation or reduce the Safe threshold.
324+
325+
### Defender Relayer
326+
327+
Open Zeppelin's [Defender](https://defender.openzeppelin.com/) product has a [Relayer](https://docs.openzeppelin.com/defender/v2/manage/relayers) service that is a managed wallet. It handles the nonce, gas, signing and sending of transactions.
328+
329+
To use a [Relayer](https://defender.openzeppelin.com/v2/#/manage/relayers) account, first log into Defender and create an API key for the account you want to use. Use the generated API key and secret to set the `DEFENDER_API_KEY` and `DEFENDER_API_SECRET` environment variables.
330+
331+
```
332+
export DEFENDER_API_KEY=
333+
export DEFENDER_API_SECRET=
334+
```
335+
336+
Once you have finished sending your transactions, the API key for hte Relayer account should be deleted in Defender and the environment variables unset.
337+
338+
```
339+
unset DEFENDER_API_KEY
340+
unset DEFENDER_API_SECRET
341+
```
342+
343+
### Deploying Defender Actions
344+
345+
Actions are used to run operational jobs are specific times or intervals.
346+
347+
[rollup](https://rollupjs.org/) is used to bundle Actions source code in
348+
[/scripts/defender-actions](./scripts/defender-actions) into a single file that can be uploaded to Defender. The
349+
implementation was based off
350+
[Defender Actions example using Rollup](https://github.com/OpenZeppelin/defender-autotask-examples/tree/master/rollup).
351+
The rollup config is in [/scripts/defender-actions/rollup.config.cjs](./scripts/defender-actions/rollup.config.cjs). The
352+
outputs are written to task specific folders under [/scripts/defender-actions/dist](./scripts/defender-actions/dist/).
353+
354+
The [defender-autotask CLI](https://www.npmjs.com/package/@openzeppelin/defender-autotask-client) is used to upload the
355+
Action code to Defender. For this to work, a Defender Team API key with `Manage Actions` capabilities is needed. This
356+
can be generated by a Defender team admin under the `Manage` tab on the top right of the UI and then `API Keys` on the
357+
left menu. Best to unselect all capabilities except `Manage Actions`.
358+
359+
Save the Defender Team API key and secret to your `.env` file.
360+
361+
```
362+
# Open Zeppelin Defender Team API key
363+
DEFENDER_TEAM_KEY=
364+
DEFENDER_TEAM_SECRET=
365+
```
366+
367+
The following will bundle the Actions code ready for upload.
368+
369+
```
370+
cd contracts
371+
pnpm rollup -c ./scripts/defender-actions/rollup.config.cjs
372+
```
373+
374+
If you get error like the below, you will need to install `@rollup/rollup-darwin-x64`
375+
376+
```
377+
Error: Cannot find module @rollup/rollup-darwin-x64. npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). Please try `npm i` again after removing both package-lock.json and node_modules directory.
378+
```
379+
380+
If you are on Apple Silicon (M1/M2/M3) and you node is emulated x64, then the following will return `x64` rather than `arm64`.
381+
382+
```
383+
node -p "process.arch"
384+
```
385+
386+
If x64, run the following to install the required rollup package.
387+
388+
```
389+
pnpm add -D @rollup/rollup-darwin-x64
390+
```
391+
392+
The following will upload the different Action bundles to Defender.
393+
394+
```sh
395+
cd contracts
396+
pnpm rollup -c ./scripts/defender-actions/rollup.config.cjs
397+
398+
# Set the DEFENDER_TEAM_KEY and DEFENDER_TEAM_SECRET environment variables in the .env file
399+
400+
# Set the DEBUG environment variable to oeth* for the Defender Action
401+
pnpm hardhat setActionVars --id e2929f53-db56-49b2-b054-35f7df7fc4fb
402+
pnpm hardhat setActionVars --id 6e4f764d-4126-45a5-b7d9-1ab90cd3ffd6
403+
pnpm hardhat setActionVars --id 84988850-6816-4074-8e7b-c11cb2b32e7e
404+
pnpm hardhat setActionVars --id f92ea662-fc34-433b-8beb-b34e9ab74685
405+
pnpm hardhat setActionVars --id b1d831f1-29d4-4943-bb2e-8e625b76e82c
406+
pnpm hardhat setActionVars --id 6567d7c6-7ec7-44bd-b95b-470dd1ff780b
407+
pnpm hardhat setActionVars --id 6a633bb0-aff8-4b37-aaae-b4c6f244ed87
408+
pnpm hardhat setActionVars --id 076c59e4-4150-42c7-9ba0-9962069ac353
409+
pnpm hardhat setActionVars --id ca80b55c-f3f7-4e03-a2f5-ea444645f8d9
410+
pnpm hardhat setActionVars --id f74f24b4-d98b-4181-89cc-6608369b6f91
411+
pnpm hardhat setActionVars --id aa194c13-0dbf-49d2-8e87-70e61f3d71a8
412+
pnpm hardhat setActionVars --id 65b53496-e426-4850-8349-059e63eb2120
413+
pnpm hardhat setActionVars --id a4f8ca5f-7144-469b-b84a-58b30fed72ce
414+
pnpm hardhat setActionVars --id cbddb98e-a0f6-4aa8-bd73-20aa8e81d704
415+
416+
# Mainnet
417+
pnpm hardhat updateAction --id e2929f53-db56-49b2-b054-35f7df7fc4fb --file doAccounting
418+
pnpm hardhat updateAction --id 6e4f764d-4126-45a5-b7d9-1ab90cd3ffd6 --file harvest
419+
pnpm hardhat updateAction --id 84988850-6816-4074-8e7b-c11cb2b32e7e --file sonicRequestWithdrawal
420+
pnpm hardhat updateAction --id f92ea662-fc34-433b-8beb-b34e9ab74685 --file sonicClaimWithdrawals
421+
pnpm hardhat updateAction --id b1d831f1-29d4-4943-bb2e-8e625b76e82c --file claimBribes
422+
pnpm hardhat updateAction --id 6567d7c6-7ec7-44bd-b95b-470dd1ff780b --file manageBribeOnSonic
423+
pnpm hardhat updateAction --id 6a633bb0-aff8-4b37-aaae-b4c6f244ed87 --file managePassThrough
424+
pnpm hardhat updateAction --id 076c59e4-4150-42c7-9ba0-9962069ac353 --file manageBribes
425+
pnpm hardhat updateAction --id ca80b55c-f3f7-4e03-a2f5-ea444645f8d9 --file ousdRebalancer
426+
pnpm hardhat updateAction --id f74f24b4-d98b-4181-89cc-6608369b6f91 --file updateVotemarketEpochs
427+
pnpm hardhat updateAction --id aa194c13-0dbf-49d2-8e87-70e61f3d71a8 --file manageMerklBribes # Mainnet
428+
pnpm hardhat updateAction --id 65b53496-e426-4850-8349-059e63eb2120 --file manageMerklBribes # Base
429+
pnpm hardhat updateAction --id a4f8ca5f-7144-469b-b84a-58b30fed72ce --file claimSSVRewards
430+
431+
# These are Base -> Mainnet & Mainnet -> Base actions
432+
# they share the codebase. The direction of relaying attestations is defined by the
433+
# network of the relayer that is attached to the action
434+
pnpm hardhat updateAction --id bb43e5da-f936-4185-84da-253394583665 --file crossChainRelay
435+
pnpm hardhat updateAction --id e571409b-5399-48e4-bfb2-50b7af9903aa --file crossChainRelay
436+
437+
# One-off action for backfilling a missing tx-level key in Defender KV store
438+
pnpm hardhat updateAction --id cbddb98e-a0f6-4aa8-bd73-20aa8e81d704 --file crossChainRelayBackfillTx
439+
440+
# OUSD Ethereum -> HyperEVM actions
441+
pnpm hardhat updateAction --id 0b852456-96a0-4f1d-9d6c-39e1c6ae9dfc --file crossChainRelayHyperEVM
442+
pnpm hardhat updateAction --id 65f04f74-8da7-4fc5-94b3-96be31bac03b --file crossChainRelayHyperEVM
443+
444+
```
445+
446+
To backfill a missing tx-level cross-chain relay key, set
447+
`HARDCODED_TRANSACTION_ID` and `HARDCODED_DESTINATION_CHAIN_ID` in
448+
`scripts/defender-actions/crossChainRelayBackfillTx.js`, then bundle/upload and
449+
run the `crossChainRelayBackfillTx` Action manually in Defender.
450+
451+
This stores both tx-level keys with value `processed` in Defender's key-value
452+
store:
453+
454+
- `cctp_message_<HARDCODED_TRANSACTION_ID>` (legacy format)
455+
- `cctp_message_<HARDCODED_TRANSACTION_ID>_<cctpDestinationDomainId>` (current
456+
format from `tasks/crossChain.js`, where domain id is derived from the
457+
hardcoded destination chain id: mainnet `1 -> 0`, base `8453 -> 6`, hyperevm
458+
`999 -> 19`)
459+
460+
`rollup` can be installed globally to avoid the `npx` prefix.
320461
Signer construction (KMS via `utils/signersNoHardhat.js`, `DEPLOYER_PK` /
321462
`GOVERNOR_PK` fallbacks, and `IMPERSONATE`) stays exactly as described in the
322463
sections above. The library only handles the nonce wrap; it does not construct

contracts/dev.env

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ SONIC_PROVIDER_URL=https://rpc.soniclabs.com
108108
# ACTION_API_BEARER_TOKEN=test-token
109109
# RUNNER_BASE_URL=http://origin-dollar:8080
110110
# DATABASE_URL=postgresql://nonce:nonce@localhost:5432/nonce_queue
111+
# Safe Transaction Service API key used by Safe-proposal actions
112+
# SAFE_API_KEY=
111113

112114
# Postgres nonce queue lock timeout in seconds (0 = wait forever).
113115
# If lock acquisition exceeds this timeout, the tx send fails and the action exits non-zero.

contracts/docs/ACTIONS.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,55 @@ each run (see notes in `seed_schedules.sql`).
100100
| `stakeValidator` | Convert WETH to ETH and deposit to a validator from the Compounding Staking Strategy |
101101
| `removeValidator` | Remove a registered or exited compounding validator from the SSV cluster |
102102
| `ousdRebalancer` | Plan and execute OUSD strategy rebalancing via the RebalancerModule |
103+
| `proposeVaultStrategyMoves` | Simulate and propose ordered OUSD/OETH strategy movements to the Strategist 2/8 Safe |
103104
| `queueGovernorSixProposal` | Queue a GovernorSix proposal (`--propid`) |
104105
| `executeGovernorSixProposal` | Execute a GovernorSix proposal (`--propid`) |
106+
107+
## Manual / on-demand — Base
108+
109+
| Action | Description |
110+
| --------------------------- | ------------------------------------------------------------------------------------ |
111+
| `proposeVaultStrategyMoves` | Simulate and propose ordered SuperOETH strategy movements to the Strategist 2/8 Safe |
112+
113+
### Vault strategy proposal parameters
114+
115+
Talos locks the Hardhat `--network` option, so there are two disabled manual
116+
schedules: `propose_vault_strategy_moves_mainnet` for Ethereum and
117+
`propose_vault_strategy_moves_base` for Base. Before selecting "Run now", edit
118+
`--vault` and `--moves` on the Ethereum schedule, or `--moves` on the Base
119+
schedule. The underlying Hardhat action remains shared across both chains.
120+
121+
`proposeVaultStrategyMoves` accepts ordered, semicolon-separated movements. A
122+
strategy can be a deployment name or address:
123+
124+
```sh
125+
pnpm hardhat proposeVaultStrategyMoves \
126+
--network mainnet \
127+
--vault OUSD \
128+
--moves "withdraw:OUSDMorphoV2StrategyProxy:500000;deposit:OUSDCurveAMOProxy:250000"
129+
```
130+
131+
Supported operations are `deposit:<strategy>:<amount>`,
132+
`withdraw:<strategy>:<amount>`, and `withdrawAll:<strategy>`. Amounts are human
133+
units of the Vault's backing asset. Operations execute in the supplied order.
134+
135+
By default the action starts a temporary Hardhat fork, executes
136+
`rebase -> snapshot -> movements`, derives `expectedProfit` and
137+
`expectedVaultChange`, validates `checkDelta`, and then estimates the completed
138+
Safe MultiSend before proposing it. The atomic proposal is always
139+
`rebase -> snapshot -> movements -> checkDelta`.
140+
141+
- `--skip-fork` skips the local fork and requires both `--expected-profit` and
142+
`--expected-vault-change`.
143+
- `--skip-estimation` skips only the final Safe estimation.
144+
- `--dryrun` runs all enabled checks without signing or proposing.
145+
- `--nonce <n>` targets an unexecuted Safe nonce so a pending proposal can be
146+
replaced. Without it, the next available Safe nonce is used.
147+
- `--profit-variance` and `--vault-change-variance` override the defaults:
148+
OUSD `100/100`, OETH `1/1`, and SuperOETH `1/10`.
149+
150+
The runner requires `SAFE_API_KEY`. Its active KMS or Defender signer must also
151+
be registered, by a Safe owner, as a Safe Transaction Service delegate scoped
152+
to `0x4FF1b9D9ba8558F5EAfCec096318eA0d8b541971` on both Ethereum and Base.
153+
Delegation only permits proposal submission; it does not count toward the
154+
Safe's 2/8 owner confirmations. A Safe module is not used.

contracts/migrations/seed_schedules.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ INSERT INTO schedules (product, name, command, cron_expr, timezone, enabled, not
5555
('origin-dollar', 'module_rebase_base', 'cd /app && pnpm exec tsx tasks/run.ts permissionedRebase --network base', '15 10,22 * * *', 'UTC', false, NULL),
5656
('origin-dollar', 'module_rebase_sonic', 'cd /app && pnpm exec tsx tasks/run.ts permissionedRebase --network sonic', '15 10,22 * * *', 'UTC', false, NULL),
5757
('origin-dollar', 'ousd_rebalancer', 'cd /app && pnpm exec tsx tasks/run.ts ousdRebalancer --network mainnet', '0 0 1 1 *', 'UTC', false, 'Manual: Run now to rebalance OUSD Morpho strategies'),
58+
('origin-dollar', 'propose_vault_strategy_moves_mainnet', 'cd /app && pnpm exec tsx tasks/run.ts proposeVaultStrategyMoves --network mainnet --vault OUSD --moves "withdrawAll:REPLACE_WITH_STRATEGY"', '0 0 1 1 *', 'UTC', false, 'Manual Ethereum launcher: replace vault and moves before Run now. Proposes a Strategist Safe transaction; never enable this schedule.'),
59+
('origin-dollar', 'propose_vault_strategy_moves_base', 'cd /app && pnpm exec tsx tasks/run.ts proposeVaultStrategyMoves --network base --vault SuperOETH --moves "withdrawAll:REPLACE_WITH_STRATEGY"', '0 0 1 1 *', 'UTC', false, 'Manual Base launcher: replace moves before Run now. Proposes a Strategist Safe transaction; never enable this schedule.'),
5860
('origin-dollar', 'queue_proposal', 'cd /app && pnpm exec tsx tasks/run.ts queueGovernorSixProposal --network mainnet', '0 0 1 1 *', 'UTC', false, 'Manual: add --propid then Run now'),
5961
('origin-dollar', 'execute_proposal', 'cd /app && pnpm exec tsx tasks/run.ts executeGovernorSixProposal --network mainnet', '0 0 1 1 *', 'UTC', false, 'Manual: add --propid then Run now')
6062
ON CONFLICT (product, name) DO NOTHING;

contracts/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@
143143
"@lodestar/state-transition": "^1.44.0",
144144
"@lodestar/types": "^1.44.0",
145145
"@lodestar/utils": "^1.44.0",
146+
"@safe-global/api-kit": "^5.0.1",
147+
"@safe-global/protocol-kit": "^8.0.3",
148+
"@safe-global/types-kit": "^4.0.1",
146149
"@types/pg": "^8.20.0",
147150
"origin-morpho-utils": "^0.1.1",
148151
"pg": "^8.20.0",

0 commit comments

Comments
 (0)