Proposals
Last updated
Last updated
Proposals are an integral part of the Clarity SDK and Agora. They are how DAOs perform on-chain actions. Users will use their stakes to create a proposal or vote on proposals.
All DAOs have a proposal execution threshold. This is the number of total governance tokens that must vote for a proposal outcome for it to be possible to execute. If a proposal outcome reaches this execution threshold and has the most votes out of all outcomes, it will automatically execute on-chain.
getProposals
)Retrieving proposals for a DAO is an extremely important part of the SDK. Information from this function call will be required in many of the other SDK functions.
Unlike stakes, proposal information should not be changing. As a result, it is okay to fetch proposal information and store it in a frontend library such as redux. You will just need to call getProposals
again if you create a new proposal.
saveProposalMetadata
)Creating an Agora proposal consists of 2 different function calls from the SDK.
A create proposal function call
A saveProposalMetadata
function call
The first call will create the proposal on on-chain with Agora. This must be performed on the front-end as it requires signed wallet transactions.
The second call will save the title and description of the proposal to Clarity's database. This will ensure that the Clarity dApp properly loads the proposal. It will also ensure that the getProposals
SDK function call will return all the necessary information.
This second call requires the use of your organization's API key since it is saving data to Clarity's database. In order to not leak your API key, you should make this function call from your app's back-end.
Our recommendation, is to call the create proposal function on your front-end. After successful creation of the proposal, send the returned information from the create proposal function and your desired title and description for the proposal to your app's back-end. Then from your app's back-end, call the saveProposalMetadata
function from the Clarity SDK.
In the future we hope to make this process more streamlined. For now, you can view the for one potential solution.
proposalMetadata:
contributors: This should just be an array that holds one item which is the stake key of the wallet that created the proposal. (ex: ["stake1u9j8prglpcqg6cencq3xx3vst88w0mw6cs6vnqvpmd4a3zcz7ck38"]
description: Desired description for the proposal
id: The ID of the Agora proposal which will be returned by the create proposal function call
templateName: The type of proposal that was created. Currently the options are "No Effect", "Spend Treasury Funds", and "Update Governance Parameter"
title: Desired title for the proposal
txHash: The transaction ID for the transaction that created the proposal. This value is returned by the create proposal function call.
createTreasuryWithdrawalProposal
)A treasury withdrawal proposal is used to withdraw funds from the DAO's treasury.
NOTE: After calling createTreasuryWithdrawalProposal
, you need to call saveProposalMetadata
from your back-end to save the metadata of the proposal to Clarity's database. This will ensure that the proposal properly renders on the Clarity dApp.
The treasury should have multiple UTXOs deposited to it and at least 20 ADA deposited to it. If there are only 1 or 2 UTXOs and less than 20 ADA, Agora may have trouble balancing the transaction to withdraw the assets.
Lots of small deposits of the same asset can potentially cause transaction balancing issues when attempting to withdraw the asset. This is due to the on-chain computation limit. During testing, we have calculated that about a max of 12 UTXOs can be involved in any one treasury withdrawal transaction. If the treasury withdrawal transaction must exceed 12 UTXOs, it is possible that it fails to balance the transaction due to the on-chain computation limit. At this point in time, this will not be much of an issue for most DAOs. The team is working to improve this limit and better handle many small UTXOs.
There is nothing stopping you from creating a treasury withdrawal proposal with an asset amount greater than what the treasury actually holds. If you do this and the proposal successfully passes, a governance action token (GAT) will be minted. However, it will be unable to balance the transaction and the treasury withdrawal will not proceed until the treasury holds enough of the asset specified in the proposal. Once the GAT is minted, it lives on-chain indefinitely until the treasury conditions allow it to execute. On the Clarity app we have a simple check that stops the creation of treasury withdrawal proposals for an amount greater than what the treasury holds to prevent this scenario from happening. You may want to implement a similar check in your web app.
stakeTxOutRef: This is a property of the stake information returned from the getStakes
function call. You should use the txOutRef property from the stake you wish to use to create the proposal.
recipientWalletAddress: The wallet address that the funds will be sent to from the treasury if the proposal successfully passes. (ex. addr1...)
policyId: The policy ID of the asset to be withdrawn (ex. 1e76aaec4869308ef5b61e81ebf229f2e70f75a50223defa087f807b) (Pass empty string if withdrawing ADA)
assetName: The hex encoded name of the asset to be withdrawn (ex. 436c61726974792044414f20546f6b656e) (Pass empty string if withdrawing ADA)
amount: The amount of the asset to be withdrawn. Be sure to properly handle decimals. For example, an amount of 1000000 for a token with 6 decimals would withdraw 1.000000 tokens)
createUpdateGovernanceParameterProposal
)An update governance parameter proposal is used to update the on-chain governance parameters of the DAO. This can be very useful as the DAO grows and evolves.
This will be a relatively rare proposal as DAOs do not frequently adjust their on-chain operating parameters.
NOTE: After calling createUpdateGovernanceParameterProposal
, you need to call saveProposalMetadata
from your back-end to save the metadata of the proposal to Clarity's database. This will ensure that the proposal properly renders on the Clarity dApp.
We recommend a minimum of 30 minutes for the timing parameters and actually have checks within the SDK that enforce this minimum. Anything less than 30 minutes and it is possible to run into some strange timing issues with proposal advancement on Cardano.
The votingTimeRangeMaxWidth
parameter must be less than the votingTime
parameter.
The Agora framework supports cosigning functionality for proposals. However, the Clarity Protocol does not currently support cosigning due to the increased complexity. This means that there are a couple of parameters that we recommend handling in a specific way as detailed below:
toVoting: Just set this equal to the create
parameter or else you may encounter issues with your proposal not being able to advance to the voting stage
cosign: Just set this equal to the vote
parameter. As cosigning is not enabled, this parameter does not actually do anything at this point in time.
stakeTxOutRef: This is a property of the stake information returned from the getStakes
function call. You should use the txOutRef property from the stake you wish to use to create the proposal.
proposalThresholds: Be sure to properly handle decimals for these values. The Clarity SDK does not automatically handle the decimals. For example, if your token has 6 decimals than an execute value of 100000000 would mean that the proposal outcome needs 100 staked governance tokens that voted for it to execute.
execute: The number of governance tokens a proposal outcome must receive in staked votes to be eligible to execute.
create: The number of governance tokens a stake must hold to be eligible to create an Agora proposal for the DAO.
toVoting: The number of governance tokens the stake that was used to create the proposal must hold for the proposal to be advanced to the voting stage. This parameter is largely useless without cosigning enabled. We recommend just setting it equal to the create
parameter.
vote: The number of governance tokens a stake must hold to be able to vote on an Agora proposal.
cosign: The number of governance tokens a stake must hold to be able to cosign a proposal. However, the Clarity Protocol does not support cosigning a proposal at this point in time. We recommend just setting it equal to the vote
parameter.
proposalTimings: All of these timing parameters need to be passed in milliseconds. There is also a 30 minute minimum for all of these timing parameters to avoid potential Cardano timing issues.
draftTime: The amount of time the proposal will spend in the draft phase.
votingTime: The amount of time the proposal will spend in the voting phase.
lockingTime: The amount of time the proposal will spend in the locked phase.
executingTime: The amount of time the proposal outcome will have to mint a GAT on-chain if successful.
minStakeVotingTime: The amount of time a user must wait after voting with their stake before they can retract their vote. A "cooldown" period after voting.
votingTimeRangeMaxWidth: The maximum amount of time a transaction that casts a vote on a proposal remains valid before being submitted to the blockchain. This ensures stake owners can unlock their stakes in a reasonable amount of time.
createProposalTimeRangeMaxWidth: The maximum amount of time a transaction that creates a proposal remains valid before being submitted to the blockchain.
maximumCreatedProposalsPerStake: The maximum number of proposals a single stake can create before it must unlock "create" locks from previous proposals.
createNoEffectProposal
)A no-effect proposal is recorded on-chain; however, it includes no automatically executing proposal effects.
This type of proposal is ideal for a situation where you want to record a decision on-chain but do not want to actually implement any effects on-chain.
NOTE: After calling createNoEffectProposal
, you need to call saveProposalMetadata
from your back-end to save the metadata of the proposal to Clarity's database. This will ensure that the proposal properly renders on the Clarity dApp.
stakeTxOutRef: This is a property of the stake information returned from the getStakes
function call. You should use the txOutRef property from the stake you wish to use to create the proposal.
voteOnProposal
)This function allows a user to vote on a proposal outcome with their created stake.
A user can only vote on a proposal when the proposal is in the "voting" stage of its' lifecycle
A user can only vote on a proposal if the amount of governance tokens held by their stake meets the DAO's GT vote threshold.
A stake can only be used to vote on a single proposal one time. However, the same stake can be used to vote on multiple different proposals.
A stake can be used to both create proposals and vote on proposals. There is no need to have a separate stake for creating proposals and voting on proposals.
proposalTxOutRef: This is a property of the proposal information returned from the getProposals
function call. You should use the txOutRef property from the proposal you wish to submit a vote for.
proposalId: This is the "id" property from the proposal information returned from the getProposals
function call. You should use the "id" property from the proposal you with to submit a vote for.
stakeTxOutRefs: Array of the txOutRef properties from the stake information returned from the getStakes
function call. Only include stake txOutRefs that you wish to use to vote on the proposal.
outcomeToVoteFor: The proposal information returned from getProposals
will have a "outcome" property for each proposal. For this parameter, you need to pass the numeric ID of the outcome you wish to vote for.
delegatedStakesTxOutRef: This is an optional parameter. We recommend you leave this blank until you gain an understanding of Agora and the Clarity Protocol. Delegated stakes are a recent addition to the Clarity Protocol. If the user had an stakes delegated to them and they wished to vote with these stakes, this is where the array of "txOutRef" properties of the delegated stakes would be passed.
retractVote
)Users have the option to retract their vote from an Agora proposal. Note that Cardano timing can be a bit tricky so it may take a day or so before the vote is eligible to be withdrawn.
Cardano timing can be a bit tricky so it may take a day or so before the vote is eligible to be withdrawn.
The Agora proposal must be in the voting phase in order to retract a vote.
proposalTxOutRef: This is a property of the proposal information returned from the getProposals
function call. You should use the txOutRef property from the proposal you wish to retract a vote from.
proposalId: This is the "id" property from the proposal information returned from the getProposals
function call. You should use the "id" property from the proposal you with to retract a vote from.
outcomeToRetractVoteFor: The numeric ID of the outcome to retract votes for. You can find this information in the proposal data returned from getProposals
.
An Agora stake has a max proposal limit that is set during the creation of the DAO. This is how many proposals that individual stake can create before it is no longer allowed to create new proposals. Before it can be used to create new proposals, previous proposal creation locks must be removed from the stake through the function. If you are encountering issues creating a proposal, ensure you have not hit the proposal creation limit for the stake you are using.
An Agora stake has a max proposal limit that is set during the creation of the DAO. This is how many proposals that individual stake can create before it is no longer allowed to create new proposals. Before it can be used to create new proposals, previous proposal creation locks must be removed from the stake through the function. If you are encountering issues creating a proposal, ensure you have not hit the proposal creation limit for the stake you are using.
An Agora stake has a max proposal limit that is set during the creation of the DAO. This is how many proposals that individual stake can create before it is no longer allowed to create new proposals. Before it can be used to create new proposals, previous proposal creation locks must be removed from the stake through the function. If you are encountering issues creating a proposal, ensure you have not hit the proposal creation limit for the stake you are using.