Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
e2e88db
chore: Add Yearn BORG architectures
Detoo Apr 10, 2025
ee42434
chore: Add member-management workflow
Detoo Apr 10, 2025
3c7503a
chore: Use SnapshotExecutor for member-management workflow
Detoo Apr 11, 2025
f8748ed
chore: Clarify BORG modules ownership and member management
Detoo Apr 14, 2025
a1108fb
chore: Simplify member management voting workflow
Detoo Apr 14, 2025
14f12e8
feat: Pull previous SnapShotExecutor because it fits the requirements…
Detoo Apr 14, 2025
9a2419e
wip: feat: Yearn BORG deploy scripts and tests
Detoo Apr 15, 2025
b277486
wip: feat: Fix typos and add more tests
Detoo Apr 15, 2025
8b23d0e
test: Fork ychad.eth as Safe for tests
Detoo Apr 15, 2025
c199382
feat: Deploy scripts to accommodate external Safe TXs
Detoo Apr 15, 2025
379986f
feat: Simplify deployment process
Detoo Apr 15, 2025
c184272
chore: Update README and remove unused comments
Detoo Apr 15, 2025
8b9af67
feat: Simplify SnapShotExecutor's cancel process. Add tests
Detoo Apr 16, 2025
06a8fb5
chore: Plan for on-chain governance transition
Detoo Apr 16, 2025
c0597f0
chore: Simplify on-chain governance architectures
Detoo Apr 16, 2025
383e4a9
wip: feat: Restrict admin operations
Detoo Apr 17, 2025
43cb2de
feat: Restrict admin operations. Add tests
Detoo Apr 17, 2025
b318b70
feat: Update yearn BORG ownership and admin permissions
Detoo Apr 17, 2025
db99ecc
feat: Implement sudoImplant for DAO/BORG co-approval on admin operations
Detoo Apr 17, 2025
59b2214
chore: Update comments
Detoo Apr 17, 2025
ee6ecaa
test: Add sudoImplant tests
Detoo Apr 18, 2025
23a527b
chore: Add more comments and README
Detoo Apr 18, 2025
898c25d
test: on-chain governance transition
Detoo Apr 18, 2025
4192522
Update README-yearnBorg.md
lex-node Apr 19, 2025
800b9d9
feat: Block SudoImplant from disabling itself to prevent potential us…
Detoo Apr 20, 2025
3bee793
test: Revise on-chain governance transition to prevent potential user…
Detoo Apr 20, 2025
7b10491
test: Revise on-chain governance architectures to allow more flexible…
Detoo Apr 20, 2025
5e01785
test: Revise tests and descriptions
Detoo Apr 21, 2025
34d9a19
feat: snapShotExecutor oracle deadman switch and transfer
Detoo Apr 21, 2025
4157544
feat: ejectImplant to support disallowing self-eject with threshold r…
Detoo Apr 22, 2025
1b0e381
Revert "test: Revise on-chain governance architectures to allow more …
Detoo Apr 28, 2025
62c231f
chore: Update README regarding on-chain governance transition process…
Detoo Apr 28, 2025
37d3829
chore: clean up
Detoo Apr 28, 2025
feecb59
Merge pull request #39 from MetaLex-Tech/lex-node-patch-3
Detoo Apr 28, 2025
2c53941
feat: Allow SnapshotExecutor to transfer oracle through proposal, and…
Detoo Apr 28, 2025
7b6f938
chore: Revise README
Detoo Apr 29, 2025
7d45159
feat: Updatable SnapShotExecutor.oracleTtl in preparation for on-chai…
Detoo Apr 29, 2025
1d3e514
feat: Extend SnapShotExecutor cancellation waiting period for more re…
Detoo Apr 29, 2025
2f3b49f
chore: misc code quality improvements
Detoo Apr 29, 2025
45c0840
feat: Clarify waiting period vs expiry on snapShotExecutor
Detoo May 1, 2025
57c4264
fix: Additional checks to prevent duplicate proposals
Detoo May 17, 2025
97b6d94
chore: Add scripts to replace SnapShotExecutor
Detoo May 17, 2025
00e1628
First pass for blocking delegateCalls
merisman Jun 2, 2025
94653d2
feat: Transfer borgCore ownership to SnapShotExecutor for future poli…
Detoo Jun 2, 2025
9394785
test: BORG policy management through co-approval
Detoo Jun 2, 2025
e2fa8b7
Merge branch 'feat/yearnBorg' into feat/yearnBorg-whitelist-coapproval
Detoo Jun 2, 2025
504ccc5
feat: Whitelist MultiSendCallOnly while blocking all other delegateca…
Detoo Jun 3, 2025
7eb2da0
chore: Add "Restricted Advanced Operations" section to README
Detoo Jun 3, 2025
4393296
Updating to keep logic the same for whitelist, but new for blacklist.
merisman Jun 4, 2025
05925a7
Updating toggle for blacklist mode.
merisman Jun 5, 2025
3132d36
chore: Optimize README sections
Detoo Jun 5, 2025
643f057
Merge remote-tracking branch 'origin/feat/yearnBorg-Blacklist' into f…
Detoo Jun 5, 2025
37e5058
Merge pull request #1 from MetaLex-Tech/feat/yearnBorg-whitelist-coap…
Detoo Jun 5, 2025
531f382
chore: Add CHANGELOG.md
Detoo Jun 5, 2025
24977db
feat: Change Yearn BORG oracle TTL per requested
Detoo Jun 13, 2025
b9d4338
Fix/audit items (#4)
Detoo Jun 17, 2025
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
cache/
out/
.env
.env*
test-command.txt
broadcast/

.DS_Store
.idea/
/broadcast_bk
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- src/implants/sudoImplant.sol
- A Module (implant) for enforcing BORG, DAO co-approvals on Safe admin operations such as toggling Modules or setting Guards

- src/libs/governance/snapShotExecutor.sol
- An off-chain (snapshot) voting coordinator contract that enforces BORG, DAO co-approvals on proposals

- scripts/yearnBorg.s.sol
- Scripts for deploying Yearn BORG contracts

### Updated

- src/borgCore.sol
- Blocks delegate calls by default in blacklist mode and allow whitelisting specific contracts
- Maintains the same behaviors in whitelist mode

- src/implants/ejectImplant.sol
- Allows admin to allow/disallow a member to reduce threshold when resigning
207 changes: 207 additions & 0 deletions README-yearnBorg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
# Yearn BORG

## BORG Architectures

| Entity | Descriptions |
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| BORG Core | A Safe Guard contract restricting ychad's administrative authority |
| Eject Implant | A Safe Module contract for ychad member management, integrated with Snapshot Executor to enforce DAO co-approval |
| Sudo Implant | A Safe Module contract for ychad Guard/Module management, integrated with Snapshot Executor to enforce DAO co-approval |
| Snapshot Executor | A smart contract enabling co-approval between a DAO and ychad |
| oracle | A MetaLex service for coordinating Yearn Snapshot voting and recording results on-chain. It is set to be replaced by Yearn's own on-chain governance contract in the future |

```mermaid
graph TD
ychad[ychad.eth<br/>6/9 signers]
ychadSigner[Signer EOA]
yearnDaoVoting[Yearn DAO Voting Snapshot]

oracleAddr[oracle]

borg{{Yearn BORG<br>BORG Core}}

subgraph implants["Implants (Modules)"]
ejectImplant{{Eject Implant}}
sudoImplant{{Sudo Implant}}
end

snapshotExecutor[Snapshot Executor]

borg -->|"guard"| ychad


%% implants -->|modules| ychad

ychadSigner -->|signer| ychad
ychadSigner -->|"selfEject()"| ejectImplant

oracleAddr -->|"oracle<br>propose(admin operation)"| snapshotExecutor
oracleAddr -->|monitor| yearnDaoVoting

ychad -->|"owner<br>execute(proposalId)"| snapshotExecutor

snapshotExecutor -->|"owner<br>policy operation()"| borg
snapshotExecutor -->|"owner<br>guard & module management operation()"| sudoImplant
snapshotExecutor -->|"owner<br>member management operation()"| ejectImplant

%% Styling (optional, Mermaid supports limited styling)
classDef default fill:#191918,stroke:#fff,stroke-width:2px,color:#fff;
classDef borg fill:#191918,stroke:#E1FE52,stroke-width:2px,color:#E1FE52;
classDef yearn fill:#191918,stroke:#2C68DB,stroke-width:2px,color:#2C68DB;
classDef safe fill:#191918,stroke:#76FB8D,stroke-width:2px,color:#76FB8D;
classDef todo fill:#191918,stroke:#F09B4A,stroke-width:2px,color:#F09B4A;
class borg borg;
class ejectImplant borg;
class sudoImplant borg;
class snapshotExecutor borg;
class oracleAddr borg;
class ychad yearn;
class ychadSigner yearn;
class yearnDaoVoting yearn;
```

## Initial BORGing of ychad

To implement the BORG, ychad unilaterally:
- determines initial signer set (i.e., keep existing signers)
- approves/adopts legal agreements (Cayman Foundation)
- installs SAFE modules (BORG implants) and guard (BORG core)

If desired, can seek prior DAO social approval for these changes (and this is likely best for legitimacy), but no DAO onchain actions or legal actions are required.

## Restricted Admin Operations

Once ychad is "BORGed", the following operations will require bilateral approval of the DAO and ychad. Onchain, this means 'blacklisting' certain unilateral SAFE operations that would otherwise be possible, instead requiring DAO/ychad co-approval of such actions:

- Add / remove / swap signers / change threshold
- Add / disable Modules
- Set Guards

### Co-approval Workflows

The process for bilateral ychad / DAO approvals will be as follows:

1. Operation is initiated on the MetaLeX OS webapp
2. A Snapshot proposal will be submitted via API using Yearn's existing voting settings
3. MetaLeX's Snapshot oracle (`oracle`) will submit the results on-chain to an executor contract (`Snapshot Executor`), which will have the proposed transaction pending for co-approval
4. After a waiting period, ychad can co-approve it by executing the operation through the MetaLeX OS webapp
5. After an extra waiting period, anyone can cancel the proposal if it hasn't been executed

This essentially means that ychad cannot 'breach' its basic 'agreement' with the DAO by changing the meta-governance rules (ychad signer membership, ychad approval threshold). It also adds an extra security layer as ychad members cannot collude to change these fundamental rules. All other operations would remain under ychad's sole discretion.

### Future On-chain Governance Transition

Yearn's Snapshot governance will be replaced with an on-chain governance at some point (ex. `YearnGovExecutor`).
Technically, the transition is done by having `YearnGovExecutor` serve as the new `oracle`.
Therefore, `YearnGovernance` must meet the following requirements:

- `YearnGovernance` can call `SnapShotExecutor.propose(target, value, cdata, description)`, which contains the instructions of the admin operation

The transition process from Snapshot to on-chain governance is listed as follows:

1. A final Snapshot proposal will be submitted to assign `YearnGovExecutor` as the new oracle of `Snapshot Executor`
2. Once co-approved and executed by ychad, the transition process is complete

After the transition, the co-approval process will become:

1. Operation is initiated on the MetaLeX OS webapp, or, alternatively, through a third-party UI if the calldata is prepared
2. An on-chain proposal will be submitted to `YearnGovExecutor`
3. Once the vote passed, `YearnGovExecutor` will propose the results to the executor contract (`Snapshot Executor`), which will have the proposed transaction pending for co-approval
4. After a waiting period, ychad can co-approve it by executing the operation through the MetaLeX OS webapp
5. After an extra waiting period, anyone can cancel the proposal if it hasn't been executed

### Module Addition

New Modules grant ychad privileges to bypass Guards restrictions, therefore it requires DAO co-approval via [Co-approval Workflows](#co-approval-workflows).

### Guard & Module Updates

In exceptional circumstances, ychad can propose the removal of the Guard via [Co-approval Workflows](#co-approval-workflows).
Upon DAO co-approval and execution, ychad will no longer face any restriction on administrative operations.

Likewise, ychad can propose adding or removing Modules through [Co-approval Workflows](#co-approval-workflows) as well.
For safety, it cannot remove the `SudoImplant` Module itself.

## Member Self-resignation

A ychad member can unilaterally resign by calling `EjectImplant.selfEject(false)` without approval. The Safe contract ensures threshold validity.
Members are prohibited from calling `EjectImplant.selfEject(true)` as it would alter the multisig threshold. Consequently, they cannot self-resign when the remaining member count equals the threshold.

## Restricted Advanced Operations

Once ychad is "BORGed," the following operations are restricted for security reasons unless explicitly whitelisted:

- Transactions executed in `DelegateCall` mode

However, to ensure a seamless user experience, commonly used advanced operations are preemptively whitelisted, including:

- Batch Transactions (via `MultiSendCallOnly`)

Note: `MultiSendCallOnly` is whitelisted, but `MultiSend` is not, as it permits arbitrary `delegatecall`, posing security risks.
Operations relying on `MultiSend`, such as manual fund distributions, can typically be performed using safer alternatives, like custom vetted contracts.

## Key Parameters

| ID | Value | Descriptions |
|--------------------------------|------------|----------------------------------------------------------------------------------------------------------------------------|
| `borgIdentifier` | Yearn BORG | BORG name |
| `borgMode` | blacklist | Every operation is allowed unless blacklisted |
| `borgType` | 3 | Dev BORG |
| `snapShotWaitingPeriod` | 3 days | Waiting period before a proposal can be executed |
| `snapShotCancelPeriod` | 7 days | Extra waiting period before a proposal can be cancelled |
| `snapShotPendingProposalLimit` | 3 | Maximum pending proposals |
| `snapShotTtl` | 30 days | Duration of inactivity before an oracle is deemed expired and can be replaced by ychad |
| `oracle` | `address` | MetaLeX Snapshot oracle (or Yearn on-chain governance contract after [transition](#future-on-chain-governance-transition)) |

## Deployment

1. Run the deploy script
```bash
forge script scripts/yearnBorg.s.sol --rpc-url <RPC URL> --optimize --optimizer-runs 200 --use solc:0.8.20 --via-ir --broadcast
```

2. If got the following errors, force clean the cache with flag `--force`
```
Error: buffer overrun while deserializing
```

3. Take notes of the output Safe TXs (for setting guard & adding modules), for examples:
```
Safe TXs:
# 0
to: 0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52
value: 0
data:
0x610b59250000000000000000000000006faa027c062868424287af2faef3ddaca802bff7

# 1
to: 0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52
value: 0
data:
0x610b5925000000000000000000000000a21f6d7aa0b320b8669caef53f790b1a2ac838d7

# 2
to: 0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52
value: 0
data:
0xe19a9dd9000000000000000000000000bc19387f5b8ae73fad41cd2294f928a735c60534
```
4. Ask ychad to sign and execute the Safe TXs

## Tests

### Integration Tests

Test the deployment scripts and verify the results.

```bash
forge test --optimize --optimizer-runs 200 --use solc:0.8.20 --via-ir --fork-url <eth-mainnet-archive-endpoint> --fork-block-number 22268905 --mc YearnBorgTest
```

### Acceptance Tests

Verify a specific deployment results.

```bash
forge test --optimize --optimizer-runs 200 --use solc:0.8.20 --via-ir --fork-url <eth-mainnet-archive-endpoint> --fork-block-number <deployment-block-number> --mc YearnBorgAcceptanceTest
```
Loading