{"id":13525222,"url":"https://github.com/dfinity/threshold","last_synced_at":"2026-02-12T00:31:34.758Z","repository":{"id":152346278,"uuid":"528047509","full_name":"dfinity/threshold","owner":"dfinity","description":"Threshold voting and execution for the IC","archived":false,"fork":false,"pushed_at":"2023-07-01T17:06:03.000Z","size":77,"stargazers_count":12,"open_issues_count":5,"forks_count":2,"subscribers_count":5,"default_branch":"main","last_synced_at":"2026-01-16T08:34:50.471Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Motoko","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dfinity.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-08-23T15:15:27.000Z","updated_at":"2025-03-14T06:03:42.000Z","dependencies_parsed_at":"2024-01-13T22:49:02.518Z","dependency_job_id":"8ea72c07-e782-402e-a875-23d93383a8c8","html_url":"https://github.com/dfinity/threshold","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/dfinity/threshold","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfinity%2Fthreshold","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfinity%2Fthreshold/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfinity%2Fthreshold/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfinity%2Fthreshold/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dfinity","download_url":"https://codeload.github.com/dfinity/threshold/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfinity%2Fthreshold/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29350901,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-11T20:11:40.865Z","status":"ssl_error","status_checked_at":"2026-02-11T20:10:41.637Z","response_time":97,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T06:01:16.960Z","updated_at":"2026-02-12T00:31:34.742Z","avatar_url":"https://github.com/dfinity.png","language":"Motoko","readme":"# threshold\n\nThreshold voting and execution for the IC\n\n## Post-Beta quality\n\n_Note_: This canister can be considered production quality, a test suite is exercised in CI,\n        and **an initial security review has been performed**.\n\nTo fully declare this SW as \"ready for production\", we solicit user reports (positive and/or negative).\n\nPRs are welcome, but be prepared for an extended review period.\n\nSee also the [open issues](https://github.com/dfinity/threshold/issues) for this project.\n\n## What this canister does\n\n- one can initially set up the canister with a collection of signers or voters (which are principals)\n- one can add new proposals (by mnemonic and action, an action being the destination canister, invoked method and argument payload)\n- signers can vote to accept/reject (but can't flip the vote)\n- votes are recorded by principal and timestamp only\n- when sufficient votes for a proposal have gathered, the action gets\n  executed and the proposal retired\n- retired proposals can be pruned\n\n## Setting up the signers list\n\nWhen the `threshold` canister gets deployed (or reinstalled), the\ninitial signers list must be specified\n\n``` shell\ndfx deploy threshold --argument='(vec {principal \"'$(dfx identity get-principal)'\"; principal \"2vxsx-fae\"})'\n```\n\n_Note_: above the first principal is the `dfx` identity, so that one can vote from the command line. The second identity is the Candid GUI's, so that it can also be used.\n\nAfter the installation, changes to the signers list must be done by proposals.\n\n_CAVEAT_: if the (initial) signers list doesn't contain `threshold`'s\nprincipal (`dfx canister id threshold`), certain self-updates will be\nrejected as demonstrated in the next step...\n\n## Example Proposal\n\nOne can send an example proposal to `threshold` by\n``` shell\ndfx canister call threshold submit '(\"haha\", record {principal \"'$(dfx canister id threshold)'\"; \"accept\"; vec {68; 73; 68; 76; 0; 1; 125; 1}})'\n```\nThis will prepare the \"haha\" proposal (with ID `1`) which — when executed — will `accept '1'` on itself.\nYou'll see in the replica log that the proposal got executed by observing\n```\n[Canister rrkah-fqaaa-aaaaa-aaaaq-cai] (\"cannot authorise\", rrkah-fqaaa-aaaaa-aaaaq-cai)\n```\nbecause the canister itself is not authorised to vote.\n\nIf you have set up the signers list to contain 2 principals, then you\nhave to vote from the other canister too to see that error:\n``` shell\ndfx identity use \u003cother\u003e\ndfx canister call threshold accept 1\n```\n\n## Self-upgrade proposal\n\nAs a proof-of-concept I included a self-upgrade code path. Before execution of a\nproposal the addressee principal and the method name are compared to the management\ncanister's `install_code` method. If both facts match, the payload is decoded as\nthe official install parameters, and in case of success, the canister to be upgraded\nis extracted and compared against `threshold`. If they are equal the install parameters\nare used as arguments to the one-way invocation of the management canister's `install_code`\nmethod. Since such an invocation doesn't leave a continuation context, the canister's\nstate machine can cleanly wind down and the upgrade succeeds.\n\n### The concrete command\n\nBelow proposal submission command upgrades `threshold` to a `counter` canister with `get`\n(query) and `inc` (update) methods.\n\n``` shell\ndfx canister call threshold submit '(\"self-upgrade\", record {\n    principal \"aaaaa-aa\";\n    \"install_code\";\n    blob \"DIDL\\03l\\04\\d6\\fc\\a7\\02\\01\\a7\\9f\\c9~\\01\\e3\\a6\\83\\c3\\04\\02\\b3\\c4\\b1\\f2\\04hm{k\\01\\9c\\e9\\c6\\99\\06\\7f\\01\\00\\00\\83\\03\\00asm\\01\\00\\00\\00\\01\\17\\05\\60\\00\\00\\60\\02\\7f\\7f\\00\\60\\00\\01\\7f\\60\\03\\7f\\7f\\7f\\00\\60\\01\\7f\\00\\02h\\05\\03ic0\\09msg_reply\\00\\00\\03ic0\\15msg_reply_data_append\\00\\01\\03ic0\\11msg_arg_data_size\\00\\02\\03ic0\\11msg_arg_data_copy\\00\\03\\03ic0\\04trap\\00\\01\\03\\05\\04\\00\\00\\00\\04\\05\\03\\01\\00\\01\\06\\06\\01~\\01B\\00\\0b\\07B\\03\\12canister_query get\\00\\05\\13canister_update inc\\00\\06\\13canister_update set\\00\\07\\0ai\\04\\11\\00A\\07#\\007\\03\\00A\\00A\\0f\\10\\01\\10\\00\\0b\\11\\00#\\00B\\01|$\\00A\\0fA\\06\\10\\01\\10\\00\\0b6\\00\\10\\02A\\0fF\\10\\08A2A\\00\\10\\02\\10\\03A2)\\03\\00B\\08\\86B\\80\\88\\a5\\a2\\c4\\89\\c0\\80\\f4\\00Q\\10\\08A9)\\03\\00$\\00A\\0fA\\06\\10\\01\\10\\00\\0b\\0c\\00 \\00\\0d\\00A\\15A\\16\\10\\04\\0b\\0b3\\03\\00A\\00\\0b\\07DIDL\\00\\01t\\00A\\0f\\0b\\06DIDL\\00\\00\\00A\\15\\0b\\16Invalid input argument\\00\\01\\0a\\00\\00\\00\\00\\00\\00\\00\\01\\01\\01\"; },)'\n```\nAfter a successful \"upgrade\" `threshold` will serve the `get` query:\n``` shell\ndfx canister call threshold --query get\n(0 : int64)\n```\n_Note_: if you see something else, you have probably forgot to set `threshold` to be its own controller.\n\n### Salvaging the situation\n\nThe stable memory of `threshold` is untouched by `counter`, so a subsequent `dfx deploy`\nwill restore it to a working state.\n\n## Getting information out\n\nThere are only a few getters in the canister\n- get the current signers' list\n- get the (subset of) proposals\n\nBoth are currently defined as update methods, to completely enforce\nconsensus on the replies. (They used to be be queries but those would\nneed to apply the replicated mechanism to get the same guarantees.)\nThe security review has determined that this is the safer default. When\ncertified variables/queries are available (i.e. in place) we might\nflip this default back.\n\nAll retrievals feature access control, that is only specific\nprincipals are permitted to perform the retrieval, and the canister\ntraps when this is not the case.\n\n### Getting the signers\n\nThe list of current signers can be retrieved by the current signers\nonly. This is a somewhat strict specification, as the knowledge of the\nprincipal doesn't imply knowledge of the owning individual, and thus\ndoesn't open the door for social engineering attacks (any more than\nguessing the person). So this authorisation requirement might be\nremoved in the future (https://github.com/dfinity/threshold/issues/12).\n\n### Getting the proposals\n\nThere are two ways of retrieving proposals\n- singular `getProposal(id)`, and\n- plural `getProposals({ newest : ?Id; count : ?Nat })`.\n\nThe former, singular form is authorised based on the signers list _at\nthe creation time of the proposal_, thus allowing access even when a\nprincipal has been removed from the current list.\n\nThe latter (plural) form is authorised based on the current signers\nlist and thus opens up retrieval of _all_ proposals for these principals.\nA range of proposals can be selected by supplying a `newest` ID\n(pinning the most recent proposal in the returned set) and a `count`,\nspecifying the maximal number of proposals to be retrieved. (If a count\nis not supplied, the current default is 10 proposals, but see issue\nhttps://github.com/dfinity/threshold/issues/10.)\n\n## The mutual controller scheme for upgrades\n\nIf the self-upgrade facility is not desired, the user is advised to\nset up `threshold` twice and configuring those such that they are\nmutually the controllers of each other. This will enable each to\nupgrade the other, with fall-back (or restore) abilities preserved in\ncases of botched upgrades.\n\n-------------\n\n## Generic `dfx` usage (can be ignored)\n\nWelcome to your new threshold project and to the internet computer development community. By default, creating a new project adds this README and some template files to your project directory. You can edit these template files to customize your project and to include your own code to speed up the development cycle.\n\nTo get started, you might want to explore the project directory structure and the default configuration file. Working with this project in your development environment will not affect any production deployment or identity tokens.\n\nTo learn more before you start working with threshold, see the following documentation available online:\n\n- [Quick Start](https://sdk.dfinity.org/docs/quickstart/quickstart-intro.html)\n- [SDK Developer Tools](https://sdk.dfinity.org/docs/developers-guide/sdk-guide.html)\n- [Motoko Programming Language Guide](https://sdk.dfinity.org/docs/language-guide/motoko.html)\n- [Motoko Language Quick Reference](https://sdk.dfinity.org/docs/language-guide/language-manual.html)\n- [JavaScript API Reference](https://erxue-5aaaa-aaaab-qaagq-cai.raw.ic0.app)\n\nIf you want to start working on your project right away, you might want to try the following commands:\n\n```bash\ncd threshold/\ndfx help\ndfx canister --help\n```\n\n## Running the project locally\n\nIf you want to test your project locally, you can use the following commands:\n\n```bash\n# Starts the replica, running in the background\ndfx start --background\n\n# Deploys your canisters to the replica and generates your candid interface\ndfx deploy\n```\n\nOnce the job completes, your application will be available at `http://localhost:8000?canisterId={asset_canister_id}`.\n\nAdditionally, if you are making frontend changes, you can start a development server with\n\n```bash\nnpm start\n```\n\nWhich will start a server at `http://localhost:8080`, proxying API requests to the replica at port 8000.\n\n### Note on frontend environment variables\n\nIf you are hosting frontend code somewhere without using DFX, you may need to make one of the following adjustments to ensure your project does not fetch the root key in production:\n\n- set`NODE_ENV` to `production` if you are using Webpack\n- use your own preferred method to replace `process.env.NODE_ENV` in the autogenerated declarations\n- Write your own `createActor` constructor\n","funding_links":[],"categories":["DAO Frameworks"],"sub_categories":["Protocols"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfinity%2Fthreshold","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdfinity%2Fthreshold","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfinity%2Fthreshold/lists"}