exeDAO v1

For exeDAO v1 we have made some modifications to the original bytecode audit/execution methods, added configurable permissions, shares management (as opposed to a static list of contract owners and a constant threshold) and extension capabilities.

exeDAO provides two methods for extending functionality beyond the base methods included in the contract: safeExecute and addExtension .

Arbitrary Execution

safeExecute takes some bytecode for a contract, checks it for dangerous opcodes, deploys the bytecode as a new contract, delegatecall s into it with no input arguments, and returns the result. safeExecute is essentially exeDAO’s eval() method. It runs whatever code you give it, allowing daoists to perform one-time script execution within the context of the contract. This is essentially the same as the method used in the original exeDAO, with one exception: we removed the kill() call and added selfdestruct to the list of restricted opcodes. The risk of destroying the entire contract seemed a bit more substantial than the benefit of saving 16k gas.

GitHub links

Extensions

addExtension works a little differently. It takes in bytecode for an extension contract, a list of function signatures that are present in it and a boolean stating whether the extension should be used with call or delegatecall . The bytecode given is deployed to a new contract whose address is saved with the other input data (except the bytecode) as an Extension struct. This extension is saved in an array so users can quickly look up all extensions, and the function signatures are mapped to the extension’s index.

Whenever a user calls a method on exeDAO which does not exist in the base contract, the fallback function checks if the function signature of that data is mapped to an extension. If it is, the same approval mechanism as is used for every other function on the contract determines whether the execution can move forward, then we pass the call data to the extension contract in a delegatecall or call , according to the extension settings.

Since the function calls to extension contracts are done through the fallback method rather than some type of callExtension() function, all external contracts and APIs can treat the contract as if it had all the extension functions originally.

Extensions are expected to contain a metaHash value which is used to look up the extension’s metadata on IPFS. exedao.js expects extension metadata to contain:

abi — ABI of the extension contract

— ABI of the extension contract bytecode — bytecode of the compiled contract

— bytecode of the compiled contract functionDescriptions — mapping from function signatures to brief descriptions of what they do

The JavaScript library for exeDAO has a web3 contract instance with the base ABI of the ExeDAO.sol contract. The library is capable of looking up extensions on the contract, finding their metadata on IPFS and upgrading its contract’s ABI with the ABI from the extensions.

GitHub links:

Proposals

Proposals to execute code on the contract are identified by a hash of the full call data to whichever function the proposal targets. Proposal hashes are mapped to indices in an array of Proposal structs, which contain the vote count and mapping of who has voted. When a proposal is approved or expires, the hash-to-index mapping entry is deleted along with the non-mapping values in the struct. By mapping to indices in the array rather than directly to the structs, the same proposals can be executed multiple times without needing to clear out potentially large voter mappings.

Metadata

Proposals can optionally include a metaHash value which can be used to look up metadata about a proposal on IPFS. The metadata can be used to share any information about proposals, as the contract has no mechanism for verifying metadata; in exedao.js, metadata is expected to have:

title — name for the proposal (optional)

— name for the proposal (optional) description — summary of the proposal (optional)

— summary of the proposal (optional) function — function signature of the method being called (required)

— function signature of the method being called (required) arguments — array of function parameters (required)

This metadata allows clients to query the list of open proposals, retrieve their metadata from IPFS, verify that the function and inputs for each proposal match the proposal hash on-chain, and display the function and arguments to users.

For extensions and arbitrary execution, the JavaScript library also provides methods for including the contract source code and compiler information in the metadata. This allows other DAO members to compile the code, verify the bytecode matches the proposal hash and display the full source to users.

exedao.com has a web server that allows any DAO member to submit a metadata object for a proposal. If the metadata is verified to match an open proposal and has not already been saved, the server will pin the metadata to IPFS by using the Temporal API. The server is not necessary — any method of uploading data to IPFS is suitable (or really any method of sharing data), but it provides a simple method for DAO members to share metadata about proposals.

The server also allows members to upload “members-only” proposal metadata which is stored on the server (not uploaded to IPFS) and can only be accessed by DAO members. This is a useful feature as it allows the DAO members to agree on a proposal without alerting third parties as to what the contract is about to execute. A better method might be to use a shared key derivation mechanism so DAO members can encrypt metadata, upload it to IPFS, retrieve and decrypt the data. We’ll be looking into this in the future.

The authentication middleware is pretty useful on its own. It uses web3 signatures to verify that users are members of the DAO before issuing JWTs. With some minor modifications, this can be extended for use with any web server where users authenticate with web3 signatures after some on-chain data about their addresses is verified (has a valid ens subdomain, for example). The middleware works with both express and socket.io, though only express is used by exeDAO at the moment.

GitHub links: