From d3bddfa82aaa838f3286a05664904612d0521008 Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sat, 9 Nov 2024 05:46:56 +0000 Subject: [PATCH 01/17] Adding Affirmation Graph --- CIP-AFFIRM/README.md | 70 ++++++++++++++++++++++++++++++ CIP-AFFIRM/affirmation.ak | 89 +++++++++++++++++++++++++++++++++++++++ CIP-AFFIRM/plutus.json | 57 +++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 CIP-AFFIRM/README.md create mode 100644 CIP-AFFIRM/affirmation.ak create mode 100644 CIP-AFFIRM/plutus.json diff --git a/CIP-AFFIRM/README.md b/CIP-AFFIRM/README.md new file mode 100644 index 0000000000..9d0ab7f82a --- /dev/null +++ b/CIP-AFFIRM/README.md @@ -0,0 +1,70 @@ +--- +CIP: ? +Title: Affirmation Graph +Category: Tools +Status: Proposed +Authors: + - Kieran Simkin +Implementors: [] +Discussions: + - https://github.com/cardano-foundation/CIPs/pull/? +Created: 2024-10-26 +License: CC-BY-4.0 +--- + +## Abstract +We need a truly decentralized alternative to KYC for when we need to establish the authenticity of a wallet or make some judgement about its trustworthiness in a systematic and repeatable manner. This CIP defines a mechanism whereby any member of the community can publicly vouch for the authenticity of a wallet by submitting an "affirmation" transaction, it also provides a mechanism to revoke such an affirmation, if, for example a wallet becomes compromised, or its owner turns out to be a charlatan. +It is consequently possible to observe the current UTxO set and draw an "Affirmation Graph", a multidigraph representing the trust relationships between wallets - we can then use an algorithm to assign trust rankings and decide whether or not to trust an unknown wallet. + +## Motivation: why is this CIP necessary? +When transacting with an unknown person, currently if we want to make sure we're not dealing with a bot or a grifter, we have to perform our own detective work - examining their current token holdings and transaction history, then we make some informed guess about what we're dealing with. This is both laborious and inconsistent. This CIP aims to provide a better alternative which is repeatable and automatable, this could drastically reduce the risk of fraud and accidental loss of funds. + +Now that we are in Cardano's Voltaire era; governance is top of the agenda, it would be really nice to be able to hold ballots where each community member gets an equal vote - true democracy requires it. Currently all voting is stake-weighted - ie. 1 ADA = 1 vote - I believe it was a mistake to extend stake-weighted voting outside of its original scope within consensus mechanisms - it enables a small group of wealthy stakeholders to manipulate every vote to their liking, and these rich stakeholders barely overlap with the people most qualified to be making technical and philosophical decisions about the future of the chain - many of the people who are the best qualified, are risk-adverse developers who operate almost entirely on testnet, and have only a few thousand Ada in their mainnet wallet. It's incredibly important for the future direction of Cardano that these these people have a fair vote and it's not just completely obliterated by even one whale vote, as it would be now. + +In this CIP we propose a simple, truly decentralized mechanism for identity verification and trust. + +## Specification +[v1 of the affirmation contract](affirmation.ak) + + +In order to send an affirmation to a *target* wallet, one must construct a "frankenaddress" consisting of the affirmation contract as the spending part and the *target*'s stake address for the delegation part. To this address you should send the minimum UTxO Ada, and you must mint a single token from the affirmation contract's policy, the token name must be set to your own stake key hash, the token, along with the min UTxO Ada should end up on an output at the script "frankenaddress", and this output must have an inline datum specifying your stake key (if you fail on any of these criteria, the validator will eat your money) - this open UTxO represents your current endorsement of a particular wallet. + +If you wish to revoke an affirmation, all you need do is "spend" the currently open UTxO at their frankenaddress. You must burn the associated token, and sign the transaction with your stake key, which must match the one that's stored on the UTxO datum and in the token name. + +It is worth noting that the target can also be a script address, so this allows smart contracts and NFT collections to receive affirmations too. + +MeshJS (the Typescript Cardano library) [has been updated](https://github.com/MeshJS/mesh/commit/fbfc8dd922ddf4c4df0d59f5fbd4f260af34da5d) so that it knows how to build these transactions, so you can do it in one easy step if you're in TS/JS. [A Python implementation](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.py) is also available. + +## Rationale: how does this CIP achieve its goals? +It could be argued that, with enough Ada, it is always possible to create many wallets and then submit affirmations for yourself - thus returning the system to being weighted by how much Ada you have - however, this would be a failure to understand the purpose of a decentralized Affirmation Graph - in a this regime, each individual person is responsible for interrogating the graph to establish a trust score for a particular wallet - but they have complete freedom on how they choose to interpret the graph - for example, you could decide to only trust wallets that have been affirmed by a specific person (perhaps yourself, or a person you know who has affirmed a lot of people and whose judgement you trust), or only trust wallets that have a minimum number of affirmations from anyone, or you could specify that at least two of your friends must have affirmed a wallet. You could even require that a centralized KYC provider has affirmed a wallet - this would allow actual KYC gating in a semi-decentralized manner - multiple KYC providers might exist, and you might choose to give a higher trust rating to some than others, perhaps depending on how thorough their ID verification process is. Other providers might exist which offer affirmations in return for proving you own a unique Facebook or Google account. + +It is expected that there could be a flood of services offering affirmations in return for jumping through any number of different hoops. It is also expected that mutual affirmations will be offered; "I'll affirm you if you affirm me". None of this does any harm to the value of the graph since we can design our algorithms to sift through the data and derive whatever meaning we please from it - the more we expand the size of the graph, the more we have to work with. + +The algorithms for interpreting the graph are expectied to become numerous and varied - some examples will be provided as part of the Affirmation Graph toolchain, and users will be free and encouraged to build their own and contribute them back to the library. + +### Could this amount to a form of social credit scoring? +Well, you could describe it that way, but the biggest problem with social credit is that it's decided by a centralized authority - there's no centralized authority here, it's an egalitarian collective. I think of it as similar to the way we all have an understanding of how reputable we consider a given person - some of that will be biased by our own position, but some people will be fundamentally more "reputable" than others, we all have an instinctive understanding of who we consider these people to be. There is, perhaps, a danger in making something like reputation so publicly visible - generally these reputation judgements are something we do so regularly in real life that it's an unconscious process a lot of the time, and we're often not even immediately aware of why we've judged a certain person as untrustworthy or not. The Affirmation Graph does still give you the privacy of your own judgements though as there's no way to know what criteria you're basing your decisions on. The only thing thing you're sharing publicly is the set of wallets you endorse - this is really no different to a public friend or follow list like you have on most social networks. + +This CIP is fundamentally about linking the social graph with the blockchain, so that you can have the same level of confidence that you're dealing with a real human-being as you do on Facebook or X. While this is never 100% certain, I would argue that most people can tell the difference between a real human or a bot on social media with a high degree of accuracy - we need to acheieve a similar level of confidence in our judgements about whether or not we trust a wallet on the blockchain. Only then can we have a hope of implementing 1-person-one-vote and having any meaninful form of democractic system - and that's the end goal; to enable Cardano governance to be truly democractic by removing the biases of stake-weighted voting, and instead move to 1 person = 1 vote. + +This system allows even a user who wishes to remain completely anonymous to develop a reputation and gain a trusted rating, even if they do not not wish to prove their indentity in any way - if they have an online persona, there will be people willing to affirm them based on that persona alone. + +## Path to Active + +### Acceptance Criteria +- [ ] Implementation of "Affirm this wallet" button in a couple of third-party dApps +- [ ] The mainnet graph needs to have a good number of affirmations in it + +### Implementation Plan +- [X] Design and test [the smart contract](affirmation.ak) along with its [transaction builders in Typescript](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.mesh.cjs) and [Python](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.py) +- [ ] Get feedback on the smart contract with a view to permanently setting it in stone +- [ ] A React control to enable blockchain explorers and dApps to easily add an "Affirm this wallet" button. +- [ ] Implement "Affirm this wallet" into [Cardano Looking Glass](https://clg.wtf/) +- [ ] Build out [a specialized chain indexer](https://github.com/kieransimkin/affirmation-graph-index) to enable queries on the graph. +- [ ] Create the first examples of trust scoring algorithms +- [ ] A React control for visualising the graph as a network diagram. +- [ ] Build a service which offers affirmations in return for KYC. + +## Copyright +This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode). + diff --git a/CIP-AFFIRM/affirmation.ak b/CIP-AFFIRM/affirmation.ak new file mode 100644 index 0000000000..92b0dc2fe1 --- /dev/null +++ b/CIP-AFFIRM/affirmation.ak @@ -0,0 +1,89 @@ +use aiken/collection/list.{filter, find, has} +use aiken/primitive/bytearray.{length} +use cardano/address.{Address, Script} +use cardano/assets.{PolicyId, quantity_of} +use cardano/transaction.{ + InlineDatum, Input, Output, OutputReference, Transaction, +} + +pub type AffirmationDatum { + owner: ByteArray, +} + +pub type RichAffirmationDatum { + owner: ByteArray, + class: Int, + payload: ByteArray, +} + +validator v1 { + mint(_redeemer: Data, own_policy: PolicyId, tx: Transaction) { + let Transaction { extra_signatories, outputs, mint, .. } = tx + expect [mint_triplet] = mint |> assets.flatten + let (mint_policy, mint_name, mint_quantity) = mint_triplet + expect mint_policy == own_policy + if mint_quantity == 1 { + expect [Output { datum: InlineDatum(output_datum), .. }] = + filter( + outputs, + fn(output) { output.address.payment_credential == Script(own_policy) }, + ) + if output_datum is AffirmationDatum { + let check_datum = output_datum + expect has(extra_signatories, check_datum.owner) == True + } else if output_datum is RichAffirmationDatum { + let check_datum: RichAffirmationDatum = output_datum + expect has(extra_signatories, check_datum.owner) == True + } else { + fail + } + } else { + expect has(extra_signatories, mint_name) == True + } + + when mint_quantity is { + 1 -> True + -1 -> True + _ -> False + } + } + + spend( + datum: Option, + _redeemer: Data, + own_ref: OutputReference, + tx: Transaction, + ) { + let Transaction { extra_signatories, inputs, mint, .. } = tx + expect [mint_triplet] = mint |> assets.flatten + + let (mint_policy, mint_name, mint_quantity) = mint_triplet + expect mint_quantity == -1 + expect Some(datum) = datum + expect Some(own_input) = + find(inputs, fn(input) { input.output_reference == own_ref }) + expect own_input.output.address.payment_credential == Script(mint_policy) + + if datum is AffirmationDatum { + let AffirmationDatum { owner } = datum + expect owner == mint_name + + expect quantity_of(own_input.output.value, mint_policy, owner) == 1 + expect has(extra_signatories, owner) == True + } else if datum is RichAffirmationDatum { + let RichAffirmationDatum { owner, class, payload } = datum + expect owner == mint_name + expect class > -1 + expect length(payload) > 0 + expect quantity_of(own_input.output.value, mint_policy, owner) == 1 + expect has(extra_signatories, owner) == True + } else { + fail + } + True + } + + else(_) { + fail + } +} diff --git a/CIP-AFFIRM/plutus.json b/CIP-AFFIRM/plutus.json new file mode 100644 index 0000000000..1d43a70261 --- /dev/null +++ b/CIP-AFFIRM/plutus.json @@ -0,0 +1,57 @@ +{ + "preamble": { + "title": "kieransimkin/affirmation-graph", + "description": "Aiken contracts for project 'affirmation-graph'", + "version": "1.0.0", + "plutusVersion": "v3", + "compiler": { + "name": "Aiken", + "version": "v1.1.4+79d0e45" + }, + "license": "Apache-2.0" + }, + "validators": [ + { + "title": "affirmation.v1.mint", + "redeemer": { + "title": "_redeemer", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "compiledCode": "59060201010032323232323232322533300232323232323232323232323253233300f30070081323232323232325333019301c002132323253330193371e6eb8c0780100284c94ccc068c0300085288a99980d19b87480040085288a505333019300b00113232533301e3021002132533301c3370e9002180e9baa00113232533333302500213330150021533301e533301e3301400b375c602460406ea8008528899980f2514a0944526160010010010010011533333302400113330120011533301d533301d3301300a375c6022603e6ea8004528899980ea514a09445261616161616163021301e37540022c604060426042603a6ea800458c07c004c8cc004004024894ccc07800452f5c026464a66603a66ebcc044c07cdd51808980f9baa0023374a9001198109ba900e4bd7009981080119802002000899802002000981100118100008a99980ca99980c998078030010a5113330194a2941288a4c2c2c6eb4c074c078008dd7180e000980e0008b1bac301a0013007375660320046eb0c060c064c064c064c064004c060c060008dd6180b000980b180b18091baa00d375c602860226ea802454ccc03cc0040204c8c8c8c8c8c8c8c8c94ccc06cc0780084c8c8c94ccc06ccdc39bad302030210024800454ccc06cc04cc070dd50050991919299980f180b180f9baa0011323253330203375e602860446ea8c050c088dd5180098111baa0023374a9001198121ba90084bd7009925132325333333029007133301900713253330233371e0020122a666046602a6660066eacc010c094dd5180218129baa00500b0011533302353330233301900e00114a22666046945282511498585858dd7181398121baa0070010010010010011533333302800613330160061323232323253330263371e0080182a66604c66e212001002153330263371090001b8d0011533302630183330063756600e60506ea8c01cc0a0dd50040070020a99981329998131980e0088020a5113330264a2941288a4c2c2c2c2c2c6eb8c0a8c0ac008dd6981480098148011bae30270013023375400c2c2c2c2c2c44464a666048602c604a6ea8004520001375a6052604c6ea8004c94ccc090c058c094dd50008a60103d87a80001323300100137566054604e6ea8008894ccc0a4004530103d87a8000132323232533302a337220100042a66605466e3c0200084c038cc0b8dd4000a5eb80530103d87a8000133006006003375a60560066eb8c0a4008c0b4008c0ac004c8cc004004010894ccc0a00045300103d87a80001323232325333029337220100042a66605266e3c0200084c034cc0b4dd3000a5eb80530103d87a8000133006006003375660540066eb8c0a0008c0b0008c0a8004588c094c098004c08cc080dd50008b19198008008059129998110008a60103d87a80001323253330213375e602a60466ea80080444c014cc0940092f5c0266008008002604c00460480026e9520003020301d37540142c2c6eb8c07c004c07c008dd7180e8008b1bac301c0013009375660360046eb0c068c06cc06cc06cc06c004c068c068c068c068008dd6180c000980a1baa00f301630170023015001301137540122c6e1d20022323300100100222533301300114bd70099199911191980080080191299980c80088018991980d9ba73301b375200c66036603000266036603200297ae033003003301d002301b001375c60240026eacc04c004cc00c00cc05c008c0540048c0480048894ccc038c018c03cdd50018992999809000801099299999980b80080180180180189919299980a800802899299999980d00080300300309919299980c000804099299999980e800804804804804899299980d180e8018a8058051bae001301a001301a003375a00200c602e002602e0066eb8004c050004c040dd50018009119198008008019129998088008a50132533300f3371e6eb8c050008010528899801801800980a0009112999806180218069baa003132533301000100213253333330150010030030030031325333012301500315005004375c0026024002601c6ea800c004dc3a400060106ea8004c02cc030008c028004c028008c020004c010dd50008a4c26cacae6955ceaab9e5573eae815d0aba25749", + "hash": "780b8dcab8ec263281b810e26c4e5ef5e38a057c297c686661c75d4d" + }, + { + "title": "affirmation.v1.spend", + "datum": { + "title": "datum", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "redeemer": { + "title": "_redeemer", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "compiledCode": "59060201010032323232323232322533300232323232323232323232323253233300f30070081323232323232325333019301c002132323253330193371e6eb8c0780100284c94ccc068c0300085288a99980d19b87480040085288a505333019300b00113232533301e3021002132533301c3370e9002180e9baa00113232533333302500213330150021533301e533301e3301400b375c602460406ea8008528899980f2514a0944526160010010010010011533333302400113330120011533301d533301d3301300a375c6022603e6ea8004528899980ea514a09445261616161616163021301e37540022c604060426042603a6ea800458c07c004c8cc004004024894ccc07800452f5c026464a66603a66ebcc044c07cdd51808980f9baa0023374a9001198109ba900e4bd7009981080119802002000899802002000981100118100008a99980ca99980c998078030010a5113330194a2941288a4c2c2c6eb4c074c078008dd7180e000980e0008b1bac301a0013007375660320046eb0c060c064c064c064c064004c060c060008dd6180b000980b180b18091baa00d375c602860226ea802454ccc03cc0040204c8c8c8c8c8c8c8c8c94ccc06cc0780084c8c8c94ccc06ccdc39bad302030210024800454ccc06cc04cc070dd50050991919299980f180b180f9baa0011323253330203375e602860446ea8c050c088dd5180098111baa0023374a9001198121ba90084bd7009925132325333333029007133301900713253330233371e0020122a666046602a6660066eacc010c094dd5180218129baa00500b0011533302353330233301900e00114a22666046945282511498585858dd7181398121baa0070010010010010011533333302800613330160061323232323253330263371e0080182a66604c66e212001002153330263371090001b8d0011533302630183330063756600e60506ea8c01cc0a0dd50040070020a99981329998131980e0088020a5113330264a2941288a4c2c2c2c2c2c6eb8c0a8c0ac008dd6981480098148011bae30270013023375400c2c2c2c2c2c44464a666048602c604a6ea8004520001375a6052604c6ea8004c94ccc090c058c094dd50008a60103d87a80001323300100137566054604e6ea8008894ccc0a4004530103d87a8000132323232533302a337220100042a66605466e3c0200084c038cc0b8dd4000a5eb80530103d87a8000133006006003375a60560066eb8c0a4008c0b4008c0ac004c8cc004004010894ccc0a00045300103d87a80001323232325333029337220100042a66605266e3c0200084c034cc0b4dd3000a5eb80530103d87a8000133006006003375660540066eb8c0a0008c0b0008c0a8004588c094c098004c08cc080dd50008b19198008008059129998110008a60103d87a80001323253330213375e602a60466ea80080444c014cc0940092f5c0266008008002604c00460480026e9520003020301d37540142c2c6eb8c07c004c07c008dd7180e8008b1bac301c0013009375660360046eb0c068c06cc06cc06cc06c004c068c068c068c068008dd6180c000980a1baa00f301630170023015001301137540122c6e1d20022323300100100222533301300114bd70099199911191980080080191299980c80088018991980d9ba73301b375200c66036603000266036603200297ae033003003301d002301b001375c60240026eacc04c004cc00c00cc05c008c0540048c0480048894ccc038c018c03cdd50018992999809000801099299999980b80080180180180189919299980a800802899299999980d00080300300309919299980c000804099299999980e800804804804804899299980d180e8018a8058051bae001301a001301a003375a00200c602e002602e0066eb8004c050004c040dd50018009119198008008019129998088008a50132533300f3371e6eb8c050008010528899801801800980a0009112999806180218069baa003132533301000100213253333330150010030030030031325333012301500315005004375c0026024002601c6ea800c004dc3a400060106ea8004c02cc030008c028004c028008c020004c010dd50008a4c26cacae6955ceaab9e5573eae815d0aba25749", + "hash": "780b8dcab8ec263281b810e26c4e5ef5e38a057c297c686661c75d4d" + }, + { + "title": "affirmation.v1.else", + "redeemer": { + "schema": {} + }, + "compiledCode": "59060201010032323232323232322533300232323232323232323232323253233300f30070081323232323232325333019301c002132323253330193371e6eb8c0780100284c94ccc068c0300085288a99980d19b87480040085288a505333019300b00113232533301e3021002132533301c3370e9002180e9baa00113232533333302500213330150021533301e533301e3301400b375c602460406ea8008528899980f2514a0944526160010010010010011533333302400113330120011533301d533301d3301300a375c6022603e6ea8004528899980ea514a09445261616161616163021301e37540022c604060426042603a6ea800458c07c004c8cc004004024894ccc07800452f5c026464a66603a66ebcc044c07cdd51808980f9baa0023374a9001198109ba900e4bd7009981080119802002000899802002000981100118100008a99980ca99980c998078030010a5113330194a2941288a4c2c2c6eb4c074c078008dd7180e000980e0008b1bac301a0013007375660320046eb0c060c064c064c064c064004c060c060008dd6180b000980b180b18091baa00d375c602860226ea802454ccc03cc0040204c8c8c8c8c8c8c8c8c94ccc06cc0780084c8c8c94ccc06ccdc39bad302030210024800454ccc06cc04cc070dd50050991919299980f180b180f9baa0011323253330203375e602860446ea8c050c088dd5180098111baa0023374a9001198121ba90084bd7009925132325333333029007133301900713253330233371e0020122a666046602a6660066eacc010c094dd5180218129baa00500b0011533302353330233301900e00114a22666046945282511498585858dd7181398121baa0070010010010010011533333302800613330160061323232323253330263371e0080182a66604c66e212001002153330263371090001b8d0011533302630183330063756600e60506ea8c01cc0a0dd50040070020a99981329998131980e0088020a5113330264a2941288a4c2c2c2c2c2c6eb8c0a8c0ac008dd6981480098148011bae30270013023375400c2c2c2c2c2c44464a666048602c604a6ea8004520001375a6052604c6ea8004c94ccc090c058c094dd50008a60103d87a80001323300100137566054604e6ea8008894ccc0a4004530103d87a8000132323232533302a337220100042a66605466e3c0200084c038cc0b8dd4000a5eb80530103d87a8000133006006003375a60560066eb8c0a4008c0b4008c0ac004c8cc004004010894ccc0a00045300103d87a80001323232325333029337220100042a66605266e3c0200084c034cc0b4dd3000a5eb80530103d87a8000133006006003375660540066eb8c0a0008c0b0008c0a8004588c094c098004c08cc080dd50008b19198008008059129998110008a60103d87a80001323253330213375e602a60466ea80080444c014cc0940092f5c0266008008002604c00460480026e9520003020301d37540142c2c6eb8c07c004c07c008dd7180e8008b1bac301c0013009375660360046eb0c068c06cc06cc06cc06c004c068c068c068c068008dd6180c000980a1baa00f301630170023015001301137540122c6e1d20022323300100100222533301300114bd70099199911191980080080191299980c80088018991980d9ba73301b375200c66036603000266036603200297ae033003003301d002301b001375c60240026eacc04c004cc00c00cc05c008c0540048c0480048894ccc038c018c03cdd50018992999809000801099299999980b80080180180180189919299980a800802899299999980d00080300300309919299980c000804099299999980e800804804804804899299980d180e8018a8058051bae001301a001301a003375a00200c602e002602e0066eb8004c050004c040dd50018009119198008008019129998088008a50132533300f3371e6eb8c050008010528899801801800980a0009112999806180218069baa003132533301000100213253333330150010030030030031325333012301500315005004375c0026024002601c6ea800c004dc3a400060106ea8004c02cc030008c028004c028008c020004c010dd50008a4c26cacae6955ceaab9e5573eae815d0aba25749", + "hash": "780b8dcab8ec263281b810e26c4e5ef5e38a057c297c686661c75d4d" + } + ], + "definitions": { + "Data": { + "title": "Data", + "description": "Any Plutus data." + } + } +} \ No newline at end of file From b2edfebfd4ed50628ca737531708081a4ea37945 Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sat, 9 Nov 2024 06:28:39 +0000 Subject: [PATCH 02/17] Adding link to the Affirmation Graph thread on the forum A forum post has been created to discuss this at: https://forum.cardano.org/t/introducing-the-affirmation-graph-request-for-comment/138320 --- CIP-AFFIRM/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CIP-AFFIRM/README.md b/CIP-AFFIRM/README.md index 9d0ab7f82a..b07f94a35f 100644 --- a/CIP-AFFIRM/README.md +++ b/CIP-AFFIRM/README.md @@ -7,7 +7,8 @@ Authors: - Kieran Simkin Implementors: [] Discussions: - - https://github.com/cardano-foundation/CIPs/pull/? + - https://github.com/cardano-foundation/CIPs/pull/938 + - https://forum.cardano.org/t/introducing-the-affirmation-graph-request-for-comment/138320 Created: 2024-10-26 License: CC-BY-4.0 --- From 1f4f7c3f1a61e917b1a485705eb713b3472c88aa Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sat, 9 Nov 2024 12:16:17 +0000 Subject: [PATCH 03/17] Add some more rationale and versioning details to Affirmation Graph --- CIP-AFFIRM/README.md | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/CIP-AFFIRM/README.md b/CIP-AFFIRM/README.md index b07f94a35f..f6bc1f667a 100644 --- a/CIP-AFFIRM/README.md +++ b/CIP-AFFIRM/README.md @@ -20,10 +20,15 @@ It is consequently possible to observe the current UTxO set and draw an "Affirma ## Motivation: why is this CIP necessary? When transacting with an unknown person, currently if we want to make sure we're not dealing with a bot or a grifter, we have to perform our own detective work - examining their current token holdings and transaction history, then we make some informed guess about what we're dealing with. This is both laborious and inconsistent. This CIP aims to provide a better alternative which is repeatable and automatable, this could drastically reduce the risk of fraud and accidental loss of funds. -Now that we are in Cardano's Voltaire era; governance is top of the agenda, it would be really nice to be able to hold ballots where each community member gets an equal vote - true democracy requires it. Currently all voting is stake-weighted - ie. 1 ADA = 1 vote - I believe it was a mistake to extend stake-weighted voting outside of its original scope within consensus mechanisms - it enables a small group of wealthy stakeholders to manipulate every vote to their liking, and these rich stakeholders barely overlap with the people most qualified to be making technical and philosophical decisions about the future of the chain - many of the people who are the best qualified, are risk-adverse developers who operate almost entirely on testnet, and have only a few thousand Ada in their mainnet wallet. It's incredibly important for the future direction of Cardano that these these people have a fair vote and it's not just completely obliterated by even one whale vote, as it would be now. +Now that we are in Cardano's Voltaire era; governance is top of the agenda, it would be really nice to be able to hold ballots where each community member gets an equal vote - true democracy requires it. Currently all voting is stake-weighted - ie. 1 Ada = 1 vote - I believe it was a mistake to extend stake-weighted voting outside of its original scope within consensus mechanisms - it enables a small group of wealthy stakeholders to manipulate every vote to their liking, and these rich stakeholders barely overlap with the people most qualified to be making technical and philosophical decisions about the future of the chain - many of the people who are the best qualified, are risk-adverse developers who operate almost entirely on testnet, and have only a few thousand Ada in their mainnet wallet. It's incredibly important for the future direction of Cardano that these these people have a fair vote and it's not just completely obliterated by even one whale vote, as it would be now. In this CIP we propose a simple, truly decentralized mechanism for identity verification and trust. +### Why does this require a CIP? +We are trying to create a scheme which is generic and becomes the accepted standard for registering your affirmation of a particular wallet, such that everyone may participate and we can be sure that there is one definitive affirmation graph for the blockchain and that all affirmation transactions will follow a consistent format. As such, a defined standard that everyone can follow is necessary - a CIP is the way to acheive this. + +To that end, the smart contract which has been defined attempts to be the most simple and generic possible whilst allowing the affirmer (and only the affirmer) to revoke their affirmation. No fee is required (aside from the inherent blockchain fees), the smart contract contains nothing specific to the author's websites or implementation. It is designed so that it can be integrated into any blockchain explorer or dApp. + ## Specification [v1 of the affirmation contract](affirmation.ak) @@ -36,19 +41,29 @@ It is worth noting that the target can also be a script address, so this allows MeshJS (the Typescript Cardano library) [has been updated](https://github.com/MeshJS/mesh/commit/fbfc8dd922ddf4c4df0d59f5fbd4f260af34da5d) so that it knows how to build these transactions, so you can do it in one easy step if you're in TS/JS. [A Python implementation](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.py) is also available. +### Versioning +Any change to the specification will result in a new smart contract, and consequently a new script hash will be generated. Since we draw the affirmation graph by monitoring for UTxOs with the script hash as the payment part of their address, it is desirable to keep new versions to a minimum - as every additional version will effectively create an entirely separate graph, as well as increasing the monitoring overhead for anyone wishing to draw the graph, and require anyone wishing to implement the affirm and revoke actions into their own code to interact with multiple contract endpoints. + +For this reason - once the initial affirmation contract has received feedback and any necessary alterations have been made, this will be "set in stone" as version 1 of the affirmation graph, and any subsequent modifications will require an entirely new specification (and new CIP). + ## Rationale: how does this CIP achieve its goals? It could be argued that, with enough Ada, it is always possible to create many wallets and then submit affirmations for yourself - thus returning the system to being weighted by how much Ada you have - however, this would be a failure to understand the purpose of a decentralized Affirmation Graph - in a this regime, each individual person is responsible for interrogating the graph to establish a trust score for a particular wallet - but they have complete freedom on how they choose to interpret the graph - for example, you could decide to only trust wallets that have been affirmed by a specific person (perhaps yourself, or a person you know who has affirmed a lot of people and whose judgement you trust), or only trust wallets that have a minimum number of affirmations from anyone, or you could specify that at least two of your friends must have affirmed a wallet. You could even require that a centralized KYC provider has affirmed a wallet - this would allow actual KYC gating in a semi-decentralized manner - multiple KYC providers might exist, and you might choose to give a higher trust rating to some than others, perhaps depending on how thorough their ID verification process is. Other providers might exist which offer affirmations in return for proving you own a unique Facebook or Google account. -It is expected that there could be a flood of services offering affirmations in return for jumping through any number of different hoops. It is also expected that mutual affirmations will be offered; "I'll affirm you if you affirm me". None of this does any harm to the value of the graph since we can design our algorithms to sift through the data and derive whatever meaning we please from it - the more we expand the size of the graph, the more we have to work with. +It is expected that there could be a flood of services offering affirmations in return for jumping through any number of different hoops. It is also expected that mutual affirmations will be offered; "I'll affirm you if you affirm me". Stake pools might choose to offer affirmations in return for keeping your delegation with them for some amount of time. None of this does any harm to the value of the graph since we can design our algorithms to sift through the data and derive whatever meaning we please from it - the more we expand the size of the graph, the more we have to work with. -The algorithms for interpreting the graph are expectied to become numerous and varied - some examples will be provided as part of the Affirmation Graph toolchain, and users will be free and encouraged to build their own and contribute them back to the library. +I would also suggest that affirmations should be given in return for certain "good citizen" behaviours - for example, affirmations could be given to Catalyst participants upon successful completion of their project milestones. Affirmations could also be given in return for participation in voting events, or in return for helping moderate Catalyst proposals. SPOs could receive affirmations in return for upgrading to the latest node version - any behaviour which we wish to incentivise could be rewarded with affirmations - this provides a great way to incentivise good behaviour, whilst also allowing us to judge wallets based on their behaviour. + +The algorithms for interpreting the graph are expectied to become numerous and varied - some examples will be provided as part of the Affirmation Graph toolchain, and users will be free and encouraged to build their own and contribute them back to the library. These algorithms will function by assigning a trust score to a wallet, based on a set of weighted judgement criteria - different algorithms will assign different weights to affirmations depending on where they came from. For example, an algorithm that requires KYC verification would assign positive weights to known KYC providers, and zero weights to all other affirmations. A "trust my friends" algorithm could measure each affirmer's distance from yourself on the graph, and weight affirmations from people close to you on the graph highly, with an exponential fall-off as the affirmer is an increasing number of steps away from you on the graph. ### Could this amount to a form of social credit scoring? Well, you could describe it that way, but the biggest problem with social credit is that it's decided by a centralized authority - there's no centralized authority here, it's an egalitarian collective. I think of it as similar to the way we all have an understanding of how reputable we consider a given person - some of that will be biased by our own position, but some people will be fundamentally more "reputable" than others, we all have an instinctive understanding of who we consider these people to be. There is, perhaps, a danger in making something like reputation so publicly visible - generally these reputation judgements are something we do so regularly in real life that it's an unconscious process a lot of the time, and we're often not even immediately aware of why we've judged a certain person as untrustworthy or not. The Affirmation Graph does still give you the privacy of your own judgements though as there's no way to know what criteria you're basing your decisions on. The only thing thing you're sharing publicly is the set of wallets you endorse - this is really no different to a public friend or follow list like you have on most social networks. -This CIP is fundamentally about linking the social graph with the blockchain, so that you can have the same level of confidence that you're dealing with a real human-being as you do on Facebook or X. While this is never 100% certain, I would argue that most people can tell the difference between a real human or a bot on social media with a high degree of accuracy - we need to acheieve a similar level of confidence in our judgements about whether or not we trust a wallet on the blockchain. Only then can we have a hope of implementing 1-person-one-vote and having any meaninful form of democractic system - and that's the end goal; to enable Cardano governance to be truly democractic by removing the biases of stake-weighted voting, and instead move to 1 person = 1 vote. +This system allows even a user who wishes to remain completely anonymous to develop a reputation and gain a trusted rating, even if they do not not wish to prove their indentity in any way - if they have an online persona, there will be people willing to affirm them based on that persona alone. Plus, they may accrue affirmations by displaying good behaviour if such behaviour is rewarded by affirmation as suggested. + +This CIP is fundamentally about linking the social graph with the blockchain, so that you can have the same level of confidence that you're dealing with a real human-being as you do on Facebook or X. While this is never 100% certain, I would argue that most people can tell the difference between a real human or a bot on social media with a high degree of accuracy - we need to acheieve a similar level of confidence in our judgements about whether or not we trust a wallet on the blockchain. Only then can we have a hope of implementing 1-person-one-vote and having any meaninful form of democractic system - and that's the end goal; to enable Cardano governance to be truly democractic by removing the biases of stake-weighted voting, and instead move to something more closely representing 1 person = 1 vote. + +We would also have the option of implementing a true meritocracy where a user's voting power is actually weighted by their trust score - so instead of 1 person = 1 vote, we'd actually give stronger weight to those with very high trust ratings - this would work particularly well in a scenario where we were rewarding good behaviour with affirmations, but there would potentially be a risk of power being centralized among a few very highly trusted individuals - for example if we rewarded Catalyst participants for meeting their milestones, we could find that regular Catalyst participants received very high trust ratings which enabled them to outvote everyone else. We'd therefore have to carefully design the weighting algorithm to avoid this - it may be simpler to stick to 1 person = 1 vote, and simply require a minimum trust score threshold in order to verify that a wallet represents a unique person. -This system allows even a user who wishes to remain completely anonymous to develop a reputation and gain a trusted rating, even if they do not not wish to prove their indentity in any way - if they have an online persona, there will be people willing to affirm them based on that persona alone. ## Path to Active From 766e108015b9ab9cf3014bb96fe2e3147cae3e3a Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:35:38 +0000 Subject: [PATCH 04/17] Make the affirmation specification generic so that third party smart contracts may be written that conform to the specification --- CIP-AFFIRM/README.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/CIP-AFFIRM/README.md b/CIP-AFFIRM/README.md index f6bc1f667a..1e414e6f86 100644 --- a/CIP-AFFIRM/README.md +++ b/CIP-AFFIRM/README.md @@ -20,24 +20,31 @@ It is consequently possible to observe the current UTxO set and draw an "Affirma ## Motivation: why is this CIP necessary? When transacting with an unknown person, currently if we want to make sure we're not dealing with a bot or a grifter, we have to perform our own detective work - examining their current token holdings and transaction history, then we make some informed guess about what we're dealing with. This is both laborious and inconsistent. This CIP aims to provide a better alternative which is repeatable and automatable, this could drastically reduce the risk of fraud and accidental loss of funds. -Now that we are in Cardano's Voltaire era; governance is top of the agenda, it would be really nice to be able to hold ballots where each community member gets an equal vote - true democracy requires it. Currently all voting is stake-weighted - ie. 1 Ada = 1 vote - I believe it was a mistake to extend stake-weighted voting outside of its original scope within consensus mechanisms - it enables a small group of wealthy stakeholders to manipulate every vote to their liking, and these rich stakeholders barely overlap with the people most qualified to be making technical and philosophical decisions about the future of the chain - many of the people who are the best qualified, are risk-adverse developers who operate almost entirely on testnet, and have only a few thousand Ada in their mainnet wallet. It's incredibly important for the future direction of Cardano that these these people have a fair vote and it's not just completely obliterated by even one whale vote, as it would be now. +Now that we are in Cardano's Voltaire era; governance is top of the agenda, it would be really nice to be able to hold ballots where each community member gets an equal vote - true democracy requires it. Currently all voting is stake-weighted - ie. 1 Ada = 1 vote - This author believes it was a mistake to extend stake-weighted voting outside of its original scope within consensus mechanisms - it enables a small group of wealthy stakeholders to manipulate every vote to their liking, and these rich stakeholders barely overlap with the people most qualified to be making technical and philosophical decisions about the future of the chain - many of the people who are the best qualified, are risk-adverse developers who operate almost entirely on testnet, and have only a few thousand Ada in their mainnet wallet. It's incredibly important for the future direction of Cardano that these these people have a fair vote and it's not just completely obliterated by even one whale vote, as it would be now. In this CIP we propose a simple, truly decentralized mechanism for identity verification and trust. ### Why does this require a CIP? We are trying to create a scheme which is generic and becomes the accepted standard for registering your affirmation of a particular wallet, such that everyone may participate and we can be sure that there is one definitive affirmation graph for the blockchain and that all affirmation transactions will follow a consistent format. As such, a defined standard that everyone can follow is necessary - a CIP is the way to acheive this. -To that end, the smart contract which has been defined attempts to be the most simple and generic possible whilst allowing the affirmer (and only the affirmer) to revoke their affirmation. No fee is required (aside from the inherent blockchain fees), the smart contract contains nothing specific to the author's websites or implementation. It is designed so that it can be integrated into any blockchain explorer or dApp. +To that end, the smart contract which has been defined attempts to be the most simple and generic possible whilst allowing the affirmer (and only the affirmer) to revoke their affirmation. No fee is required (aside from the inherent blockchain fees), the smart contract contains nothing specific to the author's websites or implementation. It is designed so that it can be integrated into any blockchain explorer, wallet or dApp. ## Specification [v1 of the affirmation contract](affirmation.ak) -In order to send an affirmation to a *target* wallet, one must construct a "frankenaddress" consisting of the affirmation contract as the spending part and the *target*'s stake address for the delegation part. To this address you should send the minimum UTxO Ada, and you must mint a single token from the affirmation contract's policy, the token name must be set to your own stake key hash, the token, along with the min UTxO Ada should end up on an output at the script "frankenaddress", and this output must have an inline datum specifying your stake key (if you fail on any of these criteria, the validator will eat your money) - this open UTxO represents your current endorsement of a particular wallet. +Definitions: +*target* - the recipient of the affirmation +*source* - the creator of the affirmation (the person or entity who is vouching for them) +*target hash* - if the *target* is a normal wallet, this should be their stake key hash. If the *target* is a script, this should be the script hash +*source hash* - if the *source* is a normal wallet, this should be their stake key hash. If the *source* is a script, this should be the script hash +*affirmation script* - any script which conforms to this specification (details below) +*script hash* - the hash of the *affirmation script* +*affirmation address* - An address where the spending part is *script hash* and the delegation part is *target hash* -If you wish to revoke an affirmation, all you need do is "spend" the currently open UTxO at their frankenaddress. You must burn the associated token, and sign the transaction with your stake key, which must match the one that's stored on the UTxO datum and in the token name. +An affirmation consists of a UTxO at the *affirmation address* with an inline datum containing the *source hash*. To be valid, this UTxO must contain one token minted by the *affirmation script*. -It is worth noting that the target can also be a script address, so this allows smart contracts and NFT collections to receive affirmations too. +A valid *affirmation script* _MUST_ allow minting exactly one token at a time, it _MUST_ ensure that it receives a signature matching the *source hash* or is otherwise authorized by *source*, it _MUST_ ensure that the output containing the newly minted token contains an inline datum with a matching *source hash*, it _MUST_ also ensure that this output it sent to an address where the spending part is equal to the *script hash*. In order to enable revokation, the script should allow spending, and _MUST_ ensure that it receives a signature matching *source hash* or is otherwise authorized by *source* and _MUST_ ensure that exactly one token matching the *affirmation script*'s policy ID is burned. MeshJS (the Typescript Cardano library) [has been updated](https://github.com/MeshJS/mesh/commit/fbfc8dd922ddf4c4df0d59f5fbd4f260af34da5d) so that it knows how to build these transactions, so you can do it in one easy step if you're in TS/JS. [A Python implementation](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.py) is also available. @@ -55,6 +62,8 @@ I would also suggest that affirmations should be given in return for certain "go The algorithms for interpreting the graph are expectied to become numerous and varied - some examples will be provided as part of the Affirmation Graph toolchain, and users will be free and encouraged to build their own and contribute them back to the library. These algorithms will function by assigning a trust score to a wallet, based on a set of weighted judgement criteria - different algorithms will assign different weights to affirmations depending on where they came from. For example, an algorithm that requires KYC verification would assign positive weights to known KYC providers, and zero weights to all other affirmations. A "trust my friends" algorithm could measure each affirmer's distance from yourself on the graph, and weight affirmations from people close to you on the graph highly, with an exponential fall-off as the affirmer is an increasing number of steps away from you on the graph. +Wallets could choose to display a trust score whenever they prompt you to sign a transaction - this could help users identify if they're dealing with a potential scammer, before they send them Ada. Since smart contracts can also receive affirmations, and consequently can be given a trust score, wallets might also decide to display this score every time you interact with a smart contract. + ### Could this amount to a form of social credit scoring? Well, you could describe it that way, but the biggest problem with social credit is that it's decided by a centralized authority - there's no centralized authority here, it's an egalitarian collective. I think of it as similar to the way we all have an understanding of how reputable we consider a given person - some of that will be biased by our own position, but some people will be fundamentally more "reputable" than others, we all have an instinctive understanding of who we consider these people to be. There is, perhaps, a danger in making something like reputation so publicly visible - generally these reputation judgements are something we do so regularly in real life that it's an unconscious process a lot of the time, and we're often not even immediately aware of why we've judged a certain person as untrustworthy or not. The Affirmation Graph does still give you the privacy of your own judgements though as there's no way to know what criteria you're basing your decisions on. The only thing thing you're sharing publicly is the set of wallets you endorse - this is really no different to a public friend or follow list like you have on most social networks. From b8b1608adac6a2db8433f2244a07137ad46bcd14 Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:39:42 +0000 Subject: [PATCH 05/17] Formatting fix --- CIP-AFFIRM/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CIP-AFFIRM/README.md b/CIP-AFFIRM/README.md index 1e414e6f86..05b40c1b5a 100644 --- a/CIP-AFFIRM/README.md +++ b/CIP-AFFIRM/README.md @@ -35,11 +35,17 @@ To that end, the smart contract which has been defined attempts to be the most s Definitions: *target* - the recipient of the affirmation + *source* - the creator of the affirmation (the person or entity who is vouching for them) + *target hash* - if the *target* is a normal wallet, this should be their stake key hash. If the *target* is a script, this should be the script hash + *source hash* - if the *source* is a normal wallet, this should be their stake key hash. If the *source* is a script, this should be the script hash + *affirmation script* - any script which conforms to this specification (details below) + *script hash* - the hash of the *affirmation script* + *affirmation address* - An address where the spending part is *script hash* and the delegation part is *target hash* An affirmation consists of a UTxO at the *affirmation address* with an inline datum containing the *source hash*. To be valid, this UTxO must contain one token minted by the *affirmation script*. From 27c8210f9ae8501690d685babfecfbd4136cf561 Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sat, 9 Nov 2024 23:41:03 +0000 Subject: [PATCH 06/17] Improve formatting and add datum specification cddl for affirmation --- CIP-AFFIRM/README.md | 48 +++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/CIP-AFFIRM/README.md b/CIP-AFFIRM/README.md index 05b40c1b5a..cf4636ed5c 100644 --- a/CIP-AFFIRM/README.md +++ b/CIP-AFFIRM/README.md @@ -30,30 +30,42 @@ We are trying to create a scheme which is generic and becomes the accepted stand To that end, the smart contract which has been defined attempts to be the most simple and generic possible whilst allowing the affirmer (and only the affirmer) to revoke their affirmation. No fee is required (aside from the inherent blockchain fees), the smart contract contains nothing specific to the author's websites or implementation. It is designed so that it can be integrated into any blockchain explorer, wallet or dApp. ## Specification -[v1 of the affirmation contract](affirmation.ak) +[v1 of the affirmation contract](affirmation.ak) +Definitions: +**target** - the recipient of the affirmation +**source** - the creator of the affirmation (the person or entity who is vouching for them) +**target hash** - if the **target** is a normal wallet, this should be their stake key hash. If the **target** is a script, this should be the script hash +**source hash** - if the **source** is a normal wallet, this should be their stake key hash. If the **source** is a script, this should be the script hash +**affirmation script** - any script which conforms to this specification (details below) +**script hash** - the hash of the **affirmation script** +**affirmation address** - An address where the spending part is **script hash** and the delegation part is **target hash** -Definitions: -*target* - the recipient of the affirmation +An affirmation consists of a UTxO at the **affirmation address** with an inline datum containing the **source hash**. To be valid, this UTxO must contain one token minted by the **affirmation script**, and the **affirmation script** itself must be valid as defined below: -*source* - the creator of the affirmation (the person or entity who is vouching for them) - -*target hash* - if the *target* is a normal wallet, this should be their stake key hash. If the *target* is a script, this should be the script hash - -*source hash* - if the *source* is a normal wallet, this should be their stake key hash. If the *source* is a script, this should be the script hash - -*affirmation script* - any script which conforms to this specification (details below) - -*script hash* - the hash of the *affirmation script* - -*affirmation address* - An address where the spending part is *script hash* and the delegation part is *target hash* - -An affirmation consists of a UTxO at the *affirmation address* with an inline datum containing the *source hash*. To be valid, this UTxO must contain one token minted by the *affirmation script*. - -A valid *affirmation script* _MUST_ allow minting exactly one token at a time, it _MUST_ ensure that it receives a signature matching the *source hash* or is otherwise authorized by *source*, it _MUST_ ensure that the output containing the newly minted token contains an inline datum with a matching *source hash*, it _MUST_ also ensure that this output it sent to an address where the spending part is equal to the *script hash*. In order to enable revokation, the script should allow spending, and _MUST_ ensure that it receives a signature matching *source hash* or is otherwise authorized by *source* and _MUST_ ensure that exactly one token matching the *affirmation script*'s policy ID is burned. +A valid **affirmation script** _MUST_ allow minting exactly one token at a time, it _MUST_ ensure that it receives a signature matching the **source hash** or is otherwise authorized by **source**, it _MUST_ ensure that the output containing the newly minted token contains an inline datum with a matching **source hash**, it _MUST_ also ensure that this output it sent to an address where the spending part is equal to the **script hash**. In order to enable revokation, the script should allow spending, and _MUST_ ensure that it receives a signature matching **source hash** or is otherwise authorized by **source** and _MUST_ ensure that exactly one token matching the **affirmation script**'s policy ID is burned. MeshJS (the Typescript Cardano library) [has been updated](https://github.com/MeshJS/mesh/commit/fbfc8dd922ddf4c4df0d59f5fbd4f260af34da5d) so that it knows how to build these transactions, so you can do it in one easy step if you're in TS/JS. [A Python implementation](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.py) is also available. +### Datum specification +```cddl +keyhash = bytes .size 28 +datum = #6.121([keyhash]) +``` + +Example datum as JSON: + +```json +{ + "constructor": 0, + "fields": [ + { + "bytes": "4ec65f9ad80492c187df2d9d7428d5c1fef10de7687cdf9356170816" + } + ] +} +``` + ### Versioning Any change to the specification will result in a new smart contract, and consequently a new script hash will be generated. Since we draw the affirmation graph by monitoring for UTxOs with the script hash as the payment part of their address, it is desirable to keep new versions to a minimum - as every additional version will effectively create an entirely separate graph, as well as increasing the monitoring overhead for anyone wishing to draw the graph, and require anyone wishing to implement the affirm and revoke actions into their own code to interact with multiple contract endpoints. From 27ba7cf9edf1b8f3148c0c73a6e6d09a3fd928bc Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sun, 10 Nov 2024 01:39:11 +0000 Subject: [PATCH 07/17] Lots of tidying and formatting fixes for Affirmations --- CIP-AFFIRM/README.md | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/CIP-AFFIRM/README.md b/CIP-AFFIRM/README.md index cf4636ed5c..b227b271bf 100644 --- a/CIP-AFFIRM/README.md +++ b/CIP-AFFIRM/README.md @@ -20,14 +20,16 @@ It is consequently possible to observe the current UTxO set and draw an "Affirma ## Motivation: why is this CIP necessary? When transacting with an unknown person, currently if we want to make sure we're not dealing with a bot or a grifter, we have to perform our own detective work - examining their current token holdings and transaction history, then we make some informed guess about what we're dealing with. This is both laborious and inconsistent. This CIP aims to provide a better alternative which is repeatable and automatable, this could drastically reduce the risk of fraud and accidental loss of funds. -Now that we are in Cardano's Voltaire era; governance is top of the agenda, it would be really nice to be able to hold ballots where each community member gets an equal vote - true democracy requires it. Currently all voting is stake-weighted - ie. 1 Ada = 1 vote - This author believes it was a mistake to extend stake-weighted voting outside of its original scope within consensus mechanisms - it enables a small group of wealthy stakeholders to manipulate every vote to their liking, and these rich stakeholders barely overlap with the people most qualified to be making technical and philosophical decisions about the future of the chain - many of the people who are the best qualified, are risk-adverse developers who operate almost entirely on testnet, and have only a few thousand Ada in their mainnet wallet. It's incredibly important for the future direction of Cardano that these these people have a fair vote and it's not just completely obliterated by even one whale vote, as it would be now. +Now that we are in Cardano's Voltaire era; governance is top of the agenda, it would be really nice to be able to hold ballots where each community member gets an equal vote - true democracy requires it. Currently all voting is stake-weighted - ie. 1 Ada = 1 vote - this results in a plutocracy, not a democracy. In order to deliver a fair democracy, we must have some way of identifying unique individuals. Traditionally this would be done with KYC - each voting participant would be required to identify themselves with some form of government ID - however, this relies on a central authority having issued the ID, and another central authority verifying it. It also excludes people who wish to (or must) remain anonymous for whatever reason, as well as those who may not have any government ID, perhaps because they are stateless. + +If we are to bank the unbanked, we should also provide ID for those who have none. In this CIP we propose a simple, truly decentralized mechanism for identity verification and trust. ### Why does this require a CIP? -We are trying to create a scheme which is generic and becomes the accepted standard for registering your affirmation of a particular wallet, such that everyone may participate and we can be sure that there is one definitive affirmation graph for the blockchain and that all affirmation transactions will follow a consistent format. As such, a defined standard that everyone can follow is necessary - a CIP is the way to acheive this. +We are aiming to create a scheme which is generic and becomes the accepted standard for registering your affirmation of a particular wallet, such that everyone may participate and we can be sure that there is one definitive affirmation graph for the blockchain and that all affirmation transactions will follow a consistent format. As such, a defined standard that everyone can follow is necessary - a CIP is the way to acheive this. -To that end, the smart contract which has been defined attempts to be the most simple and generic possible whilst allowing the affirmer (and only the affirmer) to revoke their affirmation. No fee is required (aside from the inherent blockchain fees), the smart contract contains nothing specific to the author's websites or implementation. It is designed so that it can be integrated into any blockchain explorer, wallet or dApp. +To that end, a smart contract conforming to this specification has been defined which attempts to be the most simple and generic possible. No fee is required (aside from the inherent blockchain fees), the smart contract contains nothing specific to the author's websites or implementation. It is designed so that it can be integrated into any blockchain explorer, wallet or dApp. It is expected that the majority will use this generic smart contract, but it's also possible to define your own smart contract that is compliant with this CIP - it must meet the specific requirements detailed below. ## Specification [v1 of the affirmation contract](affirmation.ak) @@ -37,13 +39,23 @@ Definitions: **source** - the creator of the affirmation (the person or entity who is vouching for them) **target hash** - if the **target** is a normal wallet, this should be their stake key hash. If the **target** is a script, this should be the script hash **source hash** - if the **source** is a normal wallet, this should be their stake key hash. If the **source** is a script, this should be the script hash -**affirmation script** - any script which conforms to this specification (details below) -**script hash** - the hash of the **affirmation script** -**affirmation address** - An address where the spending part is **script hash** and the delegation part is **target hash** +**affirmation contract** - any smart contract which conforms to this specification (details below) +**contract hash** - the hash of the **affirmation contract** +**affirmation address** - An address where the spending part is **contract hash** and the delegation part is **target hash** + +An affirmation consists of a UTxO at the **affirmation address** with an inline datum containing the **source hash**. To be valid, this UTxO must contain one token minted by the **affirmation contract**, and the **affirmation contract** itself must be valid as defined below: -An affirmation consists of a UTxO at the **affirmation address** with an inline datum containing the **source hash**. To be valid, this UTxO must contain one token minted by the **affirmation script**, and the **affirmation script** itself must be valid as defined below: +A valid **affirmation contract** _MUST_ allow minting exactly one token at a time. In order to mint: + - it _MUST_ ensure that it receives a signature matching the **source hash** or is otherwise authorized by **source**, + - it _MUST_ ensure that the output containing the newly minted token contains an inline datum with a matching **source hash** and + - it _MUST_ ensure that this output it sent to an address where the spending part is equal to the **contract hash**. +In order to enable revokation, the contract should allow spending. When spending, the contract: + - _MUST_ ensure that it receives a signature matching the **source hash** in the datum, or is otherwise authorized by **source** and + - _MUST_ ensure that exactly one token matching the **affirmation contract**'s policy ID is burned. -A valid **affirmation script** _MUST_ allow minting exactly one token at a time, it _MUST_ ensure that it receives a signature matching the **source hash** or is otherwise authorized by **source**, it _MUST_ ensure that the output containing the newly minted token contains an inline datum with a matching **source hash**, it _MUST_ also ensure that this output it sent to an address where the spending part is equal to the **script hash**. In order to enable revokation, the script should allow spending, and _MUST_ ensure that it receives a signature matching **source hash** or is otherwise authorized by **source** and _MUST_ ensure that exactly one token matching the **affirmation script**'s policy ID is burned. +A generic **affirmation contract** has been provided which meets these requirements - you should use that unless you have specific requirements which are not met by that script. + +It should be noted that if you do write your own custom **affirmation contract**, your affirmations will not automatically be picked up by the [affirmation graph indexer](https://github.com/kieransimkin/affirmation-graph-index) - this is because the indexer maintains a list of known valid affirmation contracts. If you wish to add your contract to the list you should submit a pull request to the indexer repository in which you must prove that your contract meets the requirements detailed above - only then will your affirmations be included in the global Affirmation Graph. If in doubt, simply use the generic affirmation contract that has been provided as part of this CIP unless you have a good reason not to. MeshJS (the Typescript Cardano library) [has been updated](https://github.com/MeshJS/mesh/commit/fbfc8dd922ddf4c4df0d59f5fbd4f260af34da5d) so that it knows how to build these transactions, so you can do it in one easy step if you're in TS/JS. [A Python implementation](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.py) is also available. @@ -67,9 +79,7 @@ Example datum as JSON: ``` ### Versioning -Any change to the specification will result in a new smart contract, and consequently a new script hash will be generated. Since we draw the affirmation graph by monitoring for UTxOs with the script hash as the payment part of their address, it is desirable to keep new versions to a minimum - as every additional version will effectively create an entirely separate graph, as well as increasing the monitoring overhead for anyone wishing to draw the graph, and require anyone wishing to implement the affirm and revoke actions into their own code to interact with multiple contract endpoints. - -For this reason - once the initial affirmation contract has received feedback and any necessary alterations have been made, this will be "set in stone" as version 1 of the affirmation graph, and any subsequent modifications will require an entirely new specification (and new CIP). +This is version 1 of the affirmation graph specification - any material change in the specification will necesssarily require a new smart contract, which will result in new set of **affirmation addresses**. Consequently an affirmation contract will always target a specific version of the specification. Any new version of this specification should be separately defined in its own CIP. ## Rationale: how does this CIP achieve its goals? It could be argued that, with enough Ada, it is always possible to create many wallets and then submit affirmations for yourself - thus returning the system to being weighted by how much Ada you have - however, this would be a failure to understand the purpose of a decentralized Affirmation Graph - in a this regime, each individual person is responsible for interrogating the graph to establish a trust score for a particular wallet - but they have complete freedom on how they choose to interpret the graph - for example, you could decide to only trust wallets that have been affirmed by a specific person (perhaps yourself, or a person you know who has affirmed a lot of people and whose judgement you trust), or only trust wallets that have a minimum number of affirmations from anyone, or you could specify that at least two of your friends must have affirmed a wallet. You could even require that a centralized KYC provider has affirmed a wallet - this would allow actual KYC gating in a semi-decentralized manner - multiple KYC providers might exist, and you might choose to give a higher trust rating to some than others, perhaps depending on how thorough their ID verification process is. Other providers might exist which offer affirmations in return for proving you own a unique Facebook or Google account. From cd756a907b8a3a1ae93327932a17e9c095214d1e Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sun, 10 Nov 2024 01:45:42 +0000 Subject: [PATCH 08/17] More formatting tweaks for Affirmation --- CIP-AFFIRM/README.md | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/CIP-AFFIRM/README.md b/CIP-AFFIRM/README.md index b227b271bf..4a6fe46489 100644 --- a/CIP-AFFIRM/README.md +++ b/CIP-AFFIRM/README.md @@ -35,27 +35,28 @@ To that end, a smart contract conforming to this specification has been defined [v1 of the affirmation contract](affirmation.ak) Definitions: -**target** - the recipient of the affirmation -**source** - the creator of the affirmation (the person or entity who is vouching for them) -**target hash** - if the **target** is a normal wallet, this should be their stake key hash. If the **target** is a script, this should be the script hash -**source hash** - if the **source** is a normal wallet, this should be their stake key hash. If the **source** is a script, this should be the script hash -**affirmation contract** - any smart contract which conforms to this specification (details below) -**contract hash** - the hash of the **affirmation contract** -**affirmation address** - An address where the spending part is **contract hash** and the delegation part is **target hash** +==target== - the recipient of the affirmation +==source== - the creator of the affirmation (the person or entity who is vouching for them) +==target hash== - if the ==target== is a normal wallet, this should be their stake key hash. If the ==target== is a script, this should be the script hash +==source hash== - if the ==source== is a normal wallet, this should be their stake key hash. If the ==source== is a script, this should be the script hash +==affirmation contract== - any smart contract which conforms to this specification (details below) +==contract hash== - the hash of the ==affirmation contract== +==affirmation address== - An address where the spending part is ==contract hash== and the delegation part is ==target hash== -An affirmation consists of a UTxO at the **affirmation address** with an inline datum containing the **source hash**. To be valid, this UTxO must contain one token minted by the **affirmation contract**, and the **affirmation contract** itself must be valid as defined below: +An affirmation consists of a UTxO at the ==affirmation address== with an inline datum containing the ==source hash==. To be valid, this UTxO must contain one token minted by the ==affirmation contract==, and the ==affirmation contract== itself must be valid as defined below: -A valid **affirmation contract** _MUST_ allow minting exactly one token at a time. In order to mint: - - it _MUST_ ensure that it receives a signature matching the **source hash** or is otherwise authorized by **source**, - - it _MUST_ ensure that the output containing the newly minted token contains an inline datum with a matching **source hash** and - - it _MUST_ ensure that this output it sent to an address where the spending part is equal to the **contract hash**. -In order to enable revokation, the contract should allow spending. When spending, the contract: - - _MUST_ ensure that it receives a signature matching the **source hash** in the datum, or is otherwise authorized by **source** and - - _MUST_ ensure that exactly one token matching the **affirmation contract**'s policy ID is burned. +A valid ==affirmation contract== _MUST_ allow minting exactly one token at a time. In order to mint: + - it _MUST_ ensure that it receives a signature matching the ==source hash== or is otherwise authorized by ==source==, + - it _MUST_ ensure that the output containing the newly minted token contains an inline datum with a matching ==source hash== and + - it _MUST_ ensure that this output it sent to an address where the spending part is equal to the ==contract hash==. -A generic **affirmation contract** has been provided which meets these requirements - you should use that unless you have specific requirements which are not met by that script. +In order to enable revokation, the contract should allow spending. When spending, the contract: + - _MUST_ ensure that it receives a signature matching the ==source hash== in the datum, or is otherwise authorized by ==source== and + - _MUST_ ensure that exactly one token matching the ==affirmation contract=='s policy ID is burned. -It should be noted that if you do write your own custom **affirmation contract**, your affirmations will not automatically be picked up by the [affirmation graph indexer](https://github.com/kieransimkin/affirmation-graph-index) - this is because the indexer maintains a list of known valid affirmation contracts. If you wish to add your contract to the list you should submit a pull request to the indexer repository in which you must prove that your contract meets the requirements detailed above - only then will your affirmations be included in the global Affirmation Graph. If in doubt, simply use the generic affirmation contract that has been provided as part of this CIP unless you have a good reason not to. +A generic ==affirmation contract== has been provided which meets these requirements - you should use that unless you have specific requirements which are not met by that script. + +It should be noted that if you do write your own custom ==affirmation contract==, your affirmations will not automatically be picked up by the [affirmation graph indexer](https://github.com/kieransimkin/affirmation-graph-index) - this is because the indexer maintains a list of known valid affirmation contracts. If you wish to add your contract to the list you should submit a pull request to the indexer repository in which you must prove that your contract meets the requirements detailed above - only then will your affirmations be included in the global Affirmation Graph. If in doubt, simply use the generic affirmation contract that has been provided as part of this CIP unless you have a good reason not to. MeshJS (the Typescript Cardano library) [has been updated](https://github.com/MeshJS/mesh/commit/fbfc8dd922ddf4c4df0d59f5fbd4f260af34da5d) so that it knows how to build these transactions, so you can do it in one easy step if you're in TS/JS. [A Python implementation](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.py) is also available. @@ -79,7 +80,7 @@ Example datum as JSON: ``` ### Versioning -This is version 1 of the affirmation graph specification - any material change in the specification will necesssarily require a new smart contract, which will result in new set of **affirmation addresses**. Consequently an affirmation contract will always target a specific version of the specification. Any new version of this specification should be separately defined in its own CIP. +This is version 1 of the affirmation graph specification - any material change in the specification will necesssarily require a new smart contract, which will result in new set of ==affirmation addresses==. Consequently an affirmation contract will always target a specific version of the specification. Any new version of this specification should be separately defined in its own CIP. ## Rationale: how does this CIP achieve its goals? It could be argued that, with enough Ada, it is always possible to create many wallets and then submit affirmations for yourself - thus returning the system to being weighted by how much Ada you have - however, this would be a failure to understand the purpose of a decentralized Affirmation Graph - in a this regime, each individual person is responsible for interrogating the graph to establish a trust score for a particular wallet - but they have complete freedom on how they choose to interpret the graph - for example, you could decide to only trust wallets that have been affirmed by a specific person (perhaps yourself, or a person you know who has affirmed a lot of people and whose judgement you trust), or only trust wallets that have a minimum number of affirmations from anyone, or you could specify that at least two of your friends must have affirmed a wallet. You could even require that a centralized KYC provider has affirmed a wallet - this would allow actual KYC gating in a semi-decentralized manner - multiple KYC providers might exist, and you might choose to give a higher trust rating to some than others, perhaps depending on how thorough their ID verification process is. Other providers might exist which offer affirmations in return for proving you own a unique Facebook or Google account. From cdd5724a6c835689ef4b8a9d918c0097f881f7cb Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sun, 10 Nov 2024 01:46:52 +0000 Subject: [PATCH 09/17] Ah I guess github markdown doesn't support == highlighting, pity. --- CIP-AFFIRM/README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/CIP-AFFIRM/README.md b/CIP-AFFIRM/README.md index 4a6fe46489..96f1f4318a 100644 --- a/CIP-AFFIRM/README.md +++ b/CIP-AFFIRM/README.md @@ -35,28 +35,28 @@ To that end, a smart contract conforming to this specification has been defined [v1 of the affirmation contract](affirmation.ak) Definitions: -==target== - the recipient of the affirmation -==source== - the creator of the affirmation (the person or entity who is vouching for them) -==target hash== - if the ==target== is a normal wallet, this should be their stake key hash. If the ==target== is a script, this should be the script hash -==source hash== - if the ==source== is a normal wallet, this should be their stake key hash. If the ==source== is a script, this should be the script hash -==affirmation contract== - any smart contract which conforms to this specification (details below) -==contract hash== - the hash of the ==affirmation contract== -==affirmation address== - An address where the spending part is ==contract hash== and the delegation part is ==target hash== +**target** - the recipient of the affirmation +**source** - the creator of the affirmation (the person or entity who is vouching for them) +**target hash** - if the **target** is a normal wallet, this should be their stake key hash. If the **target** is a script, this should be the script hash +**source hash** - if the **source** is a normal wallet, this should be their stake key hash. If the **source** is a script, this should be the script hash +**affirmation contract** - any smart contract which conforms to this specification (details below) +**contract hash** - the hash of the **affirmation contract** +**affirmation address** - An address where the spending part is **contract hash** and the delegation part is **target hash** -An affirmation consists of a UTxO at the ==affirmation address== with an inline datum containing the ==source hash==. To be valid, this UTxO must contain one token minted by the ==affirmation contract==, and the ==affirmation contract== itself must be valid as defined below: +An affirmation consists of a UTxO at the **affirmation address** with an inline datum containing the **source hash**. To be valid, this UTxO must contain one token minted by the **affirmation contract**, and the **affirmation contract** itself must be valid as defined below: -A valid ==affirmation contract== _MUST_ allow minting exactly one token at a time. In order to mint: - - it _MUST_ ensure that it receives a signature matching the ==source hash== or is otherwise authorized by ==source==, - - it _MUST_ ensure that the output containing the newly minted token contains an inline datum with a matching ==source hash== and - - it _MUST_ ensure that this output it sent to an address where the spending part is equal to the ==contract hash==. +A valid **affirmation contract** _MUST_ allow minting exactly one token at a time. In order to mint: + - it _MUST_ ensure that it receives a signature matching the **source hash** or is otherwise authorized by **source**, + - it _MUST_ ensure that the output containing the newly minted token contains an inline datum with a matching **source hash** and + - it _MUST_ ensure that this output it sent to an address where the spending part is equal to the **contract hash**. In order to enable revokation, the contract should allow spending. When spending, the contract: - - _MUST_ ensure that it receives a signature matching the ==source hash== in the datum, or is otherwise authorized by ==source== and - - _MUST_ ensure that exactly one token matching the ==affirmation contract=='s policy ID is burned. + - _MUST_ ensure that it receives a signature matching the **source hash** in the datum, or is otherwise authorized by **source** and + - _MUST_ ensure that exactly one token matching the **affirmation contract**'s policy ID is burned. -A generic ==affirmation contract== has been provided which meets these requirements - you should use that unless you have specific requirements which are not met by that script. +A generic **affirmation contract** has been provided which meets these requirements - you should use that unless you have specific requirements which are not met by that script. -It should be noted that if you do write your own custom ==affirmation contract==, your affirmations will not automatically be picked up by the [affirmation graph indexer](https://github.com/kieransimkin/affirmation-graph-index) - this is because the indexer maintains a list of known valid affirmation contracts. If you wish to add your contract to the list you should submit a pull request to the indexer repository in which you must prove that your contract meets the requirements detailed above - only then will your affirmations be included in the global Affirmation Graph. If in doubt, simply use the generic affirmation contract that has been provided as part of this CIP unless you have a good reason not to. +It should be noted that if you do write your own custom **affirmation contract**, your affirmations will not automatically be picked up by the [affirmation graph indexer](https://github.com/kieransimkin/affirmation-graph-index) - this is because the indexer maintains a list of known valid affirmation contracts. If you wish to add your contract to the list you should submit a pull request to the indexer repository in which you must prove that your contract meets the requirements detailed above - only then will your affirmations be included in the global Affirmation Graph. If in doubt, simply use the generic affirmation contract that has been provided as part of this CIP unless you have a good reason not to. MeshJS (the Typescript Cardano library) [has been updated](https://github.com/MeshJS/mesh/commit/fbfc8dd922ddf4c4df0d59f5fbd4f260af34da5d) so that it knows how to build these transactions, so you can do it in one easy step if you're in TS/JS. [A Python implementation](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.py) is also available. @@ -80,7 +80,7 @@ Example datum as JSON: ``` ### Versioning -This is version 1 of the affirmation graph specification - any material change in the specification will necesssarily require a new smart contract, which will result in new set of ==affirmation addresses==. Consequently an affirmation contract will always target a specific version of the specification. Any new version of this specification should be separately defined in its own CIP. +This is version 1 of the affirmation graph specification - any material change in the specification will necesssarily require a new smart contract, which will result in new set of **affirmation addresses**. Consequently an affirmation contract will always target a specific version of the specification. Any new version of this specification should be separately defined in its own CIP. ## Rationale: how does this CIP achieve its goals? It could be argued that, with enough Ada, it is always possible to create many wallets and then submit affirmations for yourself - thus returning the system to being weighted by how much Ada you have - however, this would be a failure to understand the purpose of a decentralized Affirmation Graph - in a this regime, each individual person is responsible for interrogating the graph to establish a trust score for a particular wallet - but they have complete freedom on how they choose to interpret the graph - for example, you could decide to only trust wallets that have been affirmed by a specific person (perhaps yourself, or a person you know who has affirmed a lot of people and whose judgement you trust), or only trust wallets that have a minimum number of affirmations from anyone, or you could specify that at least two of your friends must have affirmed a wallet. You could even require that a centralized KYC provider has affirmed a wallet - this would allow actual KYC gating in a semi-decentralized manner - multiple KYC providers might exist, and you might choose to give a higher trust rating to some than others, perhaps depending on how thorough their ID verification process is. Other providers might exist which offer affirmations in return for proving you own a unique Facebook or Google account. From 7022ceb8091f7347dad1e78f28c9bb7534617445 Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sun, 10 Nov 2024 04:27:31 +0000 Subject: [PATCH 10/17] Add an example image and remove the affirmation contract to its own repo --- CIP-AFFIRM/README.md | 42 +++++++++--------- CIP-AFFIRM/affirmation.ak | 89 --------------------------------------- CIP-AFFIRM/graph.svg | 1 + CIP-AFFIRM/plutus.json | 57 ------------------------- 4 files changed, 23 insertions(+), 166 deletions(-) delete mode 100644 CIP-AFFIRM/affirmation.ak create mode 100644 CIP-AFFIRM/graph.svg delete mode 100644 CIP-AFFIRM/plutus.json diff --git a/CIP-AFFIRM/README.md b/CIP-AFFIRM/README.md index 96f1f4318a..a0dbecf245 100644 --- a/CIP-AFFIRM/README.md +++ b/CIP-AFFIRM/README.md @@ -17,6 +17,8 @@ License: CC-BY-4.0 We need a truly decentralized alternative to KYC for when we need to establish the authenticity of a wallet or make some judgement about its trustworthiness in a systematic and repeatable manner. This CIP defines a mechanism whereby any member of the community can publicly vouch for the authenticity of a wallet by submitting an "affirmation" transaction, it also provides a mechanism to revoke such an affirmation, if, for example a wallet becomes compromised, or its owner turns out to be a charlatan. It is consequently possible to observe the current UTxO set and draw an "Affirmation Graph", a multidigraph representing the trust relationships between wallets - we can then use an algorithm to assign trust rankings and decide whether or not to trust an unknown wallet. +![Affirmation Graph example](graph.svg) + ## Motivation: why is this CIP necessary? When transacting with an unknown person, currently if we want to make sure we're not dealing with a bot or a grifter, we have to perform our own detective work - examining their current token holdings and transaction history, then we make some informed guess about what we're dealing with. This is both laborious and inconsistent. This CIP aims to provide a better alternative which is repeatable and automatable, this could drastically reduce the risk of fraud and accidental loss of funds. @@ -32,31 +34,31 @@ We are aiming to create a scheme which is generic and becomes the accepted stand To that end, a smart contract conforming to this specification has been defined which attempts to be the most simple and generic possible. No fee is required (aside from the inherent blockchain fees), the smart contract contains nothing specific to the author's websites or implementation. It is designed so that it can be integrated into any blockchain explorer, wallet or dApp. It is expected that the majority will use this generic smart contract, but it's also possible to define your own smart contract that is compliant with this CIP - it must meet the specific requirements detailed below. ## Specification -[v1 of the affirmation contract](affirmation.ak) +[v1 of the affirmation contract](https://github.com/kieransimkin/affirmation-graph/blob/main/validators/affirmation.ak) Definitions: -**target** - the recipient of the affirmation -**source** - the creator of the affirmation (the person or entity who is vouching for them) -**target hash** - if the **target** is a normal wallet, this should be their stake key hash. If the **target** is a script, this should be the script hash -**source hash** - if the **source** is a normal wallet, this should be their stake key hash. If the **source** is a script, this should be the script hash -**affirmation contract** - any smart contract which conforms to this specification (details below) -**contract hash** - the hash of the **affirmation contract** -**affirmation address** - An address where the spending part is **contract hash** and the delegation part is **target hash** +`target` - the recipient of the affirmation +`source` - the creator of the affirmation (the person or entity who is vouching for them) +`target hash` - if the `target` is a normal wallet, this should be their stake key hash. If the `target` is a script, this should be the script hash +`source hash` - if the `source` is a normal wallet, this should be their stake key hash. If the `source` is a script, this should be the script hash +`affirmation contract` - any smart contract which conforms to this specification (details below) +`contract hash` - the hash of the `affirmation contract` +`affirmation address` - An address where the spending part is `contract hash` and the delegation part is `target hash` -An affirmation consists of a UTxO at the **affirmation address** with an inline datum containing the **source hash**. To be valid, this UTxO must contain one token minted by the **affirmation contract**, and the **affirmation contract** itself must be valid as defined below: +An affirmation consists of a UTxO at the `affirmation address` with an inline datum containing the `source hash`. To be valid, this UTxO must contain one token minted by the `affirmation contract`, and the `affirmation contract` itself must be valid as defined below: -A valid **affirmation contract** _MUST_ allow minting exactly one token at a time. In order to mint: - - it _MUST_ ensure that it receives a signature matching the **source hash** or is otherwise authorized by **source**, - - it _MUST_ ensure that the output containing the newly minted token contains an inline datum with a matching **source hash** and - - it _MUST_ ensure that this output it sent to an address where the spending part is equal to the **contract hash**. +A valid `affirmation contract` _MUST_ allow minting exactly one token at a time. In order to mint: + - it _MUST_ ensure that it receives a signature matching the `source hash` or is otherwise authorized by `source`, + - it _MUST_ ensure that the output containing the newly minted token contains an inline datum with a matching `source hash` and + - it _MUST_ ensure that this output it sent to an address where the spending part is equal to the `contract hash`. In order to enable revokation, the contract should allow spending. When spending, the contract: - - _MUST_ ensure that it receives a signature matching the **source hash** in the datum, or is otherwise authorized by **source** and - - _MUST_ ensure that exactly one token matching the **affirmation contract**'s policy ID is burned. + - _MUST_ ensure that it receives a signature matching the `source hash` in the datum, or is otherwise authorized by `source` and + - _MUST_ ensure that exactly one token matching the `affirmation contract`'s policy ID is burned. -A generic **affirmation contract** has been provided which meets these requirements - you should use that unless you have specific requirements which are not met by that script. +A generic `affirmation contract` has been provided which meets these requirements - you should use that unless you have specific requirements which are not met by that script. -It should be noted that if you do write your own custom **affirmation contract**, your affirmations will not automatically be picked up by the [affirmation graph indexer](https://github.com/kieransimkin/affirmation-graph-index) - this is because the indexer maintains a list of known valid affirmation contracts. If you wish to add your contract to the list you should submit a pull request to the indexer repository in which you must prove that your contract meets the requirements detailed above - only then will your affirmations be included in the global Affirmation Graph. If in doubt, simply use the generic affirmation contract that has been provided as part of this CIP unless you have a good reason not to. +It should be noted that if you do write your own custom `affirmation contract`, your affirmations will not automatically be picked up by the [affirmation graph indexer](https://github.com/kieransimkin/affirmation-graph-index) - this is because the indexer maintains a list of known valid affirmation contracts. If you wish to add your contract to the list you should submit a pull request to the indexer repository in which you must prove that your contract meets the requirements detailed above - only then will your affirmations be included in the global Affirmation Graph. If in doubt, simply use the generic affirmation contract that has been provided as part of this CIP unless you have a good reason not to. MeshJS (the Typescript Cardano library) [has been updated](https://github.com/MeshJS/mesh/commit/fbfc8dd922ddf4c4df0d59f5fbd4f260af34da5d) so that it knows how to build these transactions, so you can do it in one easy step if you're in TS/JS. [A Python implementation](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.py) is also available. @@ -80,7 +82,7 @@ Example datum as JSON: ``` ### Versioning -This is version 1 of the affirmation graph specification - any material change in the specification will necesssarily require a new smart contract, which will result in new set of **affirmation addresses**. Consequently an affirmation contract will always target a specific version of the specification. Any new version of this specification should be separately defined in its own CIP. +This is version 1 of the affirmation graph specification - any material change in the specification will necesssarily require a new smart contract, which will result in new set of `affirmation addresses`. Consequently an affirmation contract will always target a specific version of the specification. Any new version of this specification should be separately defined in its own CIP. ## Rationale: how does this CIP achieve its goals? It could be argued that, with enough Ada, it is always possible to create many wallets and then submit affirmations for yourself - thus returning the system to being weighted by how much Ada you have - however, this would be a failure to understand the purpose of a decentralized Affirmation Graph - in a this regime, each individual person is responsible for interrogating the graph to establish a trust score for a particular wallet - but they have complete freedom on how they choose to interpret the graph - for example, you could decide to only trust wallets that have been affirmed by a specific person (perhaps yourself, or a person you know who has affirmed a lot of people and whose judgement you trust), or only trust wallets that have a minimum number of affirmations from anyone, or you could specify that at least two of your friends must have affirmed a wallet. You could even require that a centralized KYC provider has affirmed a wallet - this would allow actual KYC gating in a semi-decentralized manner - multiple KYC providers might exist, and you might choose to give a higher trust rating to some than others, perhaps depending on how thorough their ID verification process is. Other providers might exist which offer affirmations in return for proving you own a unique Facebook or Google account. @@ -89,7 +91,7 @@ It is expected that there could be a flood of services offering affirmations in I would also suggest that affirmations should be given in return for certain "good citizen" behaviours - for example, affirmations could be given to Catalyst participants upon successful completion of their project milestones. Affirmations could also be given in return for participation in voting events, or in return for helping moderate Catalyst proposals. SPOs could receive affirmations in return for upgrading to the latest node version - any behaviour which we wish to incentivise could be rewarded with affirmations - this provides a great way to incentivise good behaviour, whilst also allowing us to judge wallets based on their behaviour. -The algorithms for interpreting the graph are expectied to become numerous and varied - some examples will be provided as part of the Affirmation Graph toolchain, and users will be free and encouraged to build their own and contribute them back to the library. These algorithms will function by assigning a trust score to a wallet, based on a set of weighted judgement criteria - different algorithms will assign different weights to affirmations depending on where they came from. For example, an algorithm that requires KYC verification would assign positive weights to known KYC providers, and zero weights to all other affirmations. A "trust my friends" algorithm could measure each affirmer's distance from yourself on the graph, and weight affirmations from people close to you on the graph highly, with an exponential fall-off as the affirmer is an increasing number of steps away from you on the graph. +The algorithms for interpreting the graph are expected to become numerous and varied - some examples will be provided as part of the Affirmation Graph toolchain, and users will be free and encouraged to build their own and contribute them back to the library. These algorithms will function by assigning a trust score to a wallet, based on a set of weighted judgement criteria - different algorithms will assign different weights to affirmations depending on where they came from. For example, an algorithm that requires KYC verification would assign positive weights to known KYC providers, and zero weights to all other affirmations. A "trust my friends" algorithm could measure each affirmer's distance from yourself on the graph, and weight affirmations from people close to you on the graph highly, with an exponential fall-off as the affirmer is an increasing number of steps away from you on the graph. Wallets could choose to display a trust score whenever they prompt you to sign a transaction - this could help users identify if they're dealing with a potential scammer, before they send them Ada. Since smart contracts can also receive affirmations, and consequently can be given a trust score, wallets might also decide to display this score every time you interact with a smart contract. @@ -110,7 +112,7 @@ We would also have the option of implementing a true meritocracy where a user's - [ ] The mainnet graph needs to have a good number of affirmations in it ### Implementation Plan -- [X] Design and test [the smart contract](affirmation.ak) along with its [transaction builders in Typescript](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.mesh.cjs) and [Python](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.py) +- [X] Design and test [the smart contract](https://github.com/kieransimkin/affirmation-graph/blob/main/validators/affirmation.ak) along with its [transaction builders in Typescript](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.mesh.cjs) and [Python](https://github.com/kieransimkin/affirmation-graph/blob/main/examples/affirm.py) - [ ] Get feedback on the smart contract with a view to permanently setting it in stone - [ ] A React control to enable blockchain explorers and dApps to easily add an "Affirm this wallet" button. - [ ] Implement "Affirm this wallet" into [Cardano Looking Glass](https://clg.wtf/) diff --git a/CIP-AFFIRM/affirmation.ak b/CIP-AFFIRM/affirmation.ak deleted file mode 100644 index 92b0dc2fe1..0000000000 --- a/CIP-AFFIRM/affirmation.ak +++ /dev/null @@ -1,89 +0,0 @@ -use aiken/collection/list.{filter, find, has} -use aiken/primitive/bytearray.{length} -use cardano/address.{Address, Script} -use cardano/assets.{PolicyId, quantity_of} -use cardano/transaction.{ - InlineDatum, Input, Output, OutputReference, Transaction, -} - -pub type AffirmationDatum { - owner: ByteArray, -} - -pub type RichAffirmationDatum { - owner: ByteArray, - class: Int, - payload: ByteArray, -} - -validator v1 { - mint(_redeemer: Data, own_policy: PolicyId, tx: Transaction) { - let Transaction { extra_signatories, outputs, mint, .. } = tx - expect [mint_triplet] = mint |> assets.flatten - let (mint_policy, mint_name, mint_quantity) = mint_triplet - expect mint_policy == own_policy - if mint_quantity == 1 { - expect [Output { datum: InlineDatum(output_datum), .. }] = - filter( - outputs, - fn(output) { output.address.payment_credential == Script(own_policy) }, - ) - if output_datum is AffirmationDatum { - let check_datum = output_datum - expect has(extra_signatories, check_datum.owner) == True - } else if output_datum is RichAffirmationDatum { - let check_datum: RichAffirmationDatum = output_datum - expect has(extra_signatories, check_datum.owner) == True - } else { - fail - } - } else { - expect has(extra_signatories, mint_name) == True - } - - when mint_quantity is { - 1 -> True - -1 -> True - _ -> False - } - } - - spend( - datum: Option, - _redeemer: Data, - own_ref: OutputReference, - tx: Transaction, - ) { - let Transaction { extra_signatories, inputs, mint, .. } = tx - expect [mint_triplet] = mint |> assets.flatten - - let (mint_policy, mint_name, mint_quantity) = mint_triplet - expect mint_quantity == -1 - expect Some(datum) = datum - expect Some(own_input) = - find(inputs, fn(input) { input.output_reference == own_ref }) - expect own_input.output.address.payment_credential == Script(mint_policy) - - if datum is AffirmationDatum { - let AffirmationDatum { owner } = datum - expect owner == mint_name - - expect quantity_of(own_input.output.value, mint_policy, owner) == 1 - expect has(extra_signatories, owner) == True - } else if datum is RichAffirmationDatum { - let RichAffirmationDatum { owner, class, payload } = datum - expect owner == mint_name - expect class > -1 - expect length(payload) > 0 - expect quantity_of(own_input.output.value, mint_policy, owner) == 1 - expect has(extra_signatories, owner) == True - } else { - fail - } - True - } - - else(_) { - fail - } -} diff --git a/CIP-AFFIRM/graph.svg b/CIP-AFFIRM/graph.svg new file mode 100644 index 0000000000..1292b4456f --- /dev/null +++ b/CIP-AFFIRM/graph.svg @@ -0,0 +1 @@ +Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)AFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMS Alfie Betty Charlie Earl Doris Freya \ No newline at end of file diff --git a/CIP-AFFIRM/plutus.json b/CIP-AFFIRM/plutus.json deleted file mode 100644 index 1d43a70261..0000000000 --- a/CIP-AFFIRM/plutus.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "preamble": { - "title": "kieransimkin/affirmation-graph", - "description": "Aiken contracts for project 'affirmation-graph'", - "version": "1.0.0", - "plutusVersion": "v3", - "compiler": { - "name": "Aiken", - "version": "v1.1.4+79d0e45" - }, - "license": "Apache-2.0" - }, - "validators": [ - { - "title": "affirmation.v1.mint", - "redeemer": { - "title": "_redeemer", - "schema": { - "$ref": "#/definitions/Data" - } - }, - "compiledCode": "59060201010032323232323232322533300232323232323232323232323253233300f30070081323232323232325333019301c002132323253330193371e6eb8c0780100284c94ccc068c0300085288a99980d19b87480040085288a505333019300b00113232533301e3021002132533301c3370e9002180e9baa00113232533333302500213330150021533301e533301e3301400b375c602460406ea8008528899980f2514a0944526160010010010010011533333302400113330120011533301d533301d3301300a375c6022603e6ea8004528899980ea514a09445261616161616163021301e37540022c604060426042603a6ea800458c07c004c8cc004004024894ccc07800452f5c026464a66603a66ebcc044c07cdd51808980f9baa0023374a9001198109ba900e4bd7009981080119802002000899802002000981100118100008a99980ca99980c998078030010a5113330194a2941288a4c2c2c6eb4c074c078008dd7180e000980e0008b1bac301a0013007375660320046eb0c060c064c064c064c064004c060c060008dd6180b000980b180b18091baa00d375c602860226ea802454ccc03cc0040204c8c8c8c8c8c8c8c8c94ccc06cc0780084c8c8c94ccc06ccdc39bad302030210024800454ccc06cc04cc070dd50050991919299980f180b180f9baa0011323253330203375e602860446ea8c050c088dd5180098111baa0023374a9001198121ba90084bd7009925132325333333029007133301900713253330233371e0020122a666046602a6660066eacc010c094dd5180218129baa00500b0011533302353330233301900e00114a22666046945282511498585858dd7181398121baa0070010010010010011533333302800613330160061323232323253330263371e0080182a66604c66e212001002153330263371090001b8d0011533302630183330063756600e60506ea8c01cc0a0dd50040070020a99981329998131980e0088020a5113330264a2941288a4c2c2c2c2c2c6eb8c0a8c0ac008dd6981480098148011bae30270013023375400c2c2c2c2c2c44464a666048602c604a6ea8004520001375a6052604c6ea8004c94ccc090c058c094dd50008a60103d87a80001323300100137566054604e6ea8008894ccc0a4004530103d87a8000132323232533302a337220100042a66605466e3c0200084c038cc0b8dd4000a5eb80530103d87a8000133006006003375a60560066eb8c0a4008c0b4008c0ac004c8cc004004010894ccc0a00045300103d87a80001323232325333029337220100042a66605266e3c0200084c034cc0b4dd3000a5eb80530103d87a8000133006006003375660540066eb8c0a0008c0b0008c0a8004588c094c098004c08cc080dd50008b19198008008059129998110008a60103d87a80001323253330213375e602a60466ea80080444c014cc0940092f5c0266008008002604c00460480026e9520003020301d37540142c2c6eb8c07c004c07c008dd7180e8008b1bac301c0013009375660360046eb0c068c06cc06cc06cc06c004c068c068c068c068008dd6180c000980a1baa00f301630170023015001301137540122c6e1d20022323300100100222533301300114bd70099199911191980080080191299980c80088018991980d9ba73301b375200c66036603000266036603200297ae033003003301d002301b001375c60240026eacc04c004cc00c00cc05c008c0540048c0480048894ccc038c018c03cdd50018992999809000801099299999980b80080180180180189919299980a800802899299999980d00080300300309919299980c000804099299999980e800804804804804899299980d180e8018a8058051bae001301a001301a003375a00200c602e002602e0066eb8004c050004c040dd50018009119198008008019129998088008a50132533300f3371e6eb8c050008010528899801801800980a0009112999806180218069baa003132533301000100213253333330150010030030030031325333012301500315005004375c0026024002601c6ea800c004dc3a400060106ea8004c02cc030008c028004c028008c020004c010dd50008a4c26cacae6955ceaab9e5573eae815d0aba25749", - "hash": "780b8dcab8ec263281b810e26c4e5ef5e38a057c297c686661c75d4d" - }, - { - "title": "affirmation.v1.spend", - "datum": { - "title": "datum", - "schema": { - "$ref": "#/definitions/Data" - } - }, - "redeemer": { - "title": "_redeemer", - "schema": { - "$ref": "#/definitions/Data" - } - }, - "compiledCode": "59060201010032323232323232322533300232323232323232323232323253233300f30070081323232323232325333019301c002132323253330193371e6eb8c0780100284c94ccc068c0300085288a99980d19b87480040085288a505333019300b00113232533301e3021002132533301c3370e9002180e9baa00113232533333302500213330150021533301e533301e3301400b375c602460406ea8008528899980f2514a0944526160010010010010011533333302400113330120011533301d533301d3301300a375c6022603e6ea8004528899980ea514a09445261616161616163021301e37540022c604060426042603a6ea800458c07c004c8cc004004024894ccc07800452f5c026464a66603a66ebcc044c07cdd51808980f9baa0023374a9001198109ba900e4bd7009981080119802002000899802002000981100118100008a99980ca99980c998078030010a5113330194a2941288a4c2c2c6eb4c074c078008dd7180e000980e0008b1bac301a0013007375660320046eb0c060c064c064c064c064004c060c060008dd6180b000980b180b18091baa00d375c602860226ea802454ccc03cc0040204c8c8c8c8c8c8c8c8c94ccc06cc0780084c8c8c94ccc06ccdc39bad302030210024800454ccc06cc04cc070dd50050991919299980f180b180f9baa0011323253330203375e602860446ea8c050c088dd5180098111baa0023374a9001198121ba90084bd7009925132325333333029007133301900713253330233371e0020122a666046602a6660066eacc010c094dd5180218129baa00500b0011533302353330233301900e00114a22666046945282511498585858dd7181398121baa0070010010010010011533333302800613330160061323232323253330263371e0080182a66604c66e212001002153330263371090001b8d0011533302630183330063756600e60506ea8c01cc0a0dd50040070020a99981329998131980e0088020a5113330264a2941288a4c2c2c2c2c2c6eb8c0a8c0ac008dd6981480098148011bae30270013023375400c2c2c2c2c2c44464a666048602c604a6ea8004520001375a6052604c6ea8004c94ccc090c058c094dd50008a60103d87a80001323300100137566054604e6ea8008894ccc0a4004530103d87a8000132323232533302a337220100042a66605466e3c0200084c038cc0b8dd4000a5eb80530103d87a8000133006006003375a60560066eb8c0a4008c0b4008c0ac004c8cc004004010894ccc0a00045300103d87a80001323232325333029337220100042a66605266e3c0200084c034cc0b4dd3000a5eb80530103d87a8000133006006003375660540066eb8c0a0008c0b0008c0a8004588c094c098004c08cc080dd50008b19198008008059129998110008a60103d87a80001323253330213375e602a60466ea80080444c014cc0940092f5c0266008008002604c00460480026e9520003020301d37540142c2c6eb8c07c004c07c008dd7180e8008b1bac301c0013009375660360046eb0c068c06cc06cc06cc06c004c068c068c068c068008dd6180c000980a1baa00f301630170023015001301137540122c6e1d20022323300100100222533301300114bd70099199911191980080080191299980c80088018991980d9ba73301b375200c66036603000266036603200297ae033003003301d002301b001375c60240026eacc04c004cc00c00cc05c008c0540048c0480048894ccc038c018c03cdd50018992999809000801099299999980b80080180180180189919299980a800802899299999980d00080300300309919299980c000804099299999980e800804804804804899299980d180e8018a8058051bae001301a001301a003375a00200c602e002602e0066eb8004c050004c040dd50018009119198008008019129998088008a50132533300f3371e6eb8c050008010528899801801800980a0009112999806180218069baa003132533301000100213253333330150010030030030031325333012301500315005004375c0026024002601c6ea800c004dc3a400060106ea8004c02cc030008c028004c028008c020004c010dd50008a4c26cacae6955ceaab9e5573eae815d0aba25749", - "hash": "780b8dcab8ec263281b810e26c4e5ef5e38a057c297c686661c75d4d" - }, - { - "title": "affirmation.v1.else", - "redeemer": { - "schema": {} - }, - "compiledCode": "59060201010032323232323232322533300232323232323232323232323253233300f30070081323232323232325333019301c002132323253330193371e6eb8c0780100284c94ccc068c0300085288a99980d19b87480040085288a505333019300b00113232533301e3021002132533301c3370e9002180e9baa00113232533333302500213330150021533301e533301e3301400b375c602460406ea8008528899980f2514a0944526160010010010010011533333302400113330120011533301d533301d3301300a375c6022603e6ea8004528899980ea514a09445261616161616163021301e37540022c604060426042603a6ea800458c07c004c8cc004004024894ccc07800452f5c026464a66603a66ebcc044c07cdd51808980f9baa0023374a9001198109ba900e4bd7009981080119802002000899802002000981100118100008a99980ca99980c998078030010a5113330194a2941288a4c2c2c6eb4c074c078008dd7180e000980e0008b1bac301a0013007375660320046eb0c060c064c064c064c064004c060c060008dd6180b000980b180b18091baa00d375c602860226ea802454ccc03cc0040204c8c8c8c8c8c8c8c8c94ccc06cc0780084c8c8c94ccc06ccdc39bad302030210024800454ccc06cc04cc070dd50050991919299980f180b180f9baa0011323253330203375e602860446ea8c050c088dd5180098111baa0023374a9001198121ba90084bd7009925132325333333029007133301900713253330233371e0020122a666046602a6660066eacc010c094dd5180218129baa00500b0011533302353330233301900e00114a22666046945282511498585858dd7181398121baa0070010010010010011533333302800613330160061323232323253330263371e0080182a66604c66e212001002153330263371090001b8d0011533302630183330063756600e60506ea8c01cc0a0dd50040070020a99981329998131980e0088020a5113330264a2941288a4c2c2c2c2c2c6eb8c0a8c0ac008dd6981480098148011bae30270013023375400c2c2c2c2c2c44464a666048602c604a6ea8004520001375a6052604c6ea8004c94ccc090c058c094dd50008a60103d87a80001323300100137566054604e6ea8008894ccc0a4004530103d87a8000132323232533302a337220100042a66605466e3c0200084c038cc0b8dd4000a5eb80530103d87a8000133006006003375a60560066eb8c0a4008c0b4008c0ac004c8cc004004010894ccc0a00045300103d87a80001323232325333029337220100042a66605266e3c0200084c034cc0b4dd3000a5eb80530103d87a8000133006006003375660540066eb8c0a0008c0b0008c0a8004588c094c098004c08cc080dd50008b19198008008059129998110008a60103d87a80001323253330213375e602a60466ea80080444c014cc0940092f5c0266008008002604c00460480026e9520003020301d37540142c2c6eb8c07c004c07c008dd7180e8008b1bac301c0013009375660360046eb0c068c06cc06cc06cc06c004c068c068c068c068008dd6180c000980a1baa00f301630170023015001301137540122c6e1d20022323300100100222533301300114bd70099199911191980080080191299980c80088018991980d9ba73301b375200c66036603000266036603200297ae033003003301d002301b001375c60240026eacc04c004cc00c00cc05c008c0540048c0480048894ccc038c018c03cdd50018992999809000801099299999980b80080180180180189919299980a800802899299999980d00080300300309919299980c000804099299999980e800804804804804899299980d180e8018a8058051bae001301a001301a003375a00200c602e002602e0066eb8004c050004c040dd50018009119198008008019129998088008a50132533300f3371e6eb8c050008010528899801801800980a0009112999806180218069baa003132533301000100213253333330150010030030030031325333012301500315005004375c0026024002601c6ea800c004dc3a400060106ea8004c02cc030008c028004c028008c020004c010dd50008a4c26cacae6955ceaab9e5573eae815d0aba25749", - "hash": "780b8dcab8ec263281b810e26c4e5ef5e38a057c297c686661c75d4d" - } - ], - "definitions": { - "Data": { - "title": "Data", - "description": "Any Plutus data." - } - } -} \ No newline at end of file From de4b9a3863a70148e36c5832dd190dcabb9dd8e9 Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sun, 10 Nov 2024 04:29:50 +0000 Subject: [PATCH 11/17] Update graph.svg --- CIP-AFFIRM/graph.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-AFFIRM/graph.svg b/CIP-AFFIRM/graph.svg index 1292b4456f..d12dcc6d0d 100644 --- a/CIP-AFFIRM/graph.svg +++ b/CIP-AFFIRM/graph.svg @@ -1 +1 @@ -Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)AFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMS Alfie Betty Charlie Earl Doris Freya \ No newline at end of file +Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)AFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMS Alfie Betty Charlie Earl Doris Freya \ No newline at end of file From 7f0f51b6999c736454ea0be970fbac46349ef906 Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sun, 10 Nov 2024 06:15:54 +0000 Subject: [PATCH 12/17] Add padding to affirmation graph example svg --- CIP-AFFIRM/README.md | 2 +- CIP-AFFIRM/graph.svg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CIP-AFFIRM/README.md b/CIP-AFFIRM/README.md index a0dbecf245..b3523dfaaf 100644 --- a/CIP-AFFIRM/README.md +++ b/CIP-AFFIRM/README.md @@ -100,7 +100,7 @@ Well, you could describe it that way, but the biggest problem with social credit This system allows even a user who wishes to remain completely anonymous to develop a reputation and gain a trusted rating, even if they do not not wish to prove their indentity in any way - if they have an online persona, there will be people willing to affirm them based on that persona alone. Plus, they may accrue affirmations by displaying good behaviour if such behaviour is rewarded by affirmation as suggested. -This CIP is fundamentally about linking the social graph with the blockchain, so that you can have the same level of confidence that you're dealing with a real human-being as you do on Facebook or X. While this is never 100% certain, I would argue that most people can tell the difference between a real human or a bot on social media with a high degree of accuracy - we need to acheieve a similar level of confidence in our judgements about whether or not we trust a wallet on the blockchain. Only then can we have a hope of implementing 1-person-one-vote and having any meaninful form of democractic system - and that's the end goal; to enable Cardano governance to be truly democractic by removing the biases of stake-weighted voting, and instead move to something more closely representing 1 person = 1 vote. +This CIP is fundamentally about linking the social graph with the blockchain, so that you can have the same level of confidence that you're dealing with a real human-being as you do on Facebook or X. While this is never 100% certain, I would argue that most people can tell the difference between a real human or a bot on social media with a high degree of accuracy - we need to acheieve a similar level of confidence in our judgements about whether or not we trust a wallet on the blockchain. Only then can we have a hope of implementing 1-person-one-vote and having any meaningful form of democractic system - and that's the end goal; to enable Cardano governance to be truly democractic by removing the biases of stake-weighted voting, and instead move to something more closely representing 1 person = 1 vote. We would also have the option of implementing a true meritocracy where a user's voting power is actually weighted by their trust score - so instead of 1 person = 1 vote, we'd actually give stronger weight to those with very high trust ratings - this would work particularly well in a scenario where we were rewarding good behaviour with affirmations, but there would potentially be a risk of power being centralized among a few very highly trusted individuals - for example if we rewarded Catalyst participants for meeting their milestones, we could find that regular Catalyst participants received very high trust ratings which enabled them to outvote everyone else. We'd therefore have to carefully design the weighting algorithm to avoid this - it may be simpler to stick to 1 person = 1 vote, and simply require a minimum trust score threshold in order to verify that a wallet represents a unique person. diff --git a/CIP-AFFIRM/graph.svg b/CIP-AFFIRM/graph.svg index d12dcc6d0d..d22b94fb75 100644 --- a/CIP-AFFIRM/graph.svg +++ b/CIP-AFFIRM/graph.svg @@ -1 +1 @@ -Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)AFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMS Alfie Betty Charlie Earl Doris Freya \ No newline at end of file +Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)AFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMS Alfie Betty Charlie Earl Doris Freya \ No newline at end of file From 68b3cd0d6525b45250ec92a08531d1001987d698 Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sun, 10 Nov 2024 06:20:39 +0000 Subject: [PATCH 13/17] Update graph.svg --- CIP-AFFIRM/graph.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-AFFIRM/graph.svg b/CIP-AFFIRM/graph.svg index d22b94fb75..66d2ced8f6 100644 --- a/CIP-AFFIRM/graph.svg +++ b/CIP-AFFIRM/graph.svg @@ -1 +1 @@ -Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)AFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMS Alfie Betty Charlie Earl Doris Freya \ No newline at end of file +Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)AFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMS Alfie Betty Charlie Earl Doris Freya \ No newline at end of file From ead59f6d6722b7125aaf35da5da826ce1064d30e Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sun, 10 Nov 2024 06:23:37 +0000 Subject: [PATCH 14/17] Padding graph diagram --- CIP-AFFIRM/graph.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-AFFIRM/graph.svg b/CIP-AFFIRM/graph.svg index 66d2ced8f6..c865c4dbf5 100644 --- a/CIP-AFFIRM/graph.svg +++ b/CIP-AFFIRM/graph.svg @@ -1 +1 @@ -Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)AFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMS Alfie Betty Charlie Earl Doris Freya \ No newline at end of file +Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)AFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMS Alfie Betty Charlie Earl Doris Freya \ No newline at end of file From 13773c2e9c6d399e0bc39fc395e3d30b90a2d4ad Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sun, 10 Nov 2024 06:25:00 +0000 Subject: [PATCH 15/17] Fix graph padding --- CIP-AFFIRM/graph.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-AFFIRM/graph.svg b/CIP-AFFIRM/graph.svg index c865c4dbf5..6873848b60 100644 --- a/CIP-AFFIRM/graph.svg +++ b/CIP-AFFIRM/graph.svg @@ -1 +1 @@ -Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)AFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMS Alfie Betty Charlie Earl Doris Freya \ No newline at end of file +Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)AFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMS Alfie Betty Charlie Earl Doris Freya \ No newline at end of file From 8a081bfb5805063cadb542c891a8c63db8b74dd0 Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sun, 10 Nov 2024 06:30:25 +0000 Subject: [PATCH 16/17] Update graph.svg --- CIP-AFFIRM/graph.svg | 355 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 354 insertions(+), 1 deletion(-) diff --git a/CIP-AFFIRM/graph.svg b/CIP-AFFIRM/graph.svg index 6873848b60..ecf3e19f87 100644 --- a/CIP-AFFIRM/graph.svg +++ b/CIP-AFFIRM/graph.svg @@ -1 +1,354 @@ -Neo4j Graph VisualizationCreated using Neo4j (http://www.neo4j.com/)AFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMSAFFIRMS Alfie Betty Charlie Earl Doris Freya \ No newline at end of file + + + + + Neo4j Graph Visualization + Created using Neo4j (http://www.neo4j.com/) + + + + AFFIRMS + + + + AFFIRMS + + + + AFFIRMS + + + + AFFIRMS + + + + AFFIRMS + + + + AFFIRMS + + + + AFFIRMS + + + + + + Alfie + + + + Betty + + + + Charlie + + + + Earl + + + + Doris + + + + Freya + + + + + + Neo4j Graph Visualization + + + + From a318f2ed4a28db0a9978ae07bec8ea41b2eb9a29 Mon Sep 17 00:00:00 2001 From: Kieran Simkin <382129+kieransimkin@users.noreply.github.com> Date: Sun, 10 Nov 2024 06:31:25 +0000 Subject: [PATCH 17/17] Ugh I'll get this graph looking right eventually --- CIP-AFFIRM/graph.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-AFFIRM/graph.svg b/CIP-AFFIRM/graph.svg index ecf3e19f87..c528a266db 100644 --- a/CIP-AFFIRM/graph.svg +++ b/CIP-AFFIRM/graph.svg @@ -1,6 +1,6 @@