Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,147 @@ Building the runner image installs the optional `@oplabs/talos-client` peer
dependency from GitHub Packages. Set `TALOS_PACKAGE_TOKEN` to a PAT with
`read:packages` access before running `docker compose build`.

Actions that propose transactions through the Safe Transaction Service require
`SAFE_API_KEY`. The active Talos signer must be registered separately on each
chain as a delegate for the target Safe. A delegate can submit a proposal but
does not provide an owner confirmation or reduce the Safe threshold.

### Defender Relayer

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.

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.

```
export DEFENDER_API_KEY=
export DEFENDER_API_SECRET=
```

Once you have finished sending your transactions, the API key for hte Relayer account should be deleted in Defender and the environment variables unset.

```
unset DEFENDER_API_KEY
unset DEFENDER_API_SECRET
```

### Deploying Defender Actions

Actions are used to run operational jobs are specific times or intervals.

[rollup](https://rollupjs.org/) is used to bundle Actions source code in
[/scripts/defender-actions](./scripts/defender-actions) into a single file that can be uploaded to Defender. The
implementation was based off
[Defender Actions example using Rollup](https://github.com/OpenZeppelin/defender-autotask-examples/tree/master/rollup).
The rollup config is in [/scripts/defender-actions/rollup.config.cjs](./scripts/defender-actions/rollup.config.cjs). The
outputs are written to task specific folders under [/scripts/defender-actions/dist](./scripts/defender-actions/dist/).

The [defender-autotask CLI](https://www.npmjs.com/package/@openzeppelin/defender-autotask-client) is used to upload the
Action code to Defender. For this to work, a Defender Team API key with `Manage Actions` capabilities is needed. This
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
left menu. Best to unselect all capabilities except `Manage Actions`.

Save the Defender Team API key and secret to your `.env` file.

```
# Open Zeppelin Defender Team API key
DEFENDER_TEAM_KEY=
DEFENDER_TEAM_SECRET=
```

The following will bundle the Actions code ready for upload.

```
cd contracts
pnpm rollup -c ./scripts/defender-actions/rollup.config.cjs
```

If you get error like the below, you will need to install `@rollup/rollup-darwin-x64`

```
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.
```

If you are on Apple Silicon (M1/M2/M3) and you node is emulated x64, then the following will return `x64` rather than `arm64`.

```
node -p "process.arch"
```

If x64, run the following to install the required rollup package.

```
pnpm add -D @rollup/rollup-darwin-x64
```

The following will upload the different Action bundles to Defender.

```sh
cd contracts
pnpm rollup -c ./scripts/defender-actions/rollup.config.cjs

# Set the DEFENDER_TEAM_KEY and DEFENDER_TEAM_SECRET environment variables in the .env file

# Set the DEBUG environment variable to oeth* for the Defender Action
pnpm hardhat setActionVars --id e2929f53-db56-49b2-b054-35f7df7fc4fb
pnpm hardhat setActionVars --id 6e4f764d-4126-45a5-b7d9-1ab90cd3ffd6
pnpm hardhat setActionVars --id 84988850-6816-4074-8e7b-c11cb2b32e7e
pnpm hardhat setActionVars --id f92ea662-fc34-433b-8beb-b34e9ab74685
pnpm hardhat setActionVars --id b1d831f1-29d4-4943-bb2e-8e625b76e82c
pnpm hardhat setActionVars --id 6567d7c6-7ec7-44bd-b95b-470dd1ff780b
pnpm hardhat setActionVars --id 6a633bb0-aff8-4b37-aaae-b4c6f244ed87
pnpm hardhat setActionVars --id 076c59e4-4150-42c7-9ba0-9962069ac353
pnpm hardhat setActionVars --id ca80b55c-f3f7-4e03-a2f5-ea444645f8d9
pnpm hardhat setActionVars --id f74f24b4-d98b-4181-89cc-6608369b6f91
pnpm hardhat setActionVars --id aa194c13-0dbf-49d2-8e87-70e61f3d71a8
pnpm hardhat setActionVars --id 65b53496-e426-4850-8349-059e63eb2120
pnpm hardhat setActionVars --id a4f8ca5f-7144-469b-b84a-58b30fed72ce
pnpm hardhat setActionVars --id cbddb98e-a0f6-4aa8-bd73-20aa8e81d704

# Mainnet
pnpm hardhat updateAction --id e2929f53-db56-49b2-b054-35f7df7fc4fb --file doAccounting
pnpm hardhat updateAction --id 6e4f764d-4126-45a5-b7d9-1ab90cd3ffd6 --file harvest
pnpm hardhat updateAction --id 84988850-6816-4074-8e7b-c11cb2b32e7e --file sonicRequestWithdrawal
pnpm hardhat updateAction --id f92ea662-fc34-433b-8beb-b34e9ab74685 --file sonicClaimWithdrawals
pnpm hardhat updateAction --id b1d831f1-29d4-4943-bb2e-8e625b76e82c --file claimBribes
pnpm hardhat updateAction --id 6567d7c6-7ec7-44bd-b95b-470dd1ff780b --file manageBribeOnSonic
pnpm hardhat updateAction --id 6a633bb0-aff8-4b37-aaae-b4c6f244ed87 --file managePassThrough
pnpm hardhat updateAction --id 076c59e4-4150-42c7-9ba0-9962069ac353 --file manageBribes
pnpm hardhat updateAction --id ca80b55c-f3f7-4e03-a2f5-ea444645f8d9 --file ousdRebalancer
pnpm hardhat updateAction --id f74f24b4-d98b-4181-89cc-6608369b6f91 --file updateVotemarketEpochs
pnpm hardhat updateAction --id aa194c13-0dbf-49d2-8e87-70e61f3d71a8 --file manageMerklBribes # Mainnet
pnpm hardhat updateAction --id 65b53496-e426-4850-8349-059e63eb2120 --file manageMerklBribes # Base
pnpm hardhat updateAction --id a4f8ca5f-7144-469b-b84a-58b30fed72ce --file claimSSVRewards

# These are Base -> Mainnet & Mainnet -> Base actions
# they share the codebase. The direction of relaying attestations is defined by the
# network of the relayer that is attached to the action
pnpm hardhat updateAction --id bb43e5da-f936-4185-84da-253394583665 --file crossChainRelay
pnpm hardhat updateAction --id e571409b-5399-48e4-bfb2-50b7af9903aa --file crossChainRelay

# One-off action for backfilling a missing tx-level key in Defender KV store
pnpm hardhat updateAction --id cbddb98e-a0f6-4aa8-bd73-20aa8e81d704 --file crossChainRelayBackfillTx

# OUSD Ethereum -> HyperEVM actions
pnpm hardhat updateAction --id 0b852456-96a0-4f1d-9d6c-39e1c6ae9dfc --file crossChainRelayHyperEVM
pnpm hardhat updateAction --id 65f04f74-8da7-4fc5-94b3-96be31bac03b --file crossChainRelayHyperEVM

```

To backfill a missing tx-level cross-chain relay key, set
`HARDCODED_TRANSACTION_ID` and `HARDCODED_DESTINATION_CHAIN_ID` in
`scripts/defender-actions/crossChainRelayBackfillTx.js`, then bundle/upload and
run the `crossChainRelayBackfillTx` Action manually in Defender.

This stores both tx-level keys with value `processed` in Defender's key-value
store:

- `cctp_message_<HARDCODED_TRANSACTION_ID>` (legacy format)
- `cctp_message_<HARDCODED_TRANSACTION_ID>_<cctpDestinationDomainId>` (current
format from `tasks/crossChain.js`, where domain id is derived from the
hardcoded destination chain id: mainnet `1 -> 0`, base `8453 -> 6`, hyperevm
`999 -> 19`)

`rollup` can be installed globally to avoid the `npx` prefix.
Signer construction (KMS via `utils/signersNoHardhat.js`, `DEPLOYER_PK` /
`GOVERNOR_PK` fallbacks, and `IMPERSONATE`) stays exactly as described in the
sections above. The library only handles the nonce wrap; it does not construct
Expand Down
2 changes: 2 additions & 0 deletions contracts/dev.env
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ SONIC_PROVIDER_URL=https://rpc.soniclabs.com
# ACTION_API_BEARER_TOKEN=test-token
# RUNNER_BASE_URL=http://origin-dollar:8080
# DATABASE_URL=postgresql://nonce:nonce@localhost:5432/nonce_queue
# Safe Transaction Service API key used by Safe-proposal actions
# SAFE_API_KEY=

# Postgres nonce queue lock timeout in seconds (0 = wait forever).
# If lock acquisition exceeds this timeout, the tx send fails and the action exits non-zero.
Expand Down
50 changes: 50 additions & 0 deletions contracts/docs/ACTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,55 @@ each run (see notes in `seed_schedules.sql`).
| `stakeValidator` | Convert WETH to ETH and deposit to a validator from the Compounding Staking Strategy |
| `removeValidator` | Remove a registered or exited compounding validator from the SSV cluster |
| `ousdRebalancer` | Plan and execute OUSD strategy rebalancing via the RebalancerModule |
| `proposeVaultStrategyMoves` | Simulate and propose ordered OUSD/OETH strategy movements to the Strategist 2/8 Safe |
| `queueGovernorSixProposal` | Queue a GovernorSix proposal (`--propid`) |
| `executeGovernorSixProposal` | Execute a GovernorSix proposal (`--propid`) |

## Manual / on-demand — Base

| Action | Description |
| --------------------------- | ------------------------------------------------------------------------------------ |
| `proposeVaultStrategyMoves` | Simulate and propose ordered SuperOETH strategy movements to the Strategist 2/8 Safe |

### Vault strategy proposal parameters

Talos locks the Hardhat `--network` option, so there are two disabled manual
schedules: `propose_vault_strategy_moves_mainnet` for Ethereum and
`propose_vault_strategy_moves_base` for Base. Before selecting "Run now", edit
`--vault` and `--moves` on the Ethereum schedule, or `--moves` on the Base
schedule. The underlying Hardhat action remains shared across both chains.

`proposeVaultStrategyMoves` accepts ordered, semicolon-separated movements. A
strategy can be a deployment name or address:

```sh
pnpm hardhat proposeVaultStrategyMoves \
--network mainnet \
--vault OUSD \
--moves "withdraw:OUSDMorphoV2StrategyProxy:500000;deposit:OUSDCurveAMOProxy:250000"
```

Supported operations are `deposit:<strategy>:<amount>`,
`withdraw:<strategy>:<amount>`, and `withdrawAll:<strategy>`. Amounts are human
units of the Vault's backing asset. Operations execute in the supplied order.

By default the action starts a temporary Hardhat fork, executes
`rebase -> snapshot -> movements`, derives `expectedProfit` and
`expectedVaultChange`, validates `checkDelta`, and then estimates the completed
Safe MultiSend before proposing it. The atomic proposal is always
`rebase -> snapshot -> movements -> checkDelta`.

- `--skip-fork` skips the local fork and requires both `--expected-profit` and
`--expected-vault-change`.
- `--skip-estimation` skips only the final Safe estimation.
- `--dryrun` runs all enabled checks without signing or proposing.
- `--nonce <n>` targets an unexecuted Safe nonce so a pending proposal can be
replaced. Without it, the next available Safe nonce is used.
- `--profit-variance` and `--vault-change-variance` override the defaults:
OUSD `100/100`, OETH `1/1`, and SuperOETH `1/10`.

The runner requires `SAFE_API_KEY`. Its active KMS or Defender signer must also
be registered, by a Safe owner, as a Safe Transaction Service delegate scoped
to `0x4FF1b9D9ba8558F5EAfCec096318eA0d8b541971` on both Ethereum and Base.
Delegation only permits proposal submission; it does not count toward the
Safe's 2/8 owner confirmations. A Safe module is not used.
2 changes: 2 additions & 0 deletions contracts/migrations/seed_schedules.sql
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ INSERT INTO schedules (product, name, command, cron_expr, timezone, enabled, not
('origin-dollar', 'module_rebase_base', 'cd /app && pnpm exec tsx tasks/run.ts permissionedRebase --network base', '15 10,22 * * *', 'UTC', false, NULL),
('origin-dollar', 'module_rebase_sonic', 'cd /app && pnpm exec tsx tasks/run.ts permissionedRebase --network sonic', '15 10,22 * * *', 'UTC', false, NULL),
('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'),
('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.'),
('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.'),
('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'),
('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')
ON CONFLICT (product, name) DO UPDATE SET command = EXCLUDED.command;
3 changes: 3 additions & 0 deletions contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@
"@lodestar/state-transition": "^1.44.0",
"@lodestar/types": "^1.44.0",
"@lodestar/utils": "^1.44.0",
"@safe-global/api-kit": "^5.0.1",
"@safe-global/protocol-kit": "^8.0.3",
"@safe-global/types-kit": "^4.0.1",
"@types/pg": "^8.20.0",
"origin-morpho-utils": "^0.1.1",
"pg": "^8.20.0",
Expand Down
Loading
Loading