# SIMA spec SIMA defines a set of user actions and data standards to decentralize off-chain governance data for [substrate](https://github.com/paritytech/substrate) based blockchains. In general, governane users sign their actions data with their polkadot keys, submit the signed data to spec implementers. Spec implementers will be responsible for submitting the IPFS CID of user actions data to blockchain with a `system#remark` extrinsic. SIMA is named after [Sima Qian](https://en.wikipedia.org/wiki/Sima_Qian), one of the most famous Chinese historian. ## Problem statement There are several onchain items to be governed, including onchain treasury, parameters, runtime on the polkadot/kusama blockchain. They can be adjusted by specific permissioned calls. Usually a proposer propose one or a batch of calls which will be voted by all token holders or a group of authorized members. Proposers usually start a discussion by creating a post on forums like polkassembly, subsquare before submitting the proposal on chain. They leave related context after proposals submitted. Community members can leave comments and have a discussion during the whole process of governance proposals. These forum platforms usually have public apis which can be called to get the context info, so community members can save them and paltforms can call each other to sync the data, but there are still some problems with current model. 1. We can not verify the users' data. This is a common problem in web2 environment. Maybe these platforms have no motivations to tamper with the data, but we need more verification, less trust. So we can be 100% sure data belongs the owner. 2. Users' data maybe lost with a platform's misoperation, or a platform may just stop operations. We need a way to keep the data always accessible. 3. Data should be more auditable. Currently, platforms don't save all the data modifications. User can modify the legacy leaved context, and the website will just show the context is updated, so users may not be able to see the old data which may include the proposal owner's commitments. 4. The more one signle centralized governance platform own users' data, the less possibility another platform can provide better solutions. We need a relatively decentralize data hosting solution which will not rely on single platforms or a dedicated group of people. 5. Differences of different platforms' API data format make it hard to sync and adapt all other platforms' data. All in all, we need a more verifiable, auditable, always accessible, decentralized way to host users' off-chain governance data. ## User roles Users will be classified into following 3 roles in this spec. Proposal proposer and community members will have discussions based on various governance proposals, they signed their discussion data in a pre-defined format, submit to spec implementers, and spec implementers will upload the data proof to blockchains. - Proposal proposer: this role can provide context for proposals he/she proposed. - Community member: this role need a polkadot key to participate the discussions. - Spec implementer: teams like polkassembly, subsquare, bright treasury, nova wallet maybe the potential implementers. They accept other roles signed data, host them and upload the data IPFS CID to the corresponding blockchain. ## Proposal indexer We use a json object which contains 3 fields to identify a specific onchain proposal. - type: it will be one of proposal types shown in the following types table. - proposed_height: it is the blockchain height at which the target proposal is proposed. - index: index of a proposal. - hash: hash of a proposal. `index` and `hash` are mutually exclusive. One proposal has a `index` or `hash`, depending on the proposal type. Proposal types: | type | Description | | ---- | ---- | | treasury_proposal | Treasury proposal | | treasury_tip | Treasury tip | | treasury_bounty | Treasury bounty | | treasury_child_bounty | Treasury child bounty | | council_motion | Council motion | | tech_comm_proposal | Tech. Comm. proposal | | democracy_public_proposal | Democracy public proposal | | democracy_external_proposal | Democracy external proposal | | democracy_referendum | Democracy referendum | | referenda_referendum | OpenGov referenda referendum | | fellowship_referendum | OpenGov fellowship referendum | A treasury bounty proposal example can be: ```jsonld= { "type": "treasury_bounty", "proposed_height": 4501546, "index": 0 } ``` A democracy external proposal can be: ```jsonld= { "type": "democracy_external_proposal", "proposed_height": 13626557, "hash": "0x461ffacbb29348621ae8ca7da3780946db7d729beaec5b6e3f633ab0137f36c8" } ``` A OpenGov referenda referendum can be: ```jsonld= { "type": "referenda_referendum", "proposed_height": 17019858, "index": 125 } ``` ## User actions SIMA defines several actions for users to complete an off-chain governance discussion. These actions includes: - Start a discussion - Append a discussion - Provide context - Comment - Upvote/downvote - Cancel upvote/downvote Every action will have a unique id which will be used in the signed data, shown in following table. | Action | id | indexer | | ---- | ---- | ---- | | Start a discussion | new_discussion | IPFS CID | | Append a discussion | append_discussion | IPFS CID | | Provide context | provide_context | proposal indexer | | Comment | comment | comment indexer | | Upvote | upvote | comment indexer | | Downvote | downvote | comment indexer | | Cancel upvote | cancel_upvote | comment indexer | | Cancel downvote | cancel_downvote | comment indexer | ### Start a discussion Any community member with a polkadot key can start a discussion. An example of the action data to be signed is shown as follows. ```jsonld= { "action": "new_discussion", "title": "discussion title", "content": "discussion content", "content_format": "subsquare_md", "timestamp": 1680592723149 } ``` - action: every action should has this field. It indicates the action type. - title: title of the discussion. It should not be empty, and spec implemeters should reject data with empty title. - content: content of the discussion, should be decoded by the way indicated by `content_format` field. - content_format: it indicates the format of discussion content. At the time of writting, the formats contains `subsquare_md` and `HTML`. `subsquare_md` means subsquare supported markdown. `HTML` means just [HTML](https://en.wikipedia.org/wiki/HTML). - timestamp: time of discussion created time. Spec implementers should not accept a user submit a discussion with a timestamp much earlier or later than current time. Data should be signed before submitting to spec implementers. The signed data which will be submitted is as follows. ```jsonld= { "entity": { "action": "new_discussion", "title": "discussion title", "content": "discussion content", "content_format": "subsquare_md", "timestamp": 1680592723149 }, "address": "15ifSDJD2wA7XWwDsitFCHu3wsEfkeBESSxkQg3q8sHqAF2R", "signature": "0xa8d02f1744f9ed551fc62e9f41ae2e997c86642a96cad818dca666353a8e4e22ec7c6b6369167d050b58840a12c34a06324e14163705605a388d976acee58384" } ``` - The `address` field indicates the address who signed the entity data. - The `signature` field give the signature of entity by the address. Signature should be calculated by `polkadot_key_sign(JSON.stringify(entity))`. IPFS CID of the signed data is `bafybeicx6lf2ppu7qealce55maanaefwdiej3ogms2j5yivllz2p7iujle`. A discussion can be identified by this CID. ### Append a discussion A discussion author may need to amend the content due to typos, wrong calculations, outdated numbers, etc. But amending the content directly will change the IPFS CID, so we will support append content to a discussion instead of amending the legacy content. ```jsonld= { "action": "append_discussion", "CID": "bafybeicx6lf2ppu7qealce55maanaefwdiej3ogms2j5yivllz2p7iujle", "content": "appended discussion content", "content_format": "subsquare_md", "timestamp": 1680598637950 } ``` CID field value should be the to be amended discussion data CID. Other fields keeps same meaning with those of the action 'start a discussion'. The signed data is as follows. ```jsonld= { "entity": { "action": "append_discussion", "CID": "bafybeicx6lf2ppu7qealce55maanaefwdiej3ogms2j5yivllz2p7iujle", "content": "appended discussion content", "content_format": "subsquare_md", "timestamp": 1680598637950 }, "address": "15ifSDJD2wA7XWwDsitFCHu3wsEfkeBESSxkQg3q8sHqAF2R", "signature": "0x867fc3082f5f2ba170842fa6223eb07484b124cdbadbaf7f45ff7b4198bbb308c54ed606e27824b71cba843e8115dde6301e90e4404297c09ea44c3a75c4408e" } ``` Note: - The address should be same with that of the `start a discussion` action. ### Provide context This action provide context information for a on-chain proposal. This action author should be the proposal author. An example of this action entity data is shown as follows. ```jsonld= { "action": "provide_context", "indexer": { "type": "treasury_proposal", "proposed_height": 13750133, "index": 206 }, "title": "proposal title", "content": "proposal content", "content_format": "subsquare_md", "timestamp": 1680601098763 } ``` - `indexer` field is for locating a specific on-chain proposal. It will follow the definition described on the proposal indexer section. The signed data is as follows. ```jsonld= { "entity": { "action": "provide_context", "indexer": { "type": "treasury_proposal", "proposed_height": 13750133, "index": 206 }, "title": "proposal title", "content": "proposal content", "content_format": "subsquare_md", "timestamp": 1680601098763 }, "address": "12sNU8BXivMj1xQmcd4T39ugCyHjmhir8jkPqfAw5ZDESrx4", "signature": "0x76d9a2fe92ef9dfa867df43f9e7a8c0113f18cea7869064d2e5af0f401f9e1639634c688bc3552c99b6fcd005d5f9815c10e0e0fb4ee83d86bcd82844642928f" } ``` Note: - A new valid action updating same proposal will override the content by previous actions. ### Comment The comment action leave a comment to a discussion, a proposal or another comment. An example of this action entity data is shown as follows. ```jsonld= { "action": "comment", "indexer": { "type": "discussion", "CID": "bafybeicx6lf2ppu7qealce55maanaefwdiej3ogms2j5yivllz2p7iujle" }, "content": "proposal content", "content_format": "subsquare_md", "timestamp": 1680615958881 } ``` The signed data is as follows. ```jsonld= { "entity": { "action": "comment", "indexer": { "type": "discussion", "CID": "bafybeicx6lf2ppu7qealce55maanaefwdiej3ogms2j5yivllz2p7iujle" }, "content": "proposal content", "content_format": "subsquare_md", "timestamp": 1680615958881 }, "address": "12sNU8BXivMj1xQmcd4T39ugCyHjmhir8jkPqfAw5ZDESrx4", "signature": "0x00022d4b601779164ec4df944c1171a35773d8b4df8c5087f4153485fc70036477ed3908bc989da705bc77537821f8c2f38e480bfc0d8fcea63911ba82d3e389" } ``` The above example shows a comment action entity to a discussion. The comment target can also be a proposal, a discussion comment or a proposal comment. The comments to different targets will have different indexer. Following are `indexer` examples. A discussion comment indexer: ```jsonld= { "type": "discussion", "CID": "bafybeicx6lf2ppu7qealce55maanaefwdiej3ogms2j5yivllz2p7iujle", "comment": "bafybeid7ktyoum7lzugefurchc4hxveqbohtus5lkibanxjiaodgmlqhve" } ``` A comment indexer to a onchain proposal is same with proposal indexer. ```jsonld= { "type": "treasury_proposal", "proposed_height": 13750133, "index": 206 } ``` A comment indexer to a onchain proposal's comment requires a extra `comment` field to proposal indexer. ```jsonld= { "type": "treasury_proposal", "proposed_height": 13750133, "index": 206, "comment": "bafybeid7ktyoum7lzugefurchc4hxveqbohtus5lkibanxjiaodgmlqhve" } ``` ### Upvote/downvote This action's target is same with that of the comment action, and the target maybe a discussion, a onchain proposal or a comment. An example entity is shown as follows. ```jsonld= { "action": "upvote", "indexer": { "type": "discussion", "CID": "bafybeicx6lf2ppu7qealce55maanaefwdiej3ogms2j5yivllz2p7iujle" }, "timestamp": 1680686606947 } ``` - `action` field can be `upvote` or `downvote`. - `indexer` has same meaning and format with that of the comment action. The signed data is as follows. ```jsonld= { "entity": { "action": "upvote", "indexer": { "type": "discussion", "CID": "bafybeicx6lf2ppu7qealce55maanaefwdiej3ogms2j5yivllz2p7iujle" }, "timestamp": 1680686606947 }, "address": "15ifSDJD2wA7XWwDsitFCHu3wsEfkeBESSxkQg3q8sHqAF2R", "signature": "0x4c8b57ad491decd187acf7130fcd0e2fc58397e723c4b1c7cc10bafb6fb1d143ae94a463f23158476917ebc40ae23e950aaa982c6b8e3bc27ef2dd8a74c41688" } ``` ### Cancel upvote/downvote This action's target is same with that of upvote/downvote action. An example entity is shown as follows. ```jsonld= { "action": "cancel_upvote", "indexer": { "type": "discussion", "CID": "bafybeicx6lf2ppu7qealce55maanaefwdiej3ogms2j5yivllz2p7iujle" }, "timestamp": 1681873995303 } ``` - `action` field can be `cancel_upvote` or `cancel_downvote`. - `indexer` has same meaning and format with that of the comment action. The signed data is as follows. ```jsonld= { "entity": { "action": "cancel_upvote", "indexer": { "type": "discussion", "CID": "bafybeicx6lf2ppu7qealce55maanaefwdiej3ogms2j5yivllz2p7iujle" }, "timestamp": 1681873995303 }, "address": "15ifSDJD2wA7XWwDsitFCHu3wsEfkeBESSxkQg3q8sHqAF2R", "signature": "0x8040ceac041cb0296c1cedd8ddc16f93ea8c2fe7c728eab5b3b42ec7f5b9d136ac091195ec5f72473fb1f86b28afca4a49b9993d14003528a11bf9d019469d8a" } ``` Note: - If there is no corresponding upvote/downvote for same target from same address, this action won't take any effect. ## Decentralization SIMA doesn't require a peer to peer network to decentralize users' data. It relys on the specified blockchain's decentralization and IPFS decentralization mechanism. - User data is hosted by IPFS nodes. These nodes can be hosted by spec implementers or public ones like [infura](https://infura.io/), [cloudflare](https://www.cloudflare.com/web3/), etc. The data should be finally saved to decentralized solutions like [arweave](https://arweave.org/), [crust](https://crust.network/), etc by spec implementers. - Spec implementers will submit the user data proofs to blockchain in `system#remark` extrinsics. ### Data proof submissioin There will be different spec implementers. Each of these implemeters accept users' signed action data and save them to servers at the first step. Spec implementers are responsible to do following 2 stpes work to keep the data decentralized and public accessible. 1. Upload the received users' signed actions data to one or more public IPFS nodes. Spec implementers should keep these data always accesible. They can pin them at a specified frequency, or they can submit these data to decentralized storage solutions like arweave, crust, etc. 2. Submit IPFS CIDs of these data to blockchain in a conventional way. In the 2nd step, spec implementers will submit IPFS CID of action data CID array to blockchain. An example is shown as follows. ```jsonld= [ "bafybeicx6lf2ppu7qealce55maanaefwdiej3ogms2j5yivllz2p7iujle", "bafybeid7ktyoum7lzugefurchc4hxveqbohtus5lkibanxjiaodgmlqhve" ] ``` Above is an array of CIDs of user signed action data. Its CID is `bafybeihylrppf3ufj7dbgdlfyd4vh4dlwnvqlizkjimetxiymhollsf2ka`. Spec implementer will submit this CID to blockchain with `system#remark` extrinsic. The argument should be: `0x{bytes(SIMA:1:S:{CID_of_user_signed_action_data_CID_array})}` In the above example, it should be `0x{bytes(SIMA:1:S:bafybeihylrppf3ufj7dbgdlfyd4vh4dlwnvqlizkjimetxiymhollsf2ka)}`, and its final value is `0x53494d413a313a533a6261667962656968796c727070663375666a37646267646c66796434766834646c776e76716c697a6b6a696d65747869796d686f6c6c7366326b61`. ### Data recovery Any new SIMA spec implementers can recover users' data in following steps. 1. Scan the target blockchain and filter `system#remark` extrinsics for data proof submission. 2. Extract CIDs from extrinsics. 3. Fetch users action data from public IPFS gateways. 4. Extract user data, do normalization and save to their own databases. ## Contraints 1. Every user has to own a polkadot key to sign actions data. It's not very friendly to web2 users who are used to register a account with emails, login into a website, and then do most actions without verification anymore. 2. Users have to sign every action. ## Conclusion SIMA spec defines 6 user actions which will support substrate based blockchain users to complete off-chain governance discussion processes. Every action has predefined format. Users sign the action data, submit them to spec implementers, and spec implementers will submit the data proof to with a `system#remark` extrinsic and keep the data always accessible. Though it has some contraints, we believe it's in the right direction to work in a web3 environment.