- Use this template and continue work in your own repository
- Implement the two smart contracts:
- PSP22 + PSP22Metadata
- DAO
- In the dao directory run
cargo testand the two tests should pass
- Swanky & Swanky node
- ink! v4.2.1
- PSP22 from Openbrush
In this assignment you will create an investment DAO.
Users will be able to submit a funding proposals and asks governance token holders to vote on it. A funding proposal will have a voting period, a fund amount as well as fund recipient.
At the end of the voting period and if the vote reach the defined quorum, the fund recipient defined in the proposal will get the fund transferred.
Proposal
- defines the fund recipient
to - the start & end of the voting period
vote_startvote_end, - a boolean to know if it has been already
executedor not - requested
amount.
ProposalVote defines the proportion (in %) of for_votes and against_vote
VoteType an enum with two fields to cast a vote: Against and For
ProposalId identifiers for Proposals
new (constructor)
#[ink(constructor, payable)]
pub fn new(governance_token: AccountId, quorum: u8) -> Self { ...The constructor is payable in order to fund the contract with a certain amount of native token that will be transferred to the recipients of funding proposals (of course proposals amount should not exceed balance of the contract).
governance_token the PSP22 token accountId of the governance token
quorum Minimum number of cast voted required for a proposal to be successful. The quorum is usually somewhere in the range of 1-10% of total token supply.
propose
pub fn propose(&mut self, to: AccountId, amount: Balance, duration: u64) -> Result<(), DaoError> { ...This function is used to submit a new proposal. Any user can call this function.
to the recipient AccountId
amount the amount of funds (in Native tokens) requested
duration the duration (in minutes) of the open voting period for the proposal. Note at it should start directly after this function call.
In the body of the function:
- Ensure the
amountis not 0 (or returnDaoError::AmountShouldNotBeZero) - Ensure the
durationis not 0 (or returnDaoError::DurationError) - The vote star value should be the actual block timestamp
- The Proposal should be added to the
proposalsMapping (please increaseIdby one before insert)
vote
pub fn vote(&mut self, proposal_id: ProposalId, vote: VoteType) -> Result<(), DaoError> { ...This function is called to cast the vote of the caller. Any user can call this function.
proposal_id the id of the proposal to vote on
vote is either Against or For
In the body of the function:
- Ensure the proposal exist (or return
DaoError::ProposalNotFound) - Ensure the proposal has not been already executed (or return
DaoError::ProposalAlreadyExecuted) - Ensure the voting period is still open (or return
DaoError::VotePeriodEnded) - Ensure the caller has not already voted (or return
DaoError::AlreadyVoted) - Add the caller is the
votesMapping - Check the
weightof the caller of the governance token (the proportion of caller balance in relation to total supply) - Add the
weightvalue toagainst_votesorfor_votesbased onvote - Insert proposal in
proposal_votesMapping
execute
pub fn execute(&mut self, proposal_id: ProposalId) -> Result<(), DaoError> { ...This function is called when the voting period of a proposal has ended to transfer the funds to the recipient (if the quorum has been reached). Anyone can call this function.
proposal_id the id of the proposal to vote on
In the body of the function:
- Ensure the proposal exist (or return
DaoError::ProposalNotFound) - Ensure the proposal has not been already executed (or return
DaoError::ProposalAlreadyExecuted) - Ensure the sum of
For&Againstvote reach quorum (or returnDaoError::QuorumNotReached) - Ensure there is more
Forvotes thanAgainstvotes (or returnDaoError::ProposalNotAccepted) - Save that proposal has been executed
- transfer
amountto the recipient
proposals a Mapping to identify proposals: between ProposalId and Proposals
proposal_votes a Mapping between Proposals and ProposalVotes
votes a Mapping to ensure an account has already voted, where the mapping key is a tupple of (ProposalId, AccountId) and mapping value is just ()
next_proposal_id to track next proposal id
quorum Quorum required for a proposal to be successful. As percentage of total supply of governance tokens
governance_token address of governance token contract
- Both contracts should be implemented in the folders defined by the workspace
- All contract types and functions should be implemented as described above
- Unit test should be expanded to cover all the functions of the contracts. Run the unit test with
cargo test - Existing 2 unit tests for dao contract can be extended but should not be deleted and should pass
- There is a Github CI test that should be passing. You can check it in the Actions tab of your repository
Due to big number of participants the submissions will NOT be considered if any of the above criteria is not met.