Skip to content

Instantly share code, notes, and snippets.

@androolloyd
Last active August 15, 2018 08:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save androolloyd/0a62ef48887be00a5eff5c17f2be849a to your computer and use it in GitHub Desktop.
Save androolloyd/0a62ef48887be00a5eff5c17f2be849a to your computer and use it in GitHub Desktop.
Groundhog Delegated Execution proposal

Specification

Summary

A standardized interface for interacting with recurring subscriptions.

Abstract

Groundhog believes that the creation of a subscription should have a defined set of criteria, we should be able to define a standardized public method that ensures that a subscription can be created from any type of user interface without worry about specific implementation requirements.

Our Thoughts

Interoperability between implementations should be the highest of priorties when it comes to developing the specification, abstract enough that we are not bound by the needs of others, but specific enough that we aren't fragmented when it comes to how the specification gets utilized.

Motivation

Recurring payments are the bedrock of SaSS and countless other businesses, a robust specification for defining this interaction will enable a broad spectrum of revenue generation and business models.

Enum Contract

948 Contracts should be compiled with a contract that references all the enumerations that are required for operation

/// @title Enum - Collection of enums
/// Original concept from Richard Meissner - <richard@gnosis.pm> Gnosis safe contracts
contract Enum {
    enum Operation {
        Call,
        DelegateCall,
        Create,
        ERC20, 
        ERC20Approve
    }
    enum SubscriptionStatus {
        ACTIVE,
        PAUSED,
        CANCELLED,
        EXPIRED
    }
}

EIP-165

ERC-948 Compliant contracts support EIP-165 announcing what interfaces they support

interface ERC165 {
  /**
   * @notice Query if a contract implements an interface
   * @param interfaceID The interface identifier, as specified in ERC-165
   * @dev Interface identification is specified in ERC-165. This function
   * uses less than 30,000 gas.
   * @return `true` if the contract implements `interfaceID` and
   * `interfaceID` is not 0xffffffff, `false` otherwise
   **/
  function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

Public View Functions

isValidSubscription
/** @dev Checks if the subscription is valid.
  * @param bytes subscriptionHash is the identifier of the customer's subscription with its relevant details.
  * @return success is the result of whether the subscription is valid or not.
  **/

function isValidSubscription(
            uint256 subscriptionHash
        ) 
        public 
        view 
        returns (
            bool success
        )
getSubscriptionStatus
/** @dev returns the value of the subscription
  * @param bytes subscriptionHash is the identifier of the customer's subscription with its relevant details.
  * @return status is the enumerated status of the current subscription, 0 expired, 1 active, 2 paused, 3 cancelled
  **/
function getSubscriptionStatus(
        uint256 subscriptionHash
    )
    public 
    view 
    returns  (
        uint status
    )
getSubscriptionHash
/** @dev returns the hash of cocatenated inputs to the address of the contract holding the logic.,
  * the owner would sign this hash and then provide it to the party for execution at a later date,
  * this could be viewed like a cheque, with the exception that unless you specifically
  * capture the hash on chain a valid signature will be executable at a later date, capturing the hash lets you modify the status to cancel or expire it.
  * @param address recipient the address of the person who is getting the funds.
  * @param uint256 value the value of the transaction
  * @param bytes data the data the user is agreeing to
  * @param uint256 txGas the cost of executing one of these transactions in gas(probably safe to pad this)
  * @param uint256 dataGas the cost of executing the data portion of the trasnaction(delegate calls etc)
  * @param uint 256 gasPrice the agreed upon gas cost of Execution of this subscription(cost incurment is up to implementation, ie, sender or reciever)
  * @param address gasToken address of the token in which gas will be compensated by, address(0) is ETH, only works in the case of an enscrow implementation)
  * @return bytes32, return the hash input arguments concatenated to the address of the contract that holds the logic.
  **/
function getSubscriptionHash(
        address recipient,
        uint256 value,
        bytes data,
        Enum.Operation operation,
        uint256 txGas,
        uint256 dataGas,
        uint256 gasPrice,
        address gasToken
    )
    public
    view
    returns (
        bytes32 subscriptionHash
    )
getModifyStatusHash
/** @dev returns the hash of concatenated inputs that the owners user would sign with their public keys
  * @param address recipient the address of the person who is getting the funds.
  * @param uint256 value the value of the transaction
  * @return bytes32 returns the hash of concatenated inputs with the address of the contract holding the subscription hash
  **/
function getModifyStatusHash(
        bytes32 subscriptionHash
        Enum.SubscriptionStatus status
    )
    public
    view
    returns (
        bytes32 modifyStatusHash
    )

Public Functions

modifyStatus
/** @dev modifys the current subscription status
  * @param uint256 subscriptionHash is the identifier of the customer's subscription with its relevant details.
  * @param Enum.SubscriptionStatus status the new status of the subscription
  * @param bytes signatures of the requested method being called
  * @return success is the result of the subscription being paused
  **/
function modifyStatus(
        uint256 subscriptionHash, 
        Enum.SubscriptionStatus status, 
        bytes signatures
    ) 
    public 
    returns (
        bool success
    )
executeSubscription
/** @dev returns the hash of cocatenated inputs to the address of the contract holding the logic.,
  * the owner would sign this hash and then provide it to the party for execution at a later date,
  * this could be viewed like a cheque, with the exception that unless you specifically
  * capture the hash on chain a valid signature will be executable at a later date, capturing the hash lets you modify the status to cancel or expire it.
  * @param address recipient the address of the person who is getting the funds.
  * @param uint256 value the value of the transaction
  * @param bytes data the data the user is agreeing to
  * @param uint256 txGas the cost of executing one of these transactions in gas(probably safe to pad this)
  * @param uint256 dataGas the cost of executing the data portion of the trasnaction(delegate calls etc)
  * @param uint 256 gasPrice the agreed upon gas cost of Execution of this subscription(cost incurment is up to implementation, ie, sender or reciever)
  * @param address gasToken address of the token in which gas will be compensated by, address(0) is ETH, only works in the case of an enscrow implementation)
  * @param bytes signatures signatures concatenated that have signed the inputs as proof of valid execution
  * @return bool success something to note that a failed execution will still pay the issuer of the transaction for their gas costs.
  **/
function executeSubscription(
        address to,
        uint256 value,
        bytes data,
        Enum.Operation operation,
        uint256 txGas,
        uint256 dataGas,
        uint256 gasPrice,
        address gasToken,
        bytes signatures
    )
    public 
    returns (
        bool success
    )

Conclusion

Subscriptions can and should encompass more than just token transfers, it should include all types of recurring transactions of ETH, tokens, payable smart contract methods

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