TributeDAO is a new modular, low cost DAO framework. The framework aims to improve DAOs by fixing the:
The TributeDAO framework aims to address these issues, as part of our quest to make DAOs the dominant form of organization. As the growing number of participants in DAOs know, there is no “one size fits all” for managing any organization. DAOs need low cost and easy to develop components that can be assembled like lego blocks to fit the needs of the organization and its membership.
The TributeDAO framework is our team's tribute to the MolochDAO ecosystem. As many know, MolochDAO brought new life to DAOs. Through an elegant smart contract design, this smart contract framework brought DAOs back to life, helping us push beyond the fiery depths of “The DAO.”
Last year, we worked to evolve the initial MolochDAO smart contracts by assisting with the creation of Moloch v2, which enabled multiple token support, “guildkicks” to remove unwanted members, and “loot” to issue non-voting shares still entitled to financial distributions. These upgraded contracts were built with “venture” and similar investment transactions in mind, allowing for more effective swaps and control over tokenized assets and membership.
The TributeDAO framework hopes to provide teams looking to deploy DAOs with several enhancements and improvements, including:
Inspired by the hexagonal architecture design pattern we believe that we can have additional layers of security, and break the main contract into smaller contracts. With that, we create loosely coupled modules/contracts, easier to audit, and can be easily connected to the DAO.
The main design goal is to limit access to the smart contracts according at layer boundaries. The External World (i.e. RPC clients) can access the core contracts only via Adapters, never directly. Every adapter contains all the necessary logic and data to update/change the state of the DAO in the DAORegistry Contract. The Core Contract tracks all the state changes of the DAO, and an Adapter tracks only the state changes in its own context. Extensions enhance the DAO capabilities and simplify the Core Contract code. The information always flows from the External World to the Core Contracts, never the other way around. If a Core Contract needs external info, it must be provided by an Adapter and/or an Extension instead of calling External World directly.
There are five main components in the Tribute architecture outlined further below.
The core contracts serve as the spine for the Tribute DAO framework and act as a DAO registry, creating a digital version of "division of corporations." These contracts compose the DAO itself, and make it cheaper and easier to deploy a DAO. These contracts directly change the DAO state without the need of going through an adapter or extension (described further below). A core contract never pulls information directly from the external world. For that we use Adapters and Extensions, and the natural information flow is always from the external world to the core contracts.
There are three core contracts as part of the Tribute DAO framework, including a:
Once a DAO is created using the above core contracts, they can be extended and modified with adapters and extensions. Adapters and extensions make it easy to assemble a DAO like lego blocks, by adding to a DAO narrowly-defined, tested, and extensible smart contracts created for specific purposes. Adapters and extensions make DAOs more modular, upgradeable, and also enable us to work together to build robust DAO tooling. They can be added to a TributeDAO via a DAO vote.
There are currently 12 adapters implemented in the Tribute DAO framework and these adapters make the Tribute DAO framework feature compatible with Moloch v2:
The range of potential adapters will expand over time and likely will include:
Creating an adapter is straight forward and should save developers engineering time. Each adapter needs to be configured with the Access Flags in order to access the Core Contracts, and/or Extensions. Otherwise the Adapter will not able to pull/push information to/from the DAO.
Please note:
Extensions are conceived to isolate the complexity of state changes from the DAORegistry contract, and to simplify the core logic. Essentially an Extension is similar to an Adapter, but the main difference is that it is used by several adapters and by the DAORegistry - which end up enhancing the DAO capabilities and the state management without cluttering the DAO core contract.
Bank: adds the banking capabilities to the DAO, and keeps track of the DAO accounts and internal token balances.
NFT: adds to the DAO the capability of managing and curating a collection of standard NFTs.
ERC20: adds to the DAO the capability of managing and transfer internal tokens between members and/or external accounts.
Executor: adds to the DAO the capability of executing delegated calls to other contracts, including contracts that are not part of the DAO, using the EVM instruction delegatecall
.
The Access Control Layer (ACL) is implemented using Access Flags to indicate which permissions an adapter must have in order to access and modify the DAO state. The are 3 main categories of Access Flags:
EXISTS
.EXISTS
, SPONSORED
, PROCESSED
.REPLACE_ADAPTER
, SUBMIT_PROPOSAL
, UPDATE_DELEGATE_KEY
, SET_CONFIGURATION
, ADD_EXTENSION
, REMOVE_EXTENSION
, NEW_MEMBER
.The Access Flags of each adapter must be provided to the DAOFactory when the daoFactory.addAdapters
function is called passing the new adapters. These flags will grant the access to the DAORegistry contract, and the same process must be done to grant the access of each Adapter to each Extension (function daoFactory.configureExtension
).
The Access Flags are defined in the DAORegistry using the modifier hasAccess
. For example, a function with the modifier hasAccess(this, AclFlag.REPLACE_ADAPTER)
means the adapter calling this function needs to have the Access Flag REPLACE_ADAPTER
enabled, otherwise the call will revert. In order to create an Adapter with the proper Access Flags one needs to first map out all the functions that the Adapter will be calling in the DAORegistry and Extensions, and provide these Access Flags using the DAO Factory as described above.
You can find more information about the purpose of each access flag at DAO Registry - Access Flags.
npm ci
cp .sample.env .env
npm run compile
Deploy contracts to networks such as sepolia, harmonytest, polygontest, ganache, mainnet, harmony, polygon or avalanche.
npm run deploy sepolia
For more information about the deployment, see the in logs logs/contracts
npm run verify sepolia
OR
npm run verify mainnet
In the same .env
file created under the tribute-contracts
folder, set the following environment variables:
######################## Tribute UI env vars ########################
# Configure the UI to use the Sepolia network for local development
REACT_APP_DEFAULT_CHAIN_NAME_LOCAL=SEPOLIA
# It can be the same value you used for the Tribute DAO deployment.
REACT_APP_INFURA_PROJECT_ID_DEV=YOUR_INFURA_API_KEY
# The address of the Multicall smart contract deployed to the Sepolia network.
# Copy that from the tribute-contracts/build/contracts-sepolia-YYYY-MM-DD-HH:mm:ss.json
REACT_APP_MULTICALL_CONTRACT_ADDRESS=0x...
# The address of the DaoRegistry smart contract deployed to the Sepolia network.
# Copy that from the tribute-contracts/build/contracts-sepolia-YYYY-MM-DD-HH:mm:ss.json
REACT_APP_DAO_REGISTRY_CONTRACT_ADDRESS=0x...
# Enable Sepolia network for Tribute UI
REACT_APP_ENVIRONMENT=development
Make sure you have set the correct addresses for REACT_APP_MULTICALL_CONTRACT_ADDRESS
& REACT_APP_DAO_REGISTRY_CONTRACT_ADDRESS
.
npm run docker
List the problems found in project files
npm run lint
Fix the lint issues
npm run lint:fix
npm run slither
npm run compile && npm test
Contracts:
DAO_NAME
: The name of the DAO.DAO_OWNER_ADDR
: The DAO Owner ETH Address (0x...) in the target network.ETH_NODE_URL
: The Ethereum Node URL to connect to the Ethereum blockchain, it can be http/ws.WALLET_MNEMONIC
: The wallet mnemonic string containing the 12 secret keywords.ETHERSCAN_API_KEY
: The Ether Scan API Key to verify the contracts after the deployment.DEBUG
: Debug the Ether Scan contract verification calls (true
|false
).COUPON_CREATOR_ADDR
: The public eth (0x...) address of the creator of the onboarding coupons.ERC20_TOKEN_NAME
: The ERC20 Token Name used by the ERC20 Token Extension.ERC20_TOKEN_SYMBOL
: Token Symbol used by the ERC20 Token Extension.ERC20_TOKEN_DECIMALS
: The ERC20 Token Decimals to display in MetaMask.OFFCHAIN_ADMIN_ADDR
: The address of the admin account that manages the offchain voting adapter.VOTING_PERIOD_SECONDS
: The maximum amount of time in seconds that members are allowed vote on proposals.GRACE_PERIOD_SECONDS
: The minimum time in seconds after the voting period has ended, that the members need to wait before processing a proposal.DAO_ARTIFACTS_OWNER_ADDR
: The owner address of the artifacts deployed. Leave it empty to if you want to use the DAO_OWNER_ADDR
as the artifacts owner.DAO_ARTIFACTS_CONTRACT_ADDR
: The DaoArtifacts
contract address that will be used in the deployment script to fetch Adapters and Factories during the deployment to save gas costs.Snapshot-hub:
PORT
: The Snapshot hub Server portENV
: To indicate in which environment it is being executed: local, dev, or prodUSE_IPFS
: To indicated the pinning service on IPFS should be enabled/disabled (if enabled cause delay in the responses)RELAYER_PK
: The PK of the account that will be used to sign the messages.NETWORK
: The network name that will be used by the relayer (use testnet for sepolia and mainnet for the main ethereum network)JAWSDB_URL
: The postgres url: postgres://user:pwd@host:5432/db-nameALLOWED_DOMAINS
: The list of domains that should be allowed to send requests to the APIALCHEMY_API_URL
: The relayer API (alternative to Infura)Tribute-UI:
REACT_APP_DEFAULT_CHAIN_NAME_LOCAL
: The network which the dApp needs to connect to.REACT_APP_INFURA_PROJECT_ID_DEV
: Your infura key.REACT_APP_DAO_REGISTRY_CONTRACT_ADDRESS
: The address of the DaoRegistry
smart contract deployed, copy that from build/deployed/contracts-network-YYYY-MM-DD-HH:mm:ss.json
REACT_APP_MULTICALL_CONTRACT_ADDRESS
: The address of the Multicall
smart contract deployed, copy that from build/deployed/contracts-network-YYYY-MM-DD-HH:mm:ss.json
.REACT_APP_ENVIRONMENT
: The environment which the app will be executed. Set it to development
env.master
and pull the latestnpm run release
package.json
version will be bumpedmaster
publish.yaml
will execute (due to the new release tag) to publish the new package version to the NPM registry.Tribute exists thanks to its contributors. There are many ways you can participate and help build high quality software. Check out the contribution guide!
Join us on Discord.
THANK YOU to all coders, designers, auditors, and any individual who have contributed with ideas, resources, and energy to this and previous versions of this project. Thank you all.
Tribute is released under the MIT License.