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 previous script initializes each one of the apps, but sets up an
- The
hatch.openDate()
is 0- This means the
hatch.state()
is Pending.
- This means the
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 thanhatch.period()
andhatch.totalRaised()
less thanhatch.maxGoal()
- This means the
hatch.state()
is Funding
- This means the
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.
- Prerequisite:
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 tohatch.period()
andhatch.totalRaised()
more thanhatch.minGoal()
or independently of which is the current timestamp,hatch.totalRaised()
must be more thanhatch.maxGoal()
- This means the
hatch.state()
is GoalReached andhatch.isClosed()
is false
- This means the
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 arequire
in theclaimRewards
code)
- Prerequisite:
-
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 ahatch.close()
ACL oracle)
- Prerequisite:
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 thanhatch.period()
andhatch.totalRaised()
less thanhatch.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 andhatch.isClosed()
is true - This also means
impactHours.token().supply()
must be 0, meaning that all Impact Hours have been claimed.
- This means that
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 whenvoting.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.