Hatch DAO Machine State Diagram

TEC Hatch machine state diagram

This machine state diagram represents the different states that the TEC Hatch DAO will have from its deployment to its migration to another DAO. We distinguish between normal actions (red arrows), which are commonly made by most of the users, and administrative actions (blue arrows), which can be made by anyone but only if the requirements are met, and usually make the DAO advance in its state.

The DAO starts in the Pending state, and only when the hatch is opened, does it start the Funding phase. When the Minimum Goal is reached and the Hatch Period has ended we can mint tokens for impact hours token holders and close the hatch, splitting the funds between the Redeemable and the Non-Redeemable pool contracts. If the Maximum Goal is reached the Hatch Period ends automatically. If the Minimum Goal is not reached within the Hatch Period, we start refunding their ā€œcontributed tokensā€.

When the hatch is closed, we create a migration vote which transfers the funds from the Redeemable and the Non-Redeemable Pools to a new DAO. The same vote gives control of the DAO to the

We describe the different states and their available actions with more detail.

Pending

Itā€™s the initial state of the DAO.

Prerequisites:

  • The DAO is deployed with the new-hatch.js script.
    • The previous script initializes each one of the apps, but sets up an openDate = 0 for the hatch-app
    • The state of the DAO is reflected in the implementation spec.
  • The hatch.openDate() is 0
    • This means the hatch.state() is Pending.

Available actions:

  • hatch.open(): It starts the period in which people can contribute to the hatch. It changes the state of the DAO to Funding.

Other possible actions:

  • redemptions.redeem(): There are no contributed tokens and no organizaiton tokens. The funciton can be called but it will fail.

Funding

In this state people can contribute to the hatch.

Prerequisites:

  • Current timestamp minus hatch.openDate() must be less than hatch.period() and hatch.totalRaised() less than hatch.maxGoal()
    • This means the hatch.state() is Funding

Available actions:

  • hatch.contribute(): Individuals can send ā€œcontribute tokensā€ hatch.contributeToken() to the hatch contract in exchange for ā€œorganization tokensā€ hatch.token(). The contribute tokens are held by the hatch smart contract.
    • Prerequisite: hatchOracle.canPerform() is true. Only ā€œmembership scoreā€ token holders (CSTK token holders in the context of TEC) have permissions to execute this action, and the amount of contributed tokens is limited to their score. Read hatch oracle readme for more information on how contributions are limited.

Other possible actions:

  • redemptions.redeem(): Funds are not yet stored in the reserve, so this function would just burn ā€œorganization tokensā€ in exchange for nothing.

GoalReached

We reached the Minimum Goal, its the time to mint tokens for impact hours token holders, and send the funds to the Non-Redeemable and Redeemable pools.

Prerequisites:

  • Current timestamp minus hatch.openDate() must be greater than or equal to hatch.period() and hatch.totalRaised() more than hatch.minGoal() or independently of which is the current timestamp, hatch.totalRaised() must be more than hatch.maxGoal()
    • This means the hatch.state() is GoalReached and hatch.isClosed() is false

Available actions:

  • impactHours.claimRewards(): It can be called in batch for all the addresses that have unclaimed impact hours.
    • Prerequisite: hatch.state() must be GoalReached (specified as a require in the claimRewards code)
  • hatch.close(): We send the contributed tokens from the hatch smart contract to the
    • Prerequisite: impactHours.canPerform() must be true, assuring that all impact hours tokens has been burned (impactHours is set as a hatch.close() ACL oracle)

Other possible actions:

  • redemptions.redeem(): Funds are not yet stored in the reserve, so this function would just burn ā€œorganization tokensā€ in exchange for nothing

Refunding

The min goal was not reached in the specified hatch.period(). People can recover the funds they have contributed.

Prerequisites:

  • Current timestamp minus hatch.openDate() must be greater than hatch.period() and hatch.totalRaised() less than hatch.minGoal()
  • The hatch.state() is Refunding

Available actions:

  • hatch.refund(): Individuals can recover their ā€œcontributed tokensā€ from the hatch contract.

Other possible actions:

  • redemptions.redeem(): There are no funds in the reserve, so it would just burn the ā€œorganization tokensā€

Closed

Prerequisites:

  • The hatch.close() function has been called
    • This means that hatch.state() is Closed and hatch.isClosed() is true
    • This also means impactHours.token().supply() must be 0, meaning that all Impact Hours have been claimed.

Available actions:

  • voting.newVote(): Creates a new vote, potentially migrating the contributed tokens held in the Redeemable and Non-Redeemable pools into a new DAO, and giving the control to the remaining token holders
    • Prerequisite: Any account can create a new vote
  • voting.vote(): Token holders can vote yes or no. If they vote yes, their tokens can not be redeemed meanwhile the vote is active. This is achieved by setting up Dandelion Voting as an ACL oracle of Redemptionsā€™ REDEEM_ROLE, and only allowing to redeem when voting.canPerform() returns true.
    • Prerequisite: Only can be called when there is an active vote
  • voting.executeVote(): If the vote has passed, it executes the EVM script that potentially performs the DAO migration
    • Prerequisite: Only can be called when an active vote has passed
  • redemptions.redeem(): Burns part or all callerā€™s ā€œorganization tokensā€ in exchange of sending back a proportional part held in the reserve to the caller
    • Prerequisite: Only can be called if user didnā€™t vote yes on a currently active voting

Migrated

Prerequisites:

  • The funds from the Redeemable and Non-redeemable Pools have been migrated to the new Redeemable and Non-redeemable Pools of the new DAO.
  • The new DAO is controlled by a minime token clone of the TEC Hatch token at the moment of the migration.

Available actions:

  • redemptions.redeem(): Individuals can still redeem their tokens but since the reserve is empty, their tokens are just burned

How does the migration vote work?

In the Closed state, a migration vote is created by depositing a tollgate fee into the Non-Redeemable Pool. The vote is an EVM script with the following structure:

  • Call the migration.transferAll(contributionToken, newDAOReserve) function from the reserve agent
  • Call the migration.transferAll(contributionToken, newDAOFundingPool) function from the funding pool agent
  • Clone the tokenManager.token() and initialize the token manager of the new DAO with it

ā€œOrganization tokensā€ are redeemable by reserve ā€œcontributed tokensā€ only by those who did not vote yes meanwhile the vote is active. This is how it works from the user perspective:

When we are in the Closed state, the funds are split between the Redeemable and the Non-Redeemable Pool. Users can redeem their ā€œorganization tokensā€ for reserveā€™s ā€œcontributed tokensā€ at any time, except if they have voted yes on an active voting. In that case, their tokens are not redeemable until the vote ends. In the case the vote doesnā€™t pass, the funds are still in the reserve agent, and they are redeemable again by the user.

2 Likes