Skip to content

Instantly share code, notes, and snippets.

@danfinlay
Last active April 13, 2020 21:04
Show Gist options
  • Save danfinlay/1bfebdcb95766eb55f674a3578b5e21d to your computer and use it in GitHub Desktop.
Save danfinlay/1bfebdcb95766eb55f674a3578b5e21d to your computer and use it in GitHub Desktop.
Capped Wisp Account
  • Goal:
    • An [[Ethereum]] smart account architecture composed from a very small and simple pattern of flexible delegation with maximally off-chain, low-state contracts.
  • Axioms / Dependencies / Prior Art / Prerequisites & Tools
    • [[gnosis-safe style module]]s
      • Each module can call any function on the parent contract.
    • [[create2]] deterministic addressing
      • Account can delegate to unpublished contracts.
    • [[Will-o-wisps]]
      • Stateless delegations can clean themselves up, leaving no state-bloat on-chain.
    • [[MetaTransactions]]
      • The delegation to the unpublished contract can happen with a message that can be submitted by someone else).
      • Assume all contracts here use [[the _msgSender() trick]]
      • Assume these messages have custom replay logic that only allows them to be submitted at any time and only prevented by the same authority that granted.
    • [[Recursion]]
      • Delegating to an unpublished [[capped wisp]] also allows the creation of unpublished delegations from that contract.
      • For this reason, arbitrarily long chains of delegation can happen entirely off-chain, while retaining their full meaning.
    • [[Sub-classing]]
      • Each [[capped wisp]] can have different behavior: Authorization, attenuation, & disruption.
      • This allows the growth of arbitrarily nuanced authorization logic based on off-chain delegation and the power of the [[evm]].
  • ""
  • Security Lemmas
    • Since each child [[capped wisp]] can at most perform the operations of its parent:
      • Longer chains cannot gain authority.
      • Longer chains can only distribute control.
  • High-level spec
    • Inheritance opportunities
      • [[gnosis safe]]: A list of owner addresses who can invoke the contract to emit an arbitrary message, [[gnosis-safe style module]].
      • Support for [[MetaTransactions]] via [[the _msgSender() trick]]
    • Needs custom
      • A method to generate contracts with deterministic addresses that cannot be prevented except by the same authority that granted it.
      • A method to allow blocking the future delegation to a particular address. (Could also block publication, just needs to cover revocation use case).
    • Optional customization for [[Sub-classing]]
      • Custom attenuation/disruption logic
        • For limiting the set of possible messages that will be forwarded by this contract.
        • Enables the composition of contracts that adhere to the [[principle of least authority]].
  • [[Mushroom]] metaphor
    • Apologies to [[Nick Johnson]] and his hate of architectural metaphor, but I'll be using the metaphor of a mushroom's lifecycle to describe this architecture, so let's take some time to learn it.
    • Fun mushroom facts
      • If fungus didn't exist, there would be no living process for breaking down the lichen fiber in wood.
    • ""
    • Summary in metaphor
      • This document is a spore: the kernel of potential hoping to gain a seat in a new person's mind.
      • A [[capped wisp]] inoculation occurs as the initial contract is published to the chain.
      • The base contract allows the user to share messages of delegation off-chain, which can grow to arbitrary length and only to increasing exclusivity, never to privilege escalation. This invisible network of capability resembles the mycelial growth of a fungal colony.
      • Some of these messages are "stateful bool", and so require a new contract to be published that can also receive the same sorts of [[MetaTransactions]]. This is like a fruiting body: A visible extension of the mass, necessary to overcome the limits of off-chain/underground growth.
      • The fruitbody is a published gnostic cap in the hands of an agent who knows how to spread their spores.
      • The initiated agent IS the [[capped wisp]], spreading their own spores where needed to [[facilitate]] the risks they choose to take for growth.
    • The Body
      • Properties
        • owners
          • Set<address>
          • A set of [[ethereum addresses]] that are permitted to call functions on this hyphae.
        • revoked
          • A set of [[ethereum addresses]] that will never again be permitted to call functions from this hyphae.
      • Functions
        • execute(message bytes)
          • Depending on the "Varieties & Subclasses", custom logic may be added to the "execute(message bytes)" function to limit the messages that it may relay, or even enforce some manipulation of the message. This reflects the terms of the "The Body"'s original formation.
        • delegate(newOwner address, authProof)
          • assert(authorize(authProof))
          • adds newOwner to the owner list
        • revoke(address)
          • if in owner list, removes from the owner list.
          • Adds to the revoked list.
        • redeemAndExecute(mycelialCellPacket, tx)
          • if (authorize(authProof) === true)
            • Publish mycelial cell packet.
            • Assert primordiaAddress is not in revoked list.
            • Store resulting contract address in owner list.
            • execute tx on the newly published primordia
            • if spore.stateless
              • spore.selfdestruct()
              • remove primordiaAddress from owner list.
        • private authorize
          • Since a "Varieties & Subclasses" is an expansion of the base safe, it can have different authority delegated to it. This can mean that a particular key is in control of these particular
          • Variations
            • A signature verifier
              • a personal_sign one
              • a signTypedData one
            • a 2-factor one
            • a token-weighted vote one
            • an m-of-n one
      • Varieties & Subclasses
        • While a capwisp fundamentally could do anything if allowed to (because of the DPpgieaK2), in practice sub-classing is likely to be a field for standardization around well audited constraints on what a new delegate can do.
        • Each of the type may have its own limitations: spending limit, contract whitelist, for security, it is advisable to confine this to the narrowest scope its author prefers, per the [[principle of least authority]]). It is only those initial capabilities that the capwisp can build on, then, ensuring that no additional authority can ever be derived from its delegation to new owners.
        • Capabilities and Limitations
        • What they have in common
          • They all support forwarding a message, or broadcasting it as self.
          • They may enforce some validation or mutation on messages they forward.
        • Ways they can vary
    • Mycelial cell packet (binary data)
      • The signed message of arbitrary delegation, the technical component that delegates authority.
      • types
        • parent: address
        • bytesToPublish: bytes
        • stateful: boolean
        • authProof: bytes
      • an off-chain message.
      • Must have a deterministic address regardless of publication order, to enable:
        • being assigned commitments/permissions without being published.
        • revocation of those outstanding capabilities by the parent.
      • properties
        • parent address?
          • If there is no parent, then this is the root, and the bytesToPublish are executed as a transaction from this contract.
          • The address of the contract that granted this message, so that approved messages can be forwarded to it.
          • stateful bool
            • if false, this spore will self destruct after each usage and self revoke from storage, to avoid chain bloat.
        • authProof bytes
          • A blob of data that proves authorization of this message to the cell's authorization logic.
        • signed properties
          • message bytes
            • The payload being published as a new contract, or sent as a transaction.
      • can be submitted to its parent "The Body"."redeemAndExecute(mycelialCellPacket, tx)" to be published to the chain.
      • Could possibly include a gas limit for pre-enabling a user's gas without spending ether.
@SilentCicero
Copy link

SilentCicero commented Apr 7, 2020

Heyo!

So i want to bring attention to what I've done here with my MultiSig design.

https://github.com/SilentCicero/MultiSignatureWallet

My later version of the multisig has a lot of what you need:

  • Signers and a threshold are the starting point (i.e. standard multi-sig logic), defined initially at construction
  • Each signer can have a different weight
  • Each signer can also become a module (i.e. be a contract), whereby they can do things like daily withdrawal etc, this is simply accomplished by giving that signer contract the threshold weight
  • EIP712 compliance is followed, but if the caller is a signer or signer contract, no signing proofs are required to be presented
  • As well, if the caller signer has the threshold weight, all internal multi-sig logic is bypassed, i.e. the wallet can become both a proxy and a multisig as well
  • Deployment cost is minimal
  • All signer's, weights can be changed
  • The multi-sig also supports meta-transactional signing, as the caller doesn't need to be a signer or have weight to execute a transaction

Project details:

  • Close-To-The-Metal: Easily auditable at the opcode level (easier for formal-verification)
  • Tiny deployment cost (311 Bytes / 233 opcodes)
  • Reduced execution cost (when executing transactions)
  • Written with similar security profile to common multi-signature designs
  • Standard Numerical Nonce system to prevent double-spends
  • EIP712 Signing Compliant (signing works with all major Ethereum wallets)
  • Delegate-Call Enabled
  • Specify unfixed amount of signatories and thresholds
  • MIT License; completely open source to do with as you please

@danfinlay
Copy link
Author

So i want to bring attention to what I've done here with my MultiSig design.

Awesome @SilentCicero, I only saw this now! Really excited to see you doing a multisig in YUL.

Two features I think my spec would need that would need to be accounted for, either within or as modules to this:

  • An optional replay protection strategy that allows submission in any order (a two dimensional nonce could do): It's possible that simply integrating EIP-1776 compatibility (a single MetaTx method, and replacing msg.sender with _msgSender() could achieve this goal).
  • A method for publishing new contracts with a deterministic address with CREATE2 (this could be achieved with an additional module, so could live outside of this core lib).

Would probably be easy enough to do the first one, and make a module for the second one, does that sound about right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment