-
Notifications
You must be signed in to change notification settings - Fork 318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CIP-0071 | Non-Fungible Token (NFT) Proxy Voting Standard #351
Conversation
This is not ready for review yet I am just putting it up here so I have a pointer to get the process started. When I am ready for formal reviews, I will move it out of Draft status. |
This is now ready for community review. I will engage key participants to determine how best to get the ball rolling! |
d30ac72
to
9d83fc8
Compare
thanks @thaddeusdiamond - I've added a direct link in your OP to the README.md file in your branch, in the form we use when new CIP PR's are submitted... please modify the text as you like & keep the link updated if your CIP draft changes path (I see your "example" is linked from the CIP text). If you can indicate here which individuals or groups you are already addressing as "key participants" we can ask for feedback from any others who have submitted or reviewed proposals about voting, governance, and/or authentication by NFT. The proposal looks technically sound to me, and complete with all formalities including the Path to Active that we would expect to eventually merge this with |
} | ||
``` | ||
|
||
There is no requirement that the "ballot counter" redeem all "ballots" from the "ballot box" and send them back to the respective voters, but we anticipate that this is what will happen in practice. We encourage further open-sourced code versions that enforce this requirement at the smart contract level. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it makes more sense to burn the "ballots" instead of returning them to their respective voters. There are a few reasons for this:
First, in the motivation section, you discuss the issues with governance tokens. Although the ballots are no longer usable (defined by the time in the policy), it seems unnecessarily confusing for users to receive what seems like a governance token. That could result in confusion and even scams.
Secondly, burning the asset will make it much easier for third parties to tabulate votes or at on the results. While all the data is provided to tabulate votes as a third party already, it is quite simple, and already done for other applications, to track the -1 mint transactions of all assets under a policy ID. Any on chain voting should allow vote results to be verified as simply as possible, which would be done through burning the assets.
Of course, once you burn the asset, there is the minUTXO that was previously attached to the asset. It is important to do SOMETHING with that minUTXO, so we don't end up with up to ~10.5K ADA locked in the contract address. I propose that it is all sent back to the voters, so the only cost associated with voting is the transaction fee, but I would also support splitting it with the developer(s) in some capacity to pay for their time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the ideal here is to have the default ballot box perform:
- Burn ballot
- Send minUTxO back to address indicated by datum
- Only do the above after verifying on chain that polls are closed
I would still like to leave this as optional if possible, though it will definitely be an initial implementation in the voting.js file in cardano-nft-mint-frontend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would still like to leave this as optional if possible, though it will definitely be an initial implementation in the voting.js file in cardano-nft-mint-frontend.
I disagree with this. I think that if there is going to be a standard, it should be just that -- standard. A 3rd party should not have to change their tabulation system in order to verify votes. Ballots should always be burned once the polls have closed. If a voting organizer wants to give out a commemorative voting NFT (think the "I voted" sticker), they should then mint assets on a new policy ID and send those to the voters.
Leaving it up to choice in this situation seems like the worst choice, it removes the benefits of standardizing this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we discussed in the chat, because the minting of the "ballot" HAS TO occur in the same transaction as the "send-to-ballot-box" (to prevent a "mint now, vote later" attack) I think this is less of a concern. Monitoring for a burn transaction would actually duplicate the cost to viewers who would have to find the burn transaction per the standard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upon further discussion with @thaddeusdiamond in a Discord server (and re-reading the proposal), I now tend to agree that the burning shouldn't be required, at least not for the sake of a developer. I still do believe that burning the token makes the most sense (release the minUTXO, prevent confusion on the side of users), but it certainly isn't mandatory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure about it being optional or not but I do agree that burning the token makes the most sense instead of sending it back to the voter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it makes more sense to burn the "ballots" instead of returning them to their respective voters.
Yes.
I think that if there is going to be a standard, it should be just that -- standard.
Also.
Upon further discussion with @thaddeusdiamond in a Discord server (and re-reading the proposal)
I'd love to see the outcome of that discussion in the 'Rationale'. In particular, the rationale for burning/not burning token needs to be stated clearly as this is clearly a point everyone seems to be tripping on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's mostly about the use case around commemorative NFTs. Will add a Rationale section with our offline discussion.
What is OP? I can update any forms you need I just was not sure of them.
I have talked to several NFT projects that want this kind of functionality (especially for newer/smaller projects), but they may not be technical. I've reached out to encourage them to comment here.
|
it's a common Internet abbreviation for Original Post, i.e. your comment here. When new proposals come in I generally link them from there to the working proposal to make it easy for me & others to review, especially when on the spot at our biweekly CIP meetings: Since you had already mentioned the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, the idea looks okay but I am missing a bit some perspective with existing similar voting systems such as SundaeSwap's (cc @Quantumplation) or Voteaire's (cc @codefly) from whom I'd appreciate their review / comments on this proposal.
I am also not fully sure to understand the need for a Ballot NFT and counting ballot contract altogether. Indeed, the counting seems to happen entirely off-chain, by fetching and ordering UTxO entries, and counting assets within them. The contract merely states the rule by which the ballot can be returned to their original voters. But, why bother minting and sending ballots in the first place then?
What is the added benefit compared to a more simple vote done by sending a transaction to oneself with the associated metadata? An off-chain process can easily fetch transactions with the appropriate metadata tag and count votes in a very similar fashion. If there's a clear benefit over doing that, it should be stated in the motivation (what problem this approach has) and the rationale (how this specification solves issues of that simple approach);
CIP-0071/README.md
Outdated
|
||
## Abstract | ||
|
||
This proposal defines a standard mechanism for performing verifiable on-chain voting in NFT projects that do not have a governance token by using datums, plutus minting policies, and smart contracts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
by using datums, plutus minting policies, and smart contracts.
This is implied by the fact that this is a verifiable on-chain voting solution. It would be nice in the abstract to get instead a high-level sense of how these are put to use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will reword.
CIP-0071/README.md
Outdated
|
||
This standard provides a simple solution for this by using the underlying NFT to mint a one-time "ballot" token that can be used only for a specific voting topic. Projects that adopt this standard will be able to integrate with web viewers that track projects' governance votes and will also receive the benefits of verifiable on-chain voting without requiring issuance of a new native token. | ||
|
||
It is not intended for complex voting applications or for governance against fungible tokens that cannot be labeled individually. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd love to see perhaps a concrete use case unfold in this section. Do you have a particular project as an example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added 3. I can name names or leave it generic just let me know which is preferred in CIPs.
CIP-0071/README.md
Outdated
Mint => { | ||
polls_are_still_open(tx.time_range) | ||
&& assets_were_spent(tx.minted, minted_policy, tx.outputs) | ||
&& assets_locked_in_script(tx, tx.minted) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the minting policy expected to check that the wallet has at least one NFT of the required policy in order to mint a ballot?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes that is assets_were_spent
let me rename the pseudocode better
|
||
#### "Vote" -> eUTxO Datum | ||
|
||
To cast the vote, the user sends the ballot NFT just created to a "ballot box". Note that for reasons specified in [the "attacks" section below](#Creation-of-Ballot-Without-Casting-a-Vote) this needs to occur during the same transaction that the ballot was minted in. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What enforces that? The minting policy?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that is the assets_locked_in_script
function above (will rename to assets_locked_in_ballot_box
).
}; | ||
``` | ||
|
||
The `voter` element is extremely important in this datum so that we know who minted the ballot NFT and who we should return it to. At the end of the ballot counting process, this user will receive their ballot NFT back. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not burn the ballot?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the new Rationale section around commemorative NFTs.
1. Ensure the polls are closed (can be either on or off-chain) | ||
2. Iterate through all UTxOs in forward-time-order locked in the "ballot box" and for each: | ||
* Determine which assets are inside of that UTxO | ||
* Mark their most recent vote to match the `vote` object in the UTxOs datum |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this last point answer a question I was about to ask about multiple votes. What happens when a voter mints multiple ballots and votes multiple time? This suggests only the most recent vote is counted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct. Only the most recent vote is counted, although all votes are technically "valid". Basically we are allowing voters to change their mind.
} | ||
``` | ||
|
||
There is no requirement that the "ballot counter" redeem all "ballots" from the "ballot box" and send them back to the respective voters, but we anticipate that this is what will happen in practice. We encourage further open-sourced code versions that enforce this requirement at the smart contract level. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it makes more sense to burn the "ballots" instead of returning them to their respective voters.
Yes.
I think that if there is going to be a standard, it should be just that -- standard.
Also.
Upon further discussion with @thaddeusdiamond in a Discord server (and re-reading the proposal)
I'd love to see the outcome of that discussion in the 'Rationale'. In particular, the rationale for burning/not burning token needs to be stated clearly as this is clearly a point everyone seems to be tripping on.
|
||
### Returning the "Ballot" NFTs to the Wrong User | ||
|
||
During the construction of the ballot NFTs we allow the user to specify their vote alongside a `voter` field indicating where their "ballot" NFT should be returned to once the vote is fully counted. Unfortunately, this is not strictly checked inside the Plutus minting policy's code (largely due to CPU/memory constraints). So, we rely on the user to provide an accurate return address, which means that there is the potential for someone who has not actually voted to receive a commemorative NFT. This does not impact the protocol though, as the "ballot" NFT was legally minted, just returned to the incorrect location. That user actually received a gift, as they can now burn the ballot and receive some small amount of dust. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, this is not strictly checked inside the Plutus minting policy's code (largely due to CPU/memory constraints).
I am not sure that this is a valid justification. Nor do I understand actually how one would check the voter field? Surely, there isn't much that the minting policy can do besides verifying that it's indeed a well-formed public key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's fair, we can remove it (or make the standard be that the user's return address is checked). Basically you would have to check that the datum.vote.address
field matches the pubkeyhash of one of the signatories of ballot creation. Should we change it to that?
CIP-0071/README.md
Outdated
|
||
The Helios code above simply checks that during a burn (as indicated by the Plutus minting policy's `redeemer`), the user is not attempting to mint a positive number of any assets. With this code, *any Cardano wallet* can burn *any ballot* minted as part of this protocol. Why so permissive? We want to ensure that each vote is bringing the minimal costs possible to the user. In providing this native burning mechanism we can free up the minUTxO that had been locked with the ballot, and enable the user to potentially participate in more votes they might not have otherwise. In addition, users who really do not like the specific commemorative NFTs or projects that choose to skip the "commemorative" aspect of ballot creation now have an easy way to dispose of "junk" assets. | ||
|
||
## Potential Attacks and Mitigations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please nest this under a Rationale
section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
- The mapping function described in the [Plutus minting policy for ballots](#Ballot---Plutus-Minting-Policy) should likely be some sort of prefixing or suffixing (e.g., "Ballot #1 - <REFERENCE NFT>"), and NOT the identity function. Although the asset will be different than the reference NFT due to its differing policy ID, users are likely to be confused when viewing these assets in a token viewer. | ||
- The "ballot" NFT should have some sort of unique metadata (if using [CIP-25](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0025)), datum (if using [CIP-68](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0068)) or other identification so that the users can engage with the ballot in a fun, exciting way and to ensure there is no confusion with the reference NFT. | ||
- The "vote" represented by a datum will be easier to debug and analyze in real-time if it uses the new "inline datum" feature from Vasil, but the protocol will still work on Alonzo era transactions. | ||
- The "ballot box" smart contract should likely enforce that the datum's "voter" field is respected when returning the ballots to users after voting has ended to provide greater transparency and trust for project participants. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing I am missing from the justifications here is why this solution addresses the problem stated in the motivation. As far as I understood, one of the core motivation was the cost of minting governance tokens (min ada value), but this proposal also proposes to mint ballot NFT and only, optionally return the ballot NFT to the voter. So arguably, the proposal only optionally addresses the motivation. Since this is stated as a motivation, I think the proposal should better describes how it solves this issue systematically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair. I think we can then enforce that the ballot has to be either:
a) Returned to the user
b) Burned and the ADA unlocked returned to the user
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd have a slight preference for "Burned and ADA returned to the user" because most users wouldn't probably know how to do that in the first place. Plus, it makes the protocol complete this way by cleaning up after oneself.
Thank you so much for the review. A couple of your comments I have follow-up questions on. I am also pushing a new revision that hopefully addresses some of your thoughts. More feedback welcome (especially @codefly and @Quantumplation seeing as they have governance experience.
I am not familiar with SundaeSwap but Voteaire uses metadata (correct me if I am wrong @codefly I am going off of https://github.com/voteaire/voteaire-onchain-spec). I would like to move the procedure on-chain to allow for on-chain verification of vote authenticity (e.g., enforcing RCV/vote selection in a Smart Contract).
The creation of the ballot and simultaneously sending in the vote is the entire process. Counting can occur off-chain (just like NFT viewers retrieve IPFS images off-chain), but the validity of the votes are enforced on-chain. I am going to add a few use cases in the "Motivation" section that hopefully clear up why you need to mint the ballots on-chain.
For dApps, it is much simpler (and more cost effective against service providers) to look for UTxOs at a single address (the ballot box). Otherwise we would have to snapshot the addresses who held and look at all their txn's during a voting period to find the specific vote. We also could not enforce vote authenticity on-chain.
I will update the motivation and rationale for why this needs to be on-chain. |
582341d
to
1138044
Compare
Thank you @thaddeusdiamond for writing up this proposal. We would certainly be adopting and using this standard at ApeWatch in order to let holders of our NFT - to be released - vote on various topics, e.g. which feature to build next - since we're aspiring to form a decentralized business council behind our platform. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As outlined in the editors meeting today, we're happy to see this proposal merged as Proposed while implementations are being worked on.
Please come back with updates on the proposal (might it simply be changing the status to 'Active') as the implementation progresses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I only noticed this from a recent review comment but there are several misspellings of ada, using instead the trading symbol ADA (according to Cardano Foundation long standing documentation, a style error):
[edit: p.s. for verification, please see this official page about Ada; since the trading symbol is never mentioned, note that it is never written in all-capitals: https://cardano.org/what-is-ada]
This is the initial commit for a proposed Cardano Improvement Proposal (CIP) that would enable NFT projects that did not want to use a governance or other native fungible asset to perform verifiable on-chain votes. [ Documentation: README.md, example/ ]
See changes in README.md
[See rendered Markdown](CIP-0071/README.md)
[See rendered Markdown](CIP-0071/README.md)
1138044
to
2945e44
Compare
Thank you @rphair. I have updated the CIP to to have the appropriate spelling for ADA -> ada. Can you advise on how to complete path to Active? So far I have:
Should I add those references somehow? |
one final update for ada vs. ADA typographical convention
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thaddeusdiamond I'll go ahead & merge this since it already satisfies the requirements laid out at yesterday's meeting and more. Since you'll be updating this to Active
soon enough, perhaps you'd link to the "full example" (cardano-nft-js-toolkit
) then (when you list your active implementations). 😎
In the 20th NFT Guild Roundtable we explored CIP 71 with its author @thaddeusdiamond Watch the entire Roundtable: Or read through the transcript: |
This is the initial commit for a proposed Cardano Improvement Proposal (CIP) that would enable NFT projects that did not want to use a governance or other native fungible asset to perform verifiable on-chain votes.
[ Documentation: README.md, example/ ]
see rendered Markdown