-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add eip-zodiac #5005
Merged
Merged
add eip-zodiac #5005
Changes from 10 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
4e78db4
add eip-zodiac
auryn-macmillan ef0721a
Add security considerations and some minor fixes
auryn-macmillan 72560c2
Add ETHMagicians discussion link
auryn-macmillan 5f63787
Update EIPS/eip-zodiac.md
auryn-macmillan b3a9056
Update EIPS/eip-zodiac.md
auryn-macmillan 7cd9eac
Update EIPS/eip-zodiac.md
auryn-macmillan 2f23be7
Update EIPS/eip-zodiac.md
auryn-macmillan 17e0ea7
Remove external links to Zodiac & external imports
auryn-macmillan 3ecd82f
Rename EIP file to add ERC number
auryn-macmillan 290f074
Update EIPS/eip-5005.md
auryn-macmillan 42fd618
Update EIPS/eip-5005.md
auryn-macmillan abec040
Update EIPS/eip-5005.md
auryn-macmillan 892341d
Remove external links
auryn-macmillan c095b78
Fix gramma
auryn-macmillan 8c8e060
Small sentance structure fix
auryn-macmillan de1b7fa
Remove license and external links
auryn-macmillan 91e5fa5
Update EIPS/eip-5005.md
MicahZoltu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
--- | ||
eip: 5005 | ||
title: Zodiac | ||
description: A composable design philosophy for DAOs. | ||
author: Auryn Macmillan (@auryn-macmillan), Kei Kreutler (@keikreutler) | ||
discussions-to: https://ethereum-magicians.org/t/eip-zodiac-a-composable-design-philosophy-for-daos/8963 | ||
status: Draft | ||
type: Standards Track | ||
category: ERC | ||
created: 2022-04-14 | ||
requires: 165 | ||
--- | ||
|
||
## Abstract | ||
Zodiac is a philosophy and open standard for composable and interoperable DAO tooling. The key insight is that by separating account (thing that holds tokens, controls systems, and is referenced by others) from the logic that controls it, and making the account agnostic to the logic that controls it, we can create a DAO ecosystem that is much more composable and interoperable, along with being compatible with the vast majority of existing DAO tooling. In short, Zodiac encourages DAOs to use an "avatar" contract (like the Gnosis Safe) as their account, and to then control that avatar with just about any combination of DAO tools and frameworks (Aragon, Colony, Compound/OZ Governor, DAOStack, Moloch, Orca, Tribute, etc). | ||
auryn-macmillan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Motivation | ||
Currently, most DAO tools and frameworks are built as somewhat monolithic systems. Wherein account and control logic are coupled, either in the same contract or in a tightly bound system of contracts. This needlessly inhibits the future flexibility of organizations using these tools and encourages platform lock-in via extraordinarily high switching costs. | ||
auryn-macmillan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
By using the Zodiac standard to decouple account and control logic, organizations are able to: | ||
1. Enable flexible, module-based control of programmable accounts | ||
2. Easily switch between frameworks without unnecessary overhead. | ||
3. Enable multiple control mechanism in parallel. | ||
4. Enable cross-chain / cross-layer governance. | ||
5. Progressively decentralize their governance as their project and community matures. | ||
|
||
## Specification | ||
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. | ||
|
||
The Zodiac standard consists of four key concepts Avatars, Modules, Modifiers, and Guards: | ||
auryn-macmillan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
1. **Avatars** are programmable Ethereum accounts, like the [Gnosis Safe](https://gnosis-safe.io). Avatars are the address that holds balances, owns systems, executes transaction, is referenced externally, and ultimately represents your DAO. Avatars MUST expose the `IAvatar` interface. | ||
auryn-macmillan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
2. **Modules** are contracts enabled by an Avatar that implement some control logic. | ||
3. **Modifiers** are contracts that sit between Modules and Avatars to modify the Module's behavior. For example, they might enforce a delay on all functions a Module attempts to execute or limit the scope of transactions that can be initiated by the module. Modifiers MUST expose the `IAvatar` interface. | ||
auryn-macmillan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
4. **Guards** are contracts that MAY be enabled on Modules or Modifiers and implement pre- or post-checks on each transaction that the Module or Modifier they are enabled on executes. This allows Avatars to do things like limit the scope of addresses and functions that a Module or Modifier can call or ensure a certain state is never changed by a Module or Modifier. Guards SHOULD expose the `IGuard` interface. Modules, Modifiers, and Avatars that wish to be guardable MUST inherit `Guardable`, MUST call `checkTransaction()` before triggering execution on their target, and MUST call `checkAfterExecution()` after execution is complete. | ||
auryn-macmillan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```solidity | ||
/// @title Zodiac Avatar - A contract that manages modules that can execute transactions via this contract. | ||
|
||
pragma solidity >=0.7.0 <0.9.0; | ||
|
||
import "./Enum.sol"; | ||
|
||
|
||
interface IAvatar { | ||
/// @dev Enables a module on the avatar. | ||
/// @notice Can only be called by the avatar. | ||
/// @notice Modules should be stored as a linked list. | ||
/// @notice Must emit EnabledModule(address module) if successful. | ||
/// @param module Module to be enabled. | ||
function enableModule(address module) external; | ||
|
||
/// @dev Disables a module on the avatar. | ||
/// @notice Can only be called by the avatar. | ||
/// @notice Must emit DisabledModule(address module) if successful. | ||
/// @param prevModule Address that pointed to the module to be removed in the linked list | ||
/// @param module Module to be removed. | ||
function disableModule(address prevModule, address module) external; | ||
|
||
/// @dev Allows a Module to execute a transaction. | ||
/// @notice Can only be called by an enabled module. | ||
/// @notice Must emit ExecutionFromModuleSuccess(address module) if successful. | ||
/// @notice Must emit ExecutionFromModuleFailure(address module) if unsuccessful. | ||
/// @param to Destination address of module transaction. | ||
/// @param value Ether value of module transaction. | ||
/// @param data Data payload of module transaction. | ||
/// @param operation Operation type of module transaction: 0 == call, 1 == delegate call. | ||
function execTransactionFromModule( | ||
address to, | ||
uint256 value, | ||
bytes memory data, | ||
Enum.Operation operation | ||
) external returns (bool success); | ||
|
||
/// @dev Allows a Module to execute a transaction and return data | ||
/// @notice Can only be called by an enabled module. | ||
/// @notice Must emit ExecutionFromModuleSuccess(address module) if successful. | ||
/// @notice Must emit ExecutionFromModuleFailure(address module) if unsuccessful. | ||
/// @param to Destination address of module transaction. | ||
/// @param value Ether value of module transaction. | ||
/// @param data Data payload of module transaction. | ||
/// @param operation Operation type of module transaction: 0 == call, 1 == delegate call. | ||
function execTransactionFromModuleReturnData( | ||
address to, | ||
uint256 value, | ||
bytes memory data, | ||
Enum.Operation operation | ||
) external returns (bool success, bytes memory returnData); | ||
|
||
/// @dev Returns if an module is enabled | ||
/// @return True if the module is enabled | ||
function isModuleEnabled(address module) external view returns (bool); | ||
|
||
/// @dev Returns array of modules. | ||
/// @param start Start of the page. | ||
/// @param pageSize Maximum number of modules that should be returned. | ||
/// @return array Array of modules. | ||
/// @return next Start of the next page. | ||
function getModulesPaginated(address start, uint256 pageSize) | ||
external | ||
view | ||
returns (address[] memory array, address next); | ||
} | ||
``` | ||
|
||
```solidity | ||
pragma solidity >=0.7.0 <0.9.0; | ||
|
||
import "./Enum.sol"; | ||
|
||
interface IGuard { | ||
function checkTransaction( | ||
address to, | ||
uint256 value, | ||
bytes memory data, | ||
Enum.Operation operation, | ||
uint256 safeTxGas, | ||
uint256 baseGas, | ||
uint256 gasPrice, | ||
address gasToken, | ||
address payable refundReceiver, | ||
bytes memory signatures, | ||
address msgSender | ||
) external; | ||
|
||
function checkAfterExecution(bytes32 txHash, bool success) external; | ||
} | ||
|
||
``` | ||
|
||
```solidity | ||
pragma solidity >=0.7.0 <0.9.0; | ||
|
||
import "./Enum.sol"; | ||
import "./BaseGuard.sol"; | ||
|
||
/// @title Guardable - A contract that manages fallback calls made to this contract | ||
contract Guardable { | ||
address public guard; | ||
|
||
event ChangedGuard(address guard); | ||
|
||
/// `guard_` does not implement IERC165. | ||
error NotIERC165Compliant(address guard_); | ||
|
||
/// @dev Set a guard that checks transactions before execution. | ||
/// @param _guard The address of the guard to be used or the 0 address to disable the guard. | ||
function setGuard(address _guard) external { | ||
if (_guard != address(0)) { | ||
if (!BaseGuard(_guard).supportsInterface(type(IGuard).interfaceId)) | ||
revert NotIERC165Compliant(_guard); | ||
} | ||
guard = _guard; | ||
emit ChangedGuard(guard); | ||
} | ||
|
||
function getGuard() external view returns (address _guard) { | ||
return guard; | ||
} | ||
} | ||
``` | ||
|
||
```solidity | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
auryn-macmillan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
pragma solidity >=0.7.0 <0.9.0; | ||
|
||
import "./Enum.sol"; | ||
import "./IERC165.sol"; | ||
import "./IGuard.sol"; | ||
|
||
abstract contract BaseGuard is IERC165 { | ||
function supportsInterface(bytes4 interfaceId) | ||
external | ||
pure | ||
override | ||
returns (bool) | ||
{ | ||
return | ||
interfaceId == type(IGuard).interfaceId || // 0xe6d7a83a | ||
interfaceId == type(IERC165).interfaceId; // 0x01ffc9a7 | ||
} | ||
|
||
/// @dev Module transactions only use the first four parameters: to, value, data, and operation. | ||
/// Module.sol hardcodes the remaining parameters as 0 since they are not used for module transactions. | ||
/// @notice This interface is used to maintain compatibilty with Gnosis Safe transaction guards. | ||
MicahZoltu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
function checkTransaction( | ||
address to, | ||
uint256 value, | ||
bytes memory data, | ||
Enum.Operation operation, | ||
uint256 safeTxGas, | ||
uint256 baseGas, | ||
uint256 gasPrice, | ||
address gasToken, | ||
address payable refundReceiver, | ||
bytes memory signatures, | ||
address msgSender | ||
) external virtual; | ||
|
||
function checkAfterExecution(bytes32 txHash, bool success) external virtual; | ||
} | ||
``` | ||
|
||
```solidity | ||
pragma solidity >=0.7.0 <0.9.0; | ||
|
||
/// @title Enum - Collection of enums | ||
contract Enum { | ||
enum Operation {Call, DelegateCall} | ||
} | ||
``` | ||
|
||
## Rationale | ||
In designing the Zodiac standard, we inevitably needed to define a standard interface for modular programmable accounts (avatars). Rather than writing this from scratch, we elected to use the existing interfaces from the [Gnosis Safe's Module Manager](https://github.com/gnosis/safe-contracts/blob/main/contracts/base/ModuleManager.sol) and from the [Gnosis Safe's Guard Manager](https://github.com/gnosis/safe-contracts/blob/main/contracts/base/GuardManager.sol), since the Gnosis Safe is by far the most widely used programmable account for DAOs, other organizations, and individuals. | ||
|
||
auryn-macmillan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
## Backwards Compatibility | ||
No backward compatibility issues are introduced by this standard. | ||
|
||
## Security Considerations | ||
Zodiac primarily leverages the existing ModuleManager interface from the Gnosis Safe, which has been in running securely in production for several years. That said, there are some considerations that module developers and users should take into account. | ||
1. **Modules have unilateral control:** Modules have unilateral control over any avatar on which they are enabled, so any module implementation should be treated as security critical and users should be vary cautious about enabling new modules. ONLY ENABLE MODULES THAT YOU TRUST WITH THE FULL VALUE OF THE AVATAR. | ||
2. **Race conditions:** A given avatar may have any number of modules enabled, each with unilateral control over the safe. In such cases, there may be race conditions between different modules (and other control mechanisms, like the multisig mechanism on a Gnosis Safe). | ||
3. **Don't brick your avatar:** Be warned, there are no safe guards to stop you adding or removing modules. If you remove all of the modules that let you control an avatar, the avatar will cease to function and all funds will be stuck. | ||
|
||
## Copyright | ||
Copyright and related rights waived via [CC0](../LICENSE.md). |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like the core contribution of this EIP is Avatar accounts, and I think "extensions" covers modifiers, modules, and guards well enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer not to introduce additional terminology that isn't used elsewhere.
If we were to add anything to the title, I'd be inclined to go with something like "Zodiac Avatar Accounts and Mods".
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, how about just
Zodiac Avatar Accounts
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems reasonable as well.
One thing I have been conscious of lately is that this pattern is useful beyond just DAOs. So I wonder if it would be worthwhile changing the rest of the language to be less opinionated about how it is used / what it is used for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this PR to generalize the language. This feels like the right direction to me.
https://github.com/auryn-macmillan/EIP-Zodiac/pull/1