From e9a8f39dd4b7ccc46c72ffe53a1ad26f968ff763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aybars=20G=C3=B6ktu=C4=9F=20Ayan?= Date: Mon, 27 Jan 2025 23:21:59 +0300 Subject: [PATCH 1/3] multiversion tests --- docusaurus.config.js | 6 + .../concepts/01_what_is_kilt.md | 68 ++++++ .../version-0.35.0/concepts/02_did.md | 87 +++++++ .../version-0.35.0/concepts/03_web3names.md | 76 ++++++ .../version-0.35.0/concepts/04_asset_dids.md | 58 +++++ .../concepts/05_credentials/01_overview.md | 44 ++++ .../concepts/05_credentials/02_ctypes.md | 131 ++++++++++ .../concepts/05_credentials/03_claiming.md | 40 +++ .../concepts/05_credentials/04_attestation.md | 28 +++ .../05_credentials/05_verification.md | 113 +++++++++ .../05_credentials/06_public_credentials.md | 27 +++ .../concepts/05_credentials/_category_.json | 5 + .../concepts/06_distributed_trust.md | 66 +++++ .../concepts/07_dip/01_overview.md | 71 ++++++ .../concepts/07_dip/02_provider.md | 50 ++++ .../concepts/07_dip/03_consumer.md | 60 +++++ .../concepts/07_dip/04_user_account_kilt.md | 64 +++++ .../concepts/07_dip/05_dapp_developer.md | 152 ++++++++++++ .../concepts/07_dip/_category_.json | 5 + .../version-0.35.0/concepts/08_messaging.md | 44 ++++ .../01_terms_and_quote.md | 87 +++++++ .../09_advanced_concepts/02_nested_ctypes.md | 16 ++ .../09_advanced_concepts/_category_.json | 5 + .../version-0.35.0/concepts/10_glossary.md | 102 ++++++++ .../develop/01_sdk/01_quickstart.md | 227 ++++++++++++++++++ .../02_cookbook/01_dids/00_generate_keys.md | 63 +++++ .../01_dids/01_light_did_creation.md | 36 +++ .../01_dids/02_full_did_creation.md | 34 +++ .../02_cookbook/01_dids/03_full_did_update.md | 15 ++ .../02_cookbook/01_dids/04_did_query.md | 22 ++ .../02_cookbook/01_dids/05_full_did_delete.md | 29 +++ .../02_cookbook/01_dids/06_full_did_tx.md | 57 +++++ .../02_cookbook/01_dids/07_did_signature.md | 25 ++ .../02_cookbook/01_dids/08_did_export.md | 21 ++ .../02_cookbook/01_dids/_category_.json | 5 + .../02_cookbook/02_web3names/01_claim.md | 19 ++ .../02_web3names/02_credential_query.md | 21 ++ .../02_cookbook/02_web3names/03_release.md | 48 ++++ .../02_cookbook/02_web3names/04_query.md | 24 ++ .../02_cookbook/02_web3names/_category_.json | 5 + .../02_cookbook/03_account_linking/01_link.md | 87 +++++++ .../03_account_linking/02_account_name.md | 27 +++ .../03_account_linking/03_unlink.md | 30 +++ .../03_account_linking/_category_.json | 5 + .../04_claiming/01_ctype_creation.md | 44 ++++ .../04_claiming/02_attestation_request.md | 21 ++ .../04_claiming/03_attestation_creation.md | 21 ++ .../04_claiming/04_presentation_creation.md | 26 ++ .../05_presentation_verification.md | 27 +++ .../04_claiming/06_credential_revocation.md | 26 ++ .../02_cookbook/04_claiming/_category_.json | 5 + .../01_credential_issuance.md | 44 ++++ .../02_credential_retrieval.md | 68 ++++++ .../03_credential_revocation.md | 63 +++++ .../05_public_credentials/_category_.json | 5 + .../02_cookbook/06_messaging/01_messaging.md | 55 +++++ .../06_messaging/02_replay_protection.md | 43 ++++ .../02_cookbook/06_messaging/_category_.json | 5 + .../01_sdk/02_cookbook/07_signCallback.md | 83 +++++++ .../01_backward_compatibility.md | 93 +++++++ .../08_upgrading_to_v0_29/_category_.json | 5 + .../08_upgrading_to_v0_29/index.md | 15 ++ .../01_sdk/02_cookbook/_category_.json | 5 + .../03_chain_setup/01_standalone_setup.md | 113 +++++++++ .../03_chain_setup/02_peregrine_setup.md | 21 ++ .../03_chain_setup/03_prod_chain_setup.md | 25 ++ .../01_sdk/03_chain_setup/_category_.json | 5 + .../develop/01_sdk/03_chain_setup/index.md | 24 ++ .../develop/01_sdk/04_integrate/01_nodejs.md | 29 +++ .../develop/01_sdk/04_integrate/02_browser.md | 45 ++++ .../01_sdk/04_integrate/03_distillery.md | 12 + .../01_sdk/04_integrate/_category_.json | 5 + .../develop/01_sdk/04_integrate/index.md | 11 + .../develop/01_sdk/05_troubleshoot.md | 36 +++ .../develop/01_sdk/_category_.json | 5 + .../develop/02_chain/01_introduction.md | 10 + .../develop/02_chain/02_pallets/01_did.md | 115 +++++++++ .../02_chain/02_pallets/_category_.json | 5 + .../develop/02_chain/03_deployments.md | 32 +++ .../develop/02_chain/04_fullnode.md | 227 ++++++++++++++++++ .../develop/02_chain/_category_.json | 5 + .../develop/03_workshop/01_welcome.md | 38 +++ .../develop/03_workshop/02_setup.md | 108 +++++++++ .../develop/03_workshop/03_overview.md | 96 ++++++++ .../03_workshop/04_attester/01_account.md | 111 +++++++++ .../develop/03_workshop/04_attester/02_did.md | 139 +++++++++++ .../03_workshop/04_attester/03_ctype.md | 120 +++++++++ .../03_workshop/04_attester/_category_.json | 5 + .../develop/03_workshop/04_attester/index.md | 59 +++++ .../develop/03_workshop/05_claimer/01_did.md | 75 ++++++ .../03_workshop/05_claimer/02_request.md | 73 ++++++ .../03_workshop/05_claimer/_category_.json | 5 + .../develop/03_workshop/05_claimer/index.md | 76 ++++++ .../develop/03_workshop/06_attestation.md | 55 +++++ .../develop/03_workshop/07_verification.md | 72 ++++++ .../develop/03_workshop/08_done.md | 25 ++ .../develop/03_workshop/_category_.json | 5 + .../develop/04_specifications.md | 28 +++ .../version-0.35.0/develop/05_builtonkilt.md | 78 ++++++ .../version-0.35.0/develop/06_contribute.md | 101 ++++++++ .../develop/07_dApp/01_welcome.md | 13 + .../07_dApp/02_well-known-did-config.md | 110 +++++++++ .../develop/07_dApp/03_session.md | 59 +++++ .../develop/07_dApp/04_verifier.md | 84 +++++++ .../develop/07_dApp/_category_.json | 5 + .../develop/08_opendid/01_overview.md | 40 +++ .../develop/08_opendid/02_opendid_flow.md | 74 ++++++ .../develop/08_opendid/03_opendid_service.md | 115 +++++++++ .../08_opendid/04_integrate_opendid.md | 126 ++++++++++ .../develop/08_opendid/05_demo_project.md | 30 +++ .../develop/08_opendid/06_advanced.md | 111 +++++++++ .../develop/08_opendid/_category_.json | 5 + .../develop/09_polarpath/01_overview.md | 79 ++++++ .../develop/09_polarpath/02_switch_pallet.md | 153 ++++++++++++ .../develop/09_polarpath/_category_.json | 5 + .../version-0.35.0/develop/_category_.json | 5 + .../01_become_a_collator/01_overview.md | 46 ++++ .../02_hardware_requirements.md | 16 ++ .../01_become_a_collator/03_setup_node.md | 183 ++++++++++++++ .../01_become_a_collator/04_session_keys.md | 124 ++++++++++ .../01_become_a_collator/05_join_collators.md | 62 +++++ .../_03_start_node_binary.mdx | 61 +++++ .../_03_start_node_docker.mdx | 65 +++++ .../01_become_a_collator/_category_.json | 5 + .../01_adjust_stake.md | 41 ++++ .../02_advanced_collator_section/02_exit.md | 65 +++++ .../03_collator_lifecycle.md | 44 ++++ .../04_monitoring.md | 59 +++++ .../05_bootnodes.md | 40 +++ .../06_benchmarking.md | 40 +++ .../_category_.json | 5 + .../01_staking/03_delegate/01_overview.md | 17 ++ .../01_staking/03_delegate/02_become.md | 102 ++++++++ .../01_staking/03_delegate/03_adjust_stake.md | 52 ++++ .../01_staking/03_delegate/04_exit.md | 21 ++ .../03_delegate/05_delegator_lifecycle.md | 55 +++++ .../01_staking/03_delegate/_category_.json | 5 + .../01_staking/04_claim_rewards.md | 93 +++++++ .../01_staking/05_unlock_unstaked.md | 48 ++++ .../01_staking/06_troubleshooting.md | 65 +++++ .../01_staking/_04_claim_rewards_collator.mdx | 57 +++++ .../_04_claim_rewards_delegator.mdx | 55 +++++ .../participate/01_staking/_category_.json | 5 + .../01_staking/_disclaimer_staking_tx.md | 6 + .../participate/02_governance/01_vote.md | 83 +++++++ .../02_governance/02_remove_vote.md | 28 +++ .../02_governance/03_unlock_coins.md | 16 ++ .../participate/02_governance/_category_.json | 5 + .../participate/03_treasury_proposal.md | 157 ++++++++++++ .../04_content_creation_guidelines.md | 47 ++++ .../participate/05_propose_tip.md | 87 +++++++ .../participate/_category_.json | 5 + .../version-1.0.0/concepts/01_what_is_kilt.md | 68 ++++++ .../version-1.0.0/concepts/02_did.md | 87 +++++++ .../version-1.0.0/concepts/03_web3names.md | 76 ++++++ .../version-1.0.0/concepts/04_asset_dids.md | 58 +++++ .../concepts/05_credentials/01_overview.md | 44 ++++ .../concepts/05_credentials/02_ctypes.md | 131 ++++++++++ .../concepts/05_credentials/03_claiming.md | 40 +++ .../concepts/05_credentials/04_attestation.md | 28 +++ .../05_credentials/05_verification.md | 113 +++++++++ .../05_credentials/06_public_credentials.md | 27 +++ .../concepts/05_credentials/_category_.json | 5 + .../concepts/06_distributed_trust.md | 66 +++++ .../concepts/07_dip/01_overview.md | 71 ++++++ .../concepts/07_dip/02_provider.md | 50 ++++ .../concepts/07_dip/03_consumer.md | 60 +++++ .../concepts/07_dip/04_user_account_kilt.md | 64 +++++ .../concepts/07_dip/05_dapp_developer.md | 152 ++++++++++++ .../concepts/07_dip/_category_.json | 5 + .../version-1.0.0/concepts/08_messaging.md | 44 ++++ .../01_terms_and_quote.md | 87 +++++++ .../09_advanced_concepts/02_nested_ctypes.md | 16 ++ .../09_advanced_concepts/_category_.json | 5 + .../version-1.0.0/concepts/10_glossary.md | 102 ++++++++ .../develop/01_sdk/01_quickstart.md | 227 ++++++++++++++++++ .../02_cookbook/01_dids/00_generate_keys.md | 63 +++++ .../01_dids/01_light_did_creation.md | 36 +++ .../01_dids/02_full_did_creation.md | 34 +++ .../02_cookbook/01_dids/03_full_did_update.md | 15 ++ .../02_cookbook/01_dids/04_did_query.md | 22 ++ .../02_cookbook/01_dids/05_full_did_delete.md | 29 +++ .../02_cookbook/01_dids/06_full_did_tx.md | 57 +++++ .../02_cookbook/01_dids/07_did_signature.md | 25 ++ .../02_cookbook/01_dids/08_did_export.md | 21 ++ .../02_cookbook/01_dids/_category_.json | 5 + .../02_cookbook/02_web3names/01_claim.md | 19 ++ .../02_web3names/02_credential_query.md | 21 ++ .../02_cookbook/02_web3names/03_release.md | 48 ++++ .../02_cookbook/02_web3names/04_query.md | 24 ++ .../02_cookbook/02_web3names/_category_.json | 5 + .../02_cookbook/03_account_linking/01_link.md | 87 +++++++ .../03_account_linking/02_account_name.md | 27 +++ .../03_account_linking/03_unlink.md | 30 +++ .../03_account_linking/_category_.json | 5 + .../04_claiming/01_ctype_creation.md | 44 ++++ .../04_claiming/02_attestation_request.md | 21 ++ .../04_claiming/03_attestation_creation.md | 21 ++ .../04_claiming/04_presentation_creation.md | 26 ++ .../05_presentation_verification.md | 27 +++ .../04_claiming/06_credential_revocation.md | 26 ++ .../02_cookbook/04_claiming/_category_.json | 5 + .../01_credential_issuance.md | 44 ++++ .../02_credential_retrieval.md | 68 ++++++ .../03_credential_revocation.md | 63 +++++ .../05_public_credentials/_category_.json | 5 + .../02_cookbook/06_messaging/01_messaging.md | 55 +++++ .../06_messaging/02_replay_protection.md | 43 ++++ .../02_cookbook/06_messaging/_category_.json | 5 + .../01_sdk/02_cookbook/07_signCallback.md | 83 +++++++ .../01_backward_compatibility.md | 93 +++++++ .../08_upgrading_to_v0_29/_category_.json | 5 + .../08_upgrading_to_v0_29/index.md | 15 ++ .../01_sdk/02_cookbook/_category_.json | 5 + .../03_chain_setup/01_standalone_setup.md | 113 +++++++++ .../03_chain_setup/02_peregrine_setup.md | 21 ++ .../03_chain_setup/03_prod_chain_setup.md | 25 ++ .../01_sdk/03_chain_setup/_category_.json | 5 + .../develop/01_sdk/03_chain_setup/index.md | 24 ++ .../develop/01_sdk/04_integrate/01_nodejs.md | 29 +++ .../develop/01_sdk/04_integrate/02_browser.md | 45 ++++ .../01_sdk/04_integrate/03_distillery.md | 12 + .../01_sdk/04_integrate/_category_.json | 5 + .../develop/01_sdk/04_integrate/index.md | 11 + .../develop/01_sdk/05_troubleshoot.md | 36 +++ .../develop/01_sdk/_category_.json | 5 + .../develop/02_chain/01_introduction.md | 10 + .../develop/02_chain/02_pallets/01_did.md | 115 +++++++++ .../02_chain/02_pallets/_category_.json | 5 + .../develop/02_chain/03_deployments.md | 32 +++ .../develop/02_chain/04_fullnode.md | 227 ++++++++++++++++++ .../develop/02_chain/_category_.json | 5 + .../develop/03_workshop/01_welcome.md | 38 +++ .../develop/03_workshop/02_setup.md | 108 +++++++++ .../develop/03_workshop/03_overview.md | 96 ++++++++ .../03_workshop/04_attester/01_account.md | 111 +++++++++ .../develop/03_workshop/04_attester/02_did.md | 139 +++++++++++ .../03_workshop/04_attester/03_ctype.md | 120 +++++++++ .../03_workshop/04_attester/_category_.json | 5 + .../develop/03_workshop/04_attester/index.md | 59 +++++ .../develop/03_workshop/05_claimer/01_did.md | 75 ++++++ .../03_workshop/05_claimer/02_request.md | 73 ++++++ .../03_workshop/05_claimer/_category_.json | 5 + .../develop/03_workshop/05_claimer/index.md | 76 ++++++ .../develop/03_workshop/06_attestation.md | 55 +++++ .../develop/03_workshop/07_verification.md | 72 ++++++ .../develop/03_workshop/08_done.md | 25 ++ .../develop/03_workshop/_category_.json | 5 + .../develop/04_specifications.md | 28 +++ .../version-1.0.0/develop/05_builtonkilt.md | 78 ++++++ .../version-1.0.0/develop/06_contribute.md | 101 ++++++++ .../develop/07_dApp/01_welcome.md | 13 + .../07_dApp/02_well-known-did-config.md | 110 +++++++++ .../develop/07_dApp/03_session.md | 59 +++++ .../develop/07_dApp/04_verifier.md | 84 +++++++ .../develop/07_dApp/_category_.json | 5 + .../develop/08_opendid/01_overview.md | 40 +++ .../develop/08_opendid/02_opendid_flow.md | 74 ++++++ .../develop/08_opendid/03_opendid_service.md | 115 +++++++++ .../08_opendid/04_integrate_opendid.md | 126 ++++++++++ .../develop/08_opendid/05_demo_project.md | 30 +++ .../develop/08_opendid/06_advanced.md | 111 +++++++++ .../develop/08_opendid/_category_.json | 5 + .../develop/09_polarpath/01_overview.md | 79 ++++++ .../develop/09_polarpath/02_switch_pallet.md | 153 ++++++++++++ .../develop/09_polarpath/_category_.json | 5 + .../version-1.0.0/develop/_category_.json | 5 + .../01_become_a_collator/01_overview.md | 46 ++++ .../02_hardware_requirements.md | 16 ++ .../01_become_a_collator/03_setup_node.md | 183 ++++++++++++++ .../01_become_a_collator/04_session_keys.md | 124 ++++++++++ .../01_become_a_collator/05_join_collators.md | 62 +++++ .../_03_start_node_binary.mdx | 61 +++++ .../_03_start_node_docker.mdx | 65 +++++ .../01_become_a_collator/_category_.json | 5 + .../01_adjust_stake.md | 41 ++++ .../02_advanced_collator_section/02_exit.md | 65 +++++ .../03_collator_lifecycle.md | 44 ++++ .../04_monitoring.md | 59 +++++ .../05_bootnodes.md | 40 +++ .../06_benchmarking.md | 40 +++ .../_category_.json | 5 + .../01_staking/03_delegate/01_overview.md | 17 ++ .../01_staking/03_delegate/02_become.md | 102 ++++++++ .../01_staking/03_delegate/03_adjust_stake.md | 52 ++++ .../01_staking/03_delegate/04_exit.md | 21 ++ .../03_delegate/05_delegator_lifecycle.md | 55 +++++ .../01_staking/03_delegate/_category_.json | 5 + .../01_staking/04_claim_rewards.md | 93 +++++++ .../01_staking/05_unlock_unstaked.md | 48 ++++ .../01_staking/06_troubleshooting.md | 65 +++++ .../01_staking/_04_claim_rewards_collator.mdx | 57 +++++ .../_04_claim_rewards_delegator.mdx | 55 +++++ .../participate/01_staking/_category_.json | 5 + .../01_staking/_disclaimer_staking_tx.md | 6 + .../participate/02_governance/01_vote.md | 83 +++++++ .../02_governance/02_remove_vote.md | 28 +++ .../02_governance/03_unlock_coins.md | 16 ++ .../participate/02_governance/_category_.json | 5 + .../participate/03_treasury_proposal.md | 157 ++++++++++++ .../04_content_creation_guidelines.md | 47 ++++ .../participate/05_propose_tip.md | 87 +++++++ .../version-1.0.0/participate/_category_.json | 5 + .../version-0.35.0-sidebars.json | 55 +++++ .../version-1.0.0-sidebars.json | 55 +++++ versions.json | 4 + 306 files changed, 15572 insertions(+) create mode 100644 versioned_docs/version-0.35.0/concepts/01_what_is_kilt.md create mode 100644 versioned_docs/version-0.35.0/concepts/02_did.md create mode 100644 versioned_docs/version-0.35.0/concepts/03_web3names.md create mode 100644 versioned_docs/version-0.35.0/concepts/04_asset_dids.md create mode 100644 versioned_docs/version-0.35.0/concepts/05_credentials/01_overview.md create mode 100644 versioned_docs/version-0.35.0/concepts/05_credentials/02_ctypes.md create mode 100644 versioned_docs/version-0.35.0/concepts/05_credentials/03_claiming.md create mode 100644 versioned_docs/version-0.35.0/concepts/05_credentials/04_attestation.md create mode 100644 versioned_docs/version-0.35.0/concepts/05_credentials/05_verification.md create mode 100644 versioned_docs/version-0.35.0/concepts/05_credentials/06_public_credentials.md create mode 100644 versioned_docs/version-0.35.0/concepts/05_credentials/_category_.json create mode 100644 versioned_docs/version-0.35.0/concepts/06_distributed_trust.md create mode 100644 versioned_docs/version-0.35.0/concepts/07_dip/01_overview.md create mode 100644 versioned_docs/version-0.35.0/concepts/07_dip/02_provider.md create mode 100644 versioned_docs/version-0.35.0/concepts/07_dip/03_consumer.md create mode 100644 versioned_docs/version-0.35.0/concepts/07_dip/04_user_account_kilt.md create mode 100644 versioned_docs/version-0.35.0/concepts/07_dip/05_dapp_developer.md create mode 100644 versioned_docs/version-0.35.0/concepts/07_dip/_category_.json create mode 100644 versioned_docs/version-0.35.0/concepts/08_messaging.md create mode 100644 versioned_docs/version-0.35.0/concepts/09_advanced_concepts/01_terms_and_quote.md create mode 100644 versioned_docs/version-0.35.0/concepts/09_advanced_concepts/02_nested_ctypes.md create mode 100644 versioned_docs/version-0.35.0/concepts/09_advanced_concepts/_category_.json create mode 100644 versioned_docs/version-0.35.0/concepts/10_glossary.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/01_quickstart.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/00_generate_keys.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/02_full_did_creation.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/03_full_did_update.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/04_did_query.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/05_full_did_delete.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/06_full_did_tx.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/07_did_signature.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/08_did_export.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/01_claim.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/02_credential_query.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/03_release.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/04_query.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/01_link.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/02_account_name.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/03_unlink.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/06_credential_revocation.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/01_credential_issuance.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/02_credential_retrieval.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/03_credential_revocation.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/06_messaging/01_messaging.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/06_messaging/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/07_signCallback.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/01_backward_compatibility.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/index.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/01_standalone_setup.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/02_peregrine_setup.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/03_prod_chain_setup.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/index.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/01_nodejs.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/02_browser.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/03_distillery.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/index.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/05_troubleshoot.md create mode 100644 versioned_docs/version-0.35.0/develop/01_sdk/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/02_chain/01_introduction.md create mode 100644 versioned_docs/version-0.35.0/develop/02_chain/02_pallets/01_did.md create mode 100644 versioned_docs/version-0.35.0/develop/02_chain/02_pallets/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/02_chain/03_deployments.md create mode 100644 versioned_docs/version-0.35.0/develop/02_chain/04_fullnode.md create mode 100644 versioned_docs/version-0.35.0/develop/02_chain/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/01_welcome.md create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/02_setup.md create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/03_overview.md create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/04_attester/01_account.md create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/04_attester/02_did.md create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/04_attester/03_ctype.md create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/04_attester/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/04_attester/index.md create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/01_did.md create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/02_request.md create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/index.md create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/06_attestation.md create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/07_verification.md create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/08_done.md create mode 100644 versioned_docs/version-0.35.0/develop/03_workshop/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/04_specifications.md create mode 100644 versioned_docs/version-0.35.0/develop/05_builtonkilt.md create mode 100644 versioned_docs/version-0.35.0/develop/06_contribute.md create mode 100644 versioned_docs/version-0.35.0/develop/07_dApp/01_welcome.md create mode 100644 versioned_docs/version-0.35.0/develop/07_dApp/02_well-known-did-config.md create mode 100644 versioned_docs/version-0.35.0/develop/07_dApp/03_session.md create mode 100644 versioned_docs/version-0.35.0/develop/07_dApp/04_verifier.md create mode 100644 versioned_docs/version-0.35.0/develop/07_dApp/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/08_opendid/01_overview.md create mode 100644 versioned_docs/version-0.35.0/develop/08_opendid/02_opendid_flow.md create mode 100644 versioned_docs/version-0.35.0/develop/08_opendid/03_opendid_service.md create mode 100644 versioned_docs/version-0.35.0/develop/08_opendid/04_integrate_opendid.md create mode 100644 versioned_docs/version-0.35.0/develop/08_opendid/05_demo_project.md create mode 100644 versioned_docs/version-0.35.0/develop/08_opendid/06_advanced.md create mode 100644 versioned_docs/version-0.35.0/develop/08_opendid/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/09_polarpath/01_overview.md create mode 100644 versioned_docs/version-0.35.0/develop/09_polarpath/02_switch_pallet.md create mode 100644 versioned_docs/version-0.35.0/develop/09_polarpath/_category_.json create mode 100644 versioned_docs/version-0.35.0/develop/_category_.json create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/01_overview.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/02_hardware_requirements.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/03_setup_node.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/04_session_keys.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/05_join_collators.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/_03_start_node_binary.mdx create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/_03_start_node_docker.mdx create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/_category_.json create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/01_adjust_stake.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/02_exit.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/03_collator_lifecycle.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/04_monitoring.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/05_bootnodes.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/06_benchmarking.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/_category_.json create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/03_delegate/01_overview.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/03_delegate/02_become.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/03_delegate/03_adjust_stake.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/03_delegate/04_exit.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/03_delegate/05_delegator_lifecycle.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/03_delegate/_category_.json create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/04_claim_rewards.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/05_unlock_unstaked.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/06_troubleshooting.md create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/_04_claim_rewards_collator.mdx create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/_04_claim_rewards_delegator.mdx create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/_category_.json create mode 100644 versioned_docs/version-0.35.0/participate/01_staking/_disclaimer_staking_tx.md create mode 100644 versioned_docs/version-0.35.0/participate/02_governance/01_vote.md create mode 100644 versioned_docs/version-0.35.0/participate/02_governance/02_remove_vote.md create mode 100644 versioned_docs/version-0.35.0/participate/02_governance/03_unlock_coins.md create mode 100644 versioned_docs/version-0.35.0/participate/02_governance/_category_.json create mode 100644 versioned_docs/version-0.35.0/participate/03_treasury_proposal.md create mode 100644 versioned_docs/version-0.35.0/participate/04_content_creation_guidelines.md create mode 100644 versioned_docs/version-0.35.0/participate/05_propose_tip.md create mode 100644 versioned_docs/version-0.35.0/participate/_category_.json create mode 100644 versioned_docs/version-1.0.0/concepts/01_what_is_kilt.md create mode 100644 versioned_docs/version-1.0.0/concepts/02_did.md create mode 100644 versioned_docs/version-1.0.0/concepts/03_web3names.md create mode 100644 versioned_docs/version-1.0.0/concepts/04_asset_dids.md create mode 100644 versioned_docs/version-1.0.0/concepts/05_credentials/01_overview.md create mode 100644 versioned_docs/version-1.0.0/concepts/05_credentials/02_ctypes.md create mode 100644 versioned_docs/version-1.0.0/concepts/05_credentials/03_claiming.md create mode 100644 versioned_docs/version-1.0.0/concepts/05_credentials/04_attestation.md create mode 100644 versioned_docs/version-1.0.0/concepts/05_credentials/05_verification.md create mode 100644 versioned_docs/version-1.0.0/concepts/05_credentials/06_public_credentials.md create mode 100644 versioned_docs/version-1.0.0/concepts/05_credentials/_category_.json create mode 100644 versioned_docs/version-1.0.0/concepts/06_distributed_trust.md create mode 100644 versioned_docs/version-1.0.0/concepts/07_dip/01_overview.md create mode 100644 versioned_docs/version-1.0.0/concepts/07_dip/02_provider.md create mode 100644 versioned_docs/version-1.0.0/concepts/07_dip/03_consumer.md create mode 100644 versioned_docs/version-1.0.0/concepts/07_dip/04_user_account_kilt.md create mode 100644 versioned_docs/version-1.0.0/concepts/07_dip/05_dapp_developer.md create mode 100644 versioned_docs/version-1.0.0/concepts/07_dip/_category_.json create mode 100644 versioned_docs/version-1.0.0/concepts/08_messaging.md create mode 100644 versioned_docs/version-1.0.0/concepts/09_advanced_concepts/01_terms_and_quote.md create mode 100644 versioned_docs/version-1.0.0/concepts/09_advanced_concepts/02_nested_ctypes.md create mode 100644 versioned_docs/version-1.0.0/concepts/09_advanced_concepts/_category_.json create mode 100644 versioned_docs/version-1.0.0/concepts/10_glossary.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/01_quickstart.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/00_generate_keys.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/02_full_did_creation.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/03_full_did_update.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/04_did_query.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/05_full_did_delete.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/06_full_did_tx.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/07_did_signature.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/08_did_export.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/01_claim.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/02_credential_query.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/03_release.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/04_query.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/01_link.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/02_account_name.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/03_unlink.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/06_credential_revocation.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/01_credential_issuance.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/02_credential_retrieval.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/03_credential_revocation.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/01_messaging.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/07_signCallback.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/01_backward_compatibility.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/index.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/01_standalone_setup.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/02_peregrine_setup.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/03_prod_chain_setup.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/index.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/01_nodejs.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/02_browser.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/03_distillery.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/index.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/05_troubleshoot.md create mode 100644 versioned_docs/version-1.0.0/develop/01_sdk/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/02_chain/01_introduction.md create mode 100644 versioned_docs/version-1.0.0/develop/02_chain/02_pallets/01_did.md create mode 100644 versioned_docs/version-1.0.0/develop/02_chain/02_pallets/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/02_chain/03_deployments.md create mode 100644 versioned_docs/version-1.0.0/develop/02_chain/04_fullnode.md create mode 100644 versioned_docs/version-1.0.0/develop/02_chain/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/01_welcome.md create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/02_setup.md create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/03_overview.md create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/04_attester/01_account.md create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/04_attester/02_did.md create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/04_attester/03_ctype.md create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/04_attester/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/04_attester/index.md create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/01_did.md create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/02_request.md create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/index.md create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/06_attestation.md create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/07_verification.md create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/08_done.md create mode 100644 versioned_docs/version-1.0.0/develop/03_workshop/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/04_specifications.md create mode 100644 versioned_docs/version-1.0.0/develop/05_builtonkilt.md create mode 100644 versioned_docs/version-1.0.0/develop/06_contribute.md create mode 100644 versioned_docs/version-1.0.0/develop/07_dApp/01_welcome.md create mode 100644 versioned_docs/version-1.0.0/develop/07_dApp/02_well-known-did-config.md create mode 100644 versioned_docs/version-1.0.0/develop/07_dApp/03_session.md create mode 100644 versioned_docs/version-1.0.0/develop/07_dApp/04_verifier.md create mode 100644 versioned_docs/version-1.0.0/develop/07_dApp/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/08_opendid/01_overview.md create mode 100644 versioned_docs/version-1.0.0/develop/08_opendid/02_opendid_flow.md create mode 100644 versioned_docs/version-1.0.0/develop/08_opendid/03_opendid_service.md create mode 100644 versioned_docs/version-1.0.0/develop/08_opendid/04_integrate_opendid.md create mode 100644 versioned_docs/version-1.0.0/develop/08_opendid/05_demo_project.md create mode 100644 versioned_docs/version-1.0.0/develop/08_opendid/06_advanced.md create mode 100644 versioned_docs/version-1.0.0/develop/08_opendid/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/09_polarpath/01_overview.md create mode 100644 versioned_docs/version-1.0.0/develop/09_polarpath/02_switch_pallet.md create mode 100644 versioned_docs/version-1.0.0/develop/09_polarpath/_category_.json create mode 100644 versioned_docs/version-1.0.0/develop/_category_.json create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/01_overview.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/02_hardware_requirements.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/03_setup_node.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/04_session_keys.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/05_join_collators.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/_03_start_node_binary.mdx create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/_03_start_node_docker.mdx create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/_category_.json create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/01_adjust_stake.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/02_exit.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/03_collator_lifecycle.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/04_monitoring.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/05_bootnodes.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/06_benchmarking.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/_category_.json create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/03_delegate/01_overview.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/03_delegate/02_become.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/03_delegate/03_adjust_stake.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/03_delegate/04_exit.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/03_delegate/05_delegator_lifecycle.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/03_delegate/_category_.json create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/04_claim_rewards.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/05_unlock_unstaked.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/06_troubleshooting.md create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/_04_claim_rewards_collator.mdx create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/_04_claim_rewards_delegator.mdx create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/_category_.json create mode 100644 versioned_docs/version-1.0.0/participate/01_staking/_disclaimer_staking_tx.md create mode 100644 versioned_docs/version-1.0.0/participate/02_governance/01_vote.md create mode 100644 versioned_docs/version-1.0.0/participate/02_governance/02_remove_vote.md create mode 100644 versioned_docs/version-1.0.0/participate/02_governance/03_unlock_coins.md create mode 100644 versioned_docs/version-1.0.0/participate/02_governance/_category_.json create mode 100644 versioned_docs/version-1.0.0/participate/03_treasury_proposal.md create mode 100644 versioned_docs/version-1.0.0/participate/04_content_creation_guidelines.md create mode 100644 versioned_docs/version-1.0.0/participate/05_propose_tip.md create mode 100644 versioned_docs/version-1.0.0/participate/_category_.json create mode 100644 versioned_sidebars/version-0.35.0-sidebars.json create mode 100644 versioned_sidebars/version-1.0.0-sidebars.json create mode 100644 versions.json diff --git a/docusaurus.config.js b/docusaurus.config.js index da0c749ea..19dab89bb 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -142,6 +142,12 @@ module.exports = { }, ], }, + { + type: 'docsVersionDropdown', + position: 'right', + dropdownItemsAfter: [{ to: '/versions' }], + dropdownActiveClassDisabled: true, + }, { href: 'https://github.com/KILTprotocol/docs', position: 'right', diff --git a/versioned_docs/version-0.35.0/concepts/01_what_is_kilt.md b/versioned_docs/version-0.35.0/concepts/01_what_is_kilt.md new file mode 100644 index 000000000..735059fbc --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/01_what_is_kilt.md @@ -0,0 +1,68 @@ +--- +id: what-is-kilt +title: What is KILT? +--- + +KILT is a protocol for self-sovereign data and interoperability built on top of the permissionless KILT blockchain. + +The core component of KILT is a digital identity protocol for: + +1. Generating and managing [**decentralized identifiers (DIDs)**](./10_glossary.md) +2. Issuing and presenting digital [**verifiable credentials (VCs)**](./10_glossary.md). + +In contrast to other centralized alternatives, KILT features self-sovereign data and revocable [credentials](./10_glossary.md) anchored to the KILT blockchain. + +KILT was built to be a business enabler, not only for the software industry but also for any entity. +Such entities can establish a business model based on the trust infrastructure KILT provides, which is an essential building block of Web 3.0. + +## What KILT provides + +In particular, KILT provides: + +* A **universal identity protocol** for individuals, organizations, objects, and intelligent agents to obtain credentials for arbitrary attributes about themselves issued by trusted [Attesters](./10_glossary.md). +* A **self-sovereign mechanism** for putting credential holders in control of their own data, allowing them to choose if and where they make their credentials public and how much information from those credentials they wish to share. +* A **[Trust Market](./10_glossary.md) for [Attesters](./10_glossary.md)** of such credentials, allowing widely trusted entities to be compensated for their valuable attestation work. + +KILT's main goal is to generate a level playing field for companies to explore new business models related to trust relationships and data sovereignty. +KILT enables businesses and governments to rely on a common standard owned by everyone participating and not by a single company or set thereof. + +## The problem + +In the beginning, identity and trust between entities were organized in a fully decentralized way. +Individuals created trust relationships directly between them based on their observations. +Of course, this had major drawbacks: + +* The size of the personal social network is limited +* It's not trivial to judge the trustworthiness of an individual +* It's hard to prove one's own identity to outsiders + +When people started to organize themselves in bigger groups, founding villages and cities, those drawbacks were amplified and people needed to address them. +People introduced mechanisms to create trust relationships between groups by issuing some form of attestation. +In this way, people who don't know the individual directly but who trusted the group that gave the attestation. For example, a carpenter's guild, a monastery or a Scottish clan could verify certain properties about another individual. +When the organizational structures grew further and large bureaucratic nations emerged, the authorities issuing those attestations and the scope of the trust relationships also grew. + +While there is now a more centralized way of organizing trust, the actual information that makes up an identity is still handed out directly to the individual, who is still responsible for their data. +Take official personal documents like passports as an example. +Trusted entities issue them and hand them out to the holder. +That holder then has full control of their credential (their passport) and can use it wherever needed. + +With the invention of the internet, and later of Web 2.0, services evolved and merged into totally centralized solutions including Google, Meta, and X among others. +They no longer attest to someone's email account, but due to their business model, those same service providers store and control our personal data (i.e., our identity). +For instance, they could stop allowing us to log into a certain website if they decide to. +More often than not, companies store the data out of necessity and for their own business purpose. +Every time users log into any service, they generate new data points which are then aggregated and sold for advertising purposes. + +KILT Protocol aims to change that and give users back control over their data. + +## The solution + +KILT provides a protocol and the tools for people to manage their own data, and to build a [digital identity](./10_glossary.md) by collecting credentials issued by trusted entities. +Such credentials aren't publicly available but stay within the user's control. +This is similar to the approach used for centuries before big corporations monetized our data. + +The core ideas are: + +* Managing user identities in the form of [decentralized identifiers (DIDs)](https://w3c-ccg.github.io/did-spec/), with the support of the KILT blockchain +* Obtaining digital [verifiable credentials](./10_glossary.md) for user-specified claims +* Supporting revocation of verifiable credentials by their Attesters +* Presenting and verifying verifiable credentials in a privacy-preserving and user-controlled way diff --git a/versioned_docs/version-0.35.0/concepts/02_did.md b/versioned_docs/version-0.35.0/concepts/02_did.md new file mode 100644 index 000000000..7c1164c6c --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/02_did.md @@ -0,0 +1,87 @@ +--- +id: did +title: KILT Decentralized Identifiers (DIDs) +--- + +A KILT decentralized identifier (DID) is a string of letters and numbers uniquely identifying each KILT user. + +Think of a DID as a container of different keys all under the control of the same DID subject. + +:::info DID spec + +For the official W3C DID spec, read the [DID Core spec page](https://www.w3.org/TR/did-core/); for the official KILT DID method specification, read the [KILT DID spec page](https://github.com/KILTprotocol/spec-kilt-did). + +::: + +The simplest type of KILT DID is a **[light DID](#light-dids)**, because you can generate and use it offline and no connection with the KILT blockchain. +Although cheap, light DIDs aren't flexible and are only suitable for low-security use cases. +In more complex use cases, you need an on-chain **[full DID](#full-dids)**, which allow the subject to store different keys and key types and replace them over time by using the KILT blockchain. + +## Light DIDs + +The following is an example of a light KILT DID: + +``` +did:kilt:light:014nv4phaKc4EcwENdRERuMF79ZSSB5xvnAk3zNySSbVbXhSwS +``` + +Beyond the standard prefix `did:kilt:`, the `light:` component indicates that this DID is a light DID, hence it can be resolved and used offline. + + + +Light DIDs optionally support the specification of an **encryption key** (of one of the supported key types) and services, which are both serialized, encoded, and added at the end of the DID, like the following: + +``` +did:kilt:light:014nv4phaKc4EcwENdRERuMF79ZSSB5xvnAk3zNySSbVbXhSwS:z1ERkVVjngcarMbJn6YssB1PYULescQneSSEfCTJwYbzT2aK8fzH5WPsp3G4UVuLWWfsTayketnFV74YCnyboHBUvqEs6J8jdYY5dK2XeqCCs653Sf9XVH4RN2WvPrDFZXzzKf3KigvcaE7kkaEwLZvcas3U1M2ZDZCajDG71winwaRNrDtcqkJL9V6Q5yKNWRacw7hJ58d +``` + +## Full DIDs + +The creation of a full DID requires interaction with the KILT blockchain. +Therefore, a KILT address with enough funds to pay the transaction fees and the required deposit must submit the DID creation operation. + +The following is an example of a full KILT DID: + +``` +did:kilt:4rp4rcDHP71YrBNvDhcH5iRoM3YzVoQVnCZvQPwPom9bjo2e +``` + +Above, there is no `light:` component. +This indicates that the DID is a full DID and that you can't derive the keys associated with it from the DID identifier, but retrieve them from the KILT blockchain. + +Along with an authentication key, encryption key, and services, a full DID also supports an **attestation key**, which you must use to write CTypes and attestations on the blockchain, and a **delegation key** to write delegations on the blockchain. + +## Migrating a light DID to a full DID + +The **migration** of a DID means that a light, off-chain DID is anchored to the KILT blockchain, supporting all the features that full DIDs provide. +In the current version (v1) of the KILT DID protocol, a light DID of the form `did:kilt:light:014nv4phaKc4EcwENdRERuMF79ZSSB5xvnAk3zNySSbVbXhSwS` would become a full DID of the form `did:kilt:4nv4phaKc4EcwENdRERuMF79ZSSB5xvnAk3zNySSbVbXhSwS`. + +:::note + +The identifier of the two DIDs, apart from the initial `01` sequence of the light DID, are the same since both DIDs are derived from the same seed. + +::: + +**Once you migrate a light DID, you can only present all the credentials collected by the light DID using the migrated on-chain full DID.** + +This restriction is by design, as it's assumed that the user had valid reasons to migrate the DID, as on-chain DIDs offer greater security guarantees. +KILT thus rejects light DID signatures even if the original claim in the credential was generated with that off-chain DID. + +:::tip + +For a detailed developer-oriented guide to KILT DIDs, read the [DID Cookbook section](../develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md). + +::: + +## Storing a DID + +Storing a DID on the KILT blockchain requires a deposit, consisting of a base deposit and an additional fee. The base deposit is a fixed amount of 2 KILT, while the additional fee is 0.05 KILT. + +In addition to the base deposit and fee, the total deposit increases based on the storage space used by the DID. Each byte of storage occupied by the DID requires a deposit of 50 micro KILT (0.000005 KILT). + +The inclusion of services and keys determines the overall size of the DID. +The more services and keys in the DID, the larger the storage space required and, consequently, the higher the additional deposit. + +When updating the DID, the deposit is automatically adjusted to match the updated size. This ensures that the deposit accurately reflects the current storage requirements of the DID, whether they increase or decrease. + +You can reclaim the deposit when the DID is deleted from the blockchain, allowing users to retrieve the deposited amount. However, the additional fee can't be refunded once paid. diff --git a/versioned_docs/version-0.35.0/concepts/03_web3names.md b/versioned_docs/version-0.35.0/concepts/03_web3names.md new file mode 100644 index 000000000..b2f54a1cc --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/03_web3names.md @@ -0,0 +1,76 @@ +--- +id: web3names +title: web3names +--- + +import ThemedImage from '@theme/ThemedImage'; + +web3names are user-friendly aliases for KILT DIDs. +They serve the same purpose as domain names for IP addresses. +Do you know the IP address for the "kilt.io" domain name? ๐Ÿคท๐Ÿฝโ€โ™€๏ธ +There is a one-to-one relationship between DIDs and web3names. +This means that you can link a KILT DID to only one web3name, and a web3name can only claim one DID. + +Each web3name is globally unique within the KILT blockchain and consists of a sequence of a minimum of 3 to a maximum of 32 characters taken from a specific character set to enhance human readability and reduce the chances of *two web3names looking the same, despite being different*. + +The character set includes only: + +- *lowercase letters*, from `a` to `z` +- *digits* from `0` to `9` +- the symbols `-` and `_` + +A regex that matches all and only the allowed web3names is the following: + +``` +^[a-z0-9_-]{3,32}$ +``` + +In the global URI space, web3names are prefixed with the `w3n:` URI namespace. +For example, the full URI for the web3name `example-web3name` is `w3n:example-web3name`. + +### Linking multiple accounts to a web3name + +Beyond linking a web3name, KILT lets DID owners link multiple accounts to a single DID. +These accounts aren't specific to the KILT blockchain. +They can reference any chain within the Polkadot ecosystem. +Each account to DID link requires paying a small deposit. + +For DIDs that have also claimed a web3name, the linking feature opens the way to a host of possibilities. +For example, showing the web3name of a collator's account on the [KILT Stakeboard](https://stakeboard.kilt.io/). + + + +For a detailed developer-oriented guide to web3names and account linking, read the [web3name Cookbook section](../develop/01_sdk/02_cookbook/02_web3names/01_claim.md) and the [account linking Cookbook section](../develop/01_sdk/02_cookbook/03_account_linking/01_link.md). + +## KILT DIDs vs. KILT accounts + +While you can link multiple accounts to a DID, it's important to notice the difference between the two. + +KILT *accounts* are classical blockchain accounts, that can hold and send KILT tokens, and sign and submit transactions. + +KILT *DIDs* are a higher level construct derived from KILT accounts, but are completely separated from them. + +This means that **KILT DIDs can't hold any KILT tokens**. + +You use DIDs to authorize (sign) some operations, but you must submit the resulting signature to the KILT blockchain with a KILT account, which must pay for the transaction fees. + +Don't consider a DID `did:kilt:4rp4rcDHP71YrBNvDhcH5iRoM3YzVoQVnCZvQPwPom9bjo2e` the same as the account `4rp4rcDHP71YrBNvDhcH5iRoM3YzVoQVnCZvQPwPom9bjo2e`, although they share the same identifier. + +:::caution + +There's no (immediate) relationship between the two, so you should consider a DID **only as a DID** and never as an account. +If instructed to "*send some funds to the DID by using the account after the `did:kilt` prefix*". Ignore the advice, as without the required technical expertise, sending funds to a DID can result in loss of those funds. + +::: + +### The cost for storing a web3name + +Storing a web3name on the KILT blockchain requires providing a constant deposit, which is currently around 0.11 KILT. The deposit amount is calculated based on the worst-case scenario for a web3name, which is when a user provides a name with 32 characters. +The deposit serves as a security measure to ensure the integrity of the KILT blockchain and incentivize users to manage their web3names responsibly. +A deposit discourages spamming or unnecessary creation of web3names. You can reclaim the deposit can by deleting a web3name. diff --git a/versioned_docs/version-0.35.0/concepts/04_asset_dids.md b/versioned_docs/version-0.35.0/concepts/04_asset_dids.md new file mode 100644 index 000000000..f0b3d8528 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/04_asset_dids.md @@ -0,0 +1,58 @@ +--- +id: asset-dids +title: AssetDIDs +--- + +import ThemedImage from '@theme/ThemedImage'; + +KILT DIDs are suitable for use cases that involve "active" participants. +For example, entities that can act of their will (a person, an organization, a DAO). + +There are classes of entities that represent "passive" participants. +That is, they can be "used" by active participants within a given use case. +KILT defines these class of participants as **assets**. +As with traditional KILT users, assets also need to be uniquely identified, with an *AssetDID*. + +An example of a valid AssetDID is the following: `did:asset:eip155:1.erc721:0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb`. +This AssetDID refers to the [CryptoPunks NFT collection][cryptopunks-nft]. + +## AssetDID structure + +An AssetDID is a *generative* identifier, meaning that it doesn't depend nor rely on any information stored anywhere. +Rather, given the asset to identify, it's **always** possible to generate its AssetDID. +The reverse is also true. Given an AssetDID, it's always possible to dereference it into its components, which, together, uniquely identify a given asset. + +AssetDIDs always start with the `did:asset` prefix, and then contain a *chain* component (namespace + reference) and an *asset* component (namespace + reference + identifier). + +### Chain namespace and reference + +Together, the namespace and reference identify the (blockchain) network on which the asset lives. + +In the case of NFTs, this represents the blockchain on which the smart contract is deployed. +Different deployments of the same network have the same chain namespace but a different reference. +For instance, both the Ethereum mainnet and the Goerli testnet have a chain namespace of `eip155`, but the former is identified by the reference `1` (as the mainnet), while the Goerli testnet is identified by the reference `5`. + +### Asset namespace, reference and identifier + +Similar to their chain counterparts, you use asset *namespaces* to distinguish among different asset classes within the same environment. +In the case of NFTs, a smart contract could support both ERC20 (fungible) and ERC721 (non-fungible) tokens, hence the namespace distinguishes between the two token types. + +Each asset namespace defines the semantics and the meaning of asset references and asset identifiers within that namespace. +In the example of Ethereum-based NFTs, the asset *reference* identifies the smart contract address that stores the NFT. + +**The combination of asset namespace + asset reference is sufficient to identify an NFT collection on a given network.** + +For some assets, for instance NFTs, it's possible to specify an asset *identifier*, used to refer to a single item within the collection. +In the example of the CryptoPunks collection, the AssetDID could be extended with an additional `:1005` to now refer to the [CryptoPunk piece #1005][cryptopunk-1005] rather than to the CryptoPunks collection as a whole. + +![][cryptopunk-1005-image] + +*Credits to OpenSea for the NFT image above.* + +For a more technical explanation of AssetDIDs, please visit our [official specification][asset-did-spec]. + +[cryptopunks-nft]: https://opensea.io/collection/cryptopunks +[cryptopunk-1005]: https://opensea.io/assets/ethereum/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb/1005 +[cryptopunk-1005-image]: https://i.seadn.io/gae/qoR1cWuIZzjlrNVcSMAzhrwDvXNtMxaYuDbNqkc_J5WGGqMSrF0wzO7K2MnSCEBLG8G8pZyJPqV7eTGt4wGwret85sbXJBYoAkypdQ?auto=format&w=3840 +[chainlist]: https://chainlist.org/ +[asset-did-spec]: https://github.com/KILTprotocol/spec-asset-did \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/concepts/05_credentials/01_overview.md b/versioned_docs/version-0.35.0/concepts/05_credentials/01_overview.md new file mode 100644 index 000000000..42ce07760 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/05_credentials/01_overview.md @@ -0,0 +1,44 @@ +--- +id: overview +title: Overview +--- + +import ThemedImage from '@theme/ThemedImage'; + +**Credentials** consist of a set of claims which belong to a **Claimer**, are attested by an **Attester**, and that a **Verifier** can verify. + +
+ +
+ +To get a credential, a Claimer needs to take the following steps: + +1. Find a **CType** to base a claim on. Potential Attesters and Verifiers might advertise this information themselves. +2. Make a **claim** containing a set of properties about themselves. +3. Fulfil any requirement from your Attester. For example, accepting their **Terms** and paying a **Quote**. +4. **Request an attestation** from the Attester. +5. Wait for the Attester to **attest** claims. + +Once attested, the wrapped claims are considered to be a valid credential. + +To use a Credential, the Claimer can generate a Credential-Presentation for a Verifier. +The verification would follow this process: + +1. The Verifier may request a **Credential** of a CType, along with with properties to reveal. +He would also provide a **challenge** to ensure the presentations are not recycled. +2. The Claimer selectively **discloses** the requested properties and signs them along with the challenge to generate a presentation. +3. The Verifier **verify** the presentation structure, content and signature, and decides whether they trust the Attester of the presented credential. + +The next sections describe each step in more detail. + +:::info + +To learn about how to implement the flow above in a dapp that interacts with a browser extension, read the [Credential API specification](https://github.com/KILTprotocol/spec-ext-credential-api). + +::: diff --git a/versioned_docs/version-0.35.0/concepts/05_credentials/02_ctypes.md b/versioned_docs/version-0.35.0/concepts/05_credentials/02_ctypes.md new file mode 100644 index 000000000..11aa11918 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/05_credentials/02_ctypes.md @@ -0,0 +1,131 @@ +--- +id: ctypes +title: CTypes +--- + +import CodeBlock from '@theme/CodeBlock'; + + + +import ctypeSchema from '@site/scripts/out/ctype-schema.json.raw!=!raw-loader!@site/scripts/out/ctype-schema.json'; +import ctype from '@site/scripts/out/ctype.json.raw!=!raw-loader!@site/scripts/out/ctype.json'; + +Claim types (CTypes) are data types specific to KILT that define the structure of a claim (i.e., its data model). +CTypes are based on [JSON Schema](https://json-schema.org/), a standard used to annotate and validate JSON documents. +The schema defines which properties exist and what their type should be, e.g., a string, a number, an object, etc. + +## CType model JSON schema + +The following are all required properties of the JSON schema for CType models: + +- `$id`: An **identifier**: in the format `kilt:ctype:0x{cTypeHash}`. +- `$schema`: A **reference to CType metaschema**: Describes what a valid CType must looks like. You can find the latest metaschema on IPFS at the following address [ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq/](ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq/). +- `title`: A user-friendly name for the CType that makes it easier for users to contextualize. +- `properties`: A set of fields (e.g., name, birth date) that the CType can contain, and that the Claimer can have attested. [Read more details about properties below](#properties). +- `type`: An object containing properties for a claim about the Claimer in the credential. +- `additionalProperties`: A boolean added since version 1 of CTypes, that must be set and allows or disallows any properties in addition to those in `properties`. If set to `false`, the CType validation will fail if there are any additional properties. + +### Properties + +When creating the accepted properties of a new CType schema, you define each property as a key-value pair. +The **key** is the property name (such as "age") and the **value** is an object that has a "type" property whose property defines which type the credential property should have (e.g., "number") or a `$ref` property whose value is a reference to another CType or one of its properties. Using a `$ref` allows for nested CTypes + +Each property must have: + +- One of the following fields: `type` or `$ref` +- A type of `string`, `integer`, `number` or `boolean` to define the attribute +- Reference nested JSON schemas from previously created CTypes with a `uri` using `$ref`. +- The format field is optionally: + - _Date_ format e.g., 2012-04-23T18:25:43.511Z + - _Time_ format e.g., T18:25:43.511Z + - _URI_ format e.g., "https://www.example.com" + + + {ctypeSchema} + + +When submitted, the CType schema is hashed to generate its own identifier, and it becomes the full CType object: + + + {ctype} + + +## CType metadata + +You can link CType Metadata to a given CType to provide title and descriptions in different languages for the whole CType and its properties. + + + +## Hashing + +Use the hash of the CType to identify and anchor it to the KILT blockchain. Once this is done, it's no longer possible to change or delete the CType schema. + +### Constructing the `hash` for the `$id` + +KILT uses the `blake2b256` hashing algorithm to compute the hash of CTypes, after sorting the CType object by a canonicalization algorithm to ensure that semantically equivalent CTypes with different orders of their properties result in the same final hash. + +KILT computes the hash from the following fields of the CType schema: + +- `$schema` +- `properties` + - `key` + - `$ref` + - `type` + - `format` +- `title` +- `type` + +A typical CType ID looks like this: `kilt:ctype:0xda3861a45e0197f3ca145c2c209f9126e5053fas503e459af4255cf8011d5101`. + +## Storing and querying CTypes + +As of the [KILT runtime 1.9.0][kilt-runtime-1.9.0], you can query CTypes directly from any KILT archive node. + +After creating a CType, its full content is only included in the blockchain block history and its hash and creation block number anchored to the blockchain state. + +To query the full content of a CType, use its hash to look up the creation block number, and use that to query any KILT archive node for the extrinsic information about the CType. + +The returned information includes the whole CType, which is now available for the user to, for example, verify credentials against it. + +:::info CType creation cost + +Currently, it costs 0.001 KILT to create a CType on the KILT blockchain. + +::: + +For a detailed developer-oriented guide to KILT CTypes, read the [CType Cookbook section](../../develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md). + +[kilt-runtime-1.9.0]: https://github.com/KILTprotocol/kilt-node/releases/tag/1.9.0 + +:::danger Deprecation Warning: CType metaschema draft-01 + +CTypes based on the [Draft 01](http://kilt-protocol.org/draft-01/ctype) metaschema are subject to a vulnerability that could fool an **Attester** by introducing data they never checked. + + +Due to this vulnerability, this version of the metaschema is deprecated and its use is discouraged when creating new CTypes. + +For optimal security and functionality, use SDK version `0.33.0` or later for creating CTypes. +This newer version defaults to using the updated metaschema available at [`ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq/`](ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq). + +This also means you should update existing CTypes. +While existing CTypes continue to work in the short term, we advise to upgrade to the latest metaschema at your earliest convenience. + +Old Property Value: `"$schema": "http://kilt-protocol.org/draft-01/ctype"` +New Property Value: `"$schema": "ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq/"` + +## Migration instructions + +Attesters should transition to issuing credentials using upgraded versions of CTypes currently in use. + +Using sdk version `0.33.0` or later, you can produce a copy of an existing CType `oldCType` as follows: + +```js +const newCType = CType.fromProperties(oldCType.title, oldCType.properties, 'V1') +``` + +The new CType has the same title and properties as the existing one, but be based on the new metaschema, resulting in a different hash and id. +After [registering the new CType on the KILT blockchain](../../develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md), you can use the new CType as a drop-in replacement in issuing credentials. + +Verifiers depending on these CTypes should accept both the old and new CType during a transition period. +Test thoroughly to ensure the correct behavior and functionality of the new CTypes in your application. +::: diff --git a/versioned_docs/version-0.35.0/concepts/05_credentials/03_claiming.md b/versioned_docs/version-0.35.0/concepts/05_credentials/03_claiming.md new file mode 100644 index 000000000..1779099f6 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/05_credentials/03_claiming.md @@ -0,0 +1,40 @@ +--- +id: claiming +title: Claims +--- + +import CodeBlock from '@theme/CodeBlock'; +import Claim from '@site/scripts/out/claim.json.raw!=!raw-loader!@site/scripts/out/claim.json'; + +As KILT is an open system, entities can make claims about any other entities, including themselves. +An entity can only trust a claim (as in the real world) if another trusted entity (called **Attesters**) *certifies* this claim. +Therefore, **Verifiers** might trust different **Attesters** for distinct scenarios. + +:::info Role recap +- **Claimers** want information about themselves certified. +They also issue credentials, but these remain invalid without an attestation. +- **Attester** check the truthfulness of a claim and certify them. +- **Verifiers** accept the credentials, only verifying that your certification are legitimate. +::: + +## Creating a claim + +In KILT, claims are based on claim types (CTypes). +Given a CType, a Claimer only needs to create a claim with the properties specified in the CType schema. +The resulting claim contains a reference to the CType by its hash and includes the identity of the claim subject (identified by the `owner` property, which has the value of a KILT DID). + + + {Claim} + + +## Requesting a credential + +Once the Claimer has wrapped their claims into a `Credential`, they send it to the chosen Attester using any messaging system for **certification**, i.e. attested. + +The to-be-attested `Credential` contains the original claim, data needed for future selective disclosure of the claim contents (read more in the [Verification documentation](./05_verification.md)), and the legitimation and / or delegation ID of the Attester and the credential root hash, used to identify both the credential and its on-chain attestation. + +:::info + +For a detailed developer-oriented guide to KILT claims, read the [Claim Cookbook section](../../develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md). + +::: diff --git a/versioned_docs/version-0.35.0/concepts/05_credentials/04_attestation.md b/versioned_docs/version-0.35.0/concepts/05_credentials/04_attestation.md new file mode 100644 index 000000000..33c9c2aae --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/05_credentials/04_attestation.md @@ -0,0 +1,28 @@ +--- +id: attestation +title: Attestations +--- + +KILT uses the terms Attestation and Credential interchangeably, but their meaning is different. +A _Credential_ includes the original claimer's data and all the information linked to it, while an _Attestation_ only refers to the on-chain proof that a given credential has been attested. + +To write an attestation on the KILT blockchain, the Attester checks the validity of the received to-be-attested `Credential` data, ensuring that the data inside it matches the requirements of the attestation. For example, that the user's name is indeed Alice. + +After that, the Attester writes the `Credential`'s root hash on the KILT blockchain, certifying that a credential with that root hash is valid. +The Claimer can monitor the blockchain to listen for the event resulting from the attestation process, marking when the credential is attested and usable. + +After the credential has been attested, the Claimer can store it in their wallet and can now use it with Verifiers that trust credentials issued by that Attester. + +:::info + +For a detailed developer-oriented guide to KILT attestations, read the [Attestation cookbook section](../../develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md). + +::: + +### Storing attestations + +Storing a attestation in the blockchain requires providing a constant deposit, which is currently around 0.12 KILT. The deposit amount is calculated based on the worst-case scenario for a attestation, where the maximum storage for one attestation reaches 179 bytes. +The deposit serves as a security measure to ensure the integrity of the blockchain and incentivize users to manage their attestation responsibly. +By requiring a deposit, it discourages spamming or unnecessary creation of attestation. +The attester can reclaim the deposit by deleting their attestation. +Revoking them isn't sufficient as the deposit still shows in chain storage, but marked as invalid. \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/concepts/05_credentials/05_verification.md b/versioned_docs/version-0.35.0/concepts/05_credentials/05_verification.md new file mode 100644 index 000000000..0c50f9dcb --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/05_credentials/05_verification.md @@ -0,0 +1,113 @@ +--- +id: verification +title: Verification +--- + +KILT lets a Verifier check if the information in a credential presented by a Claimer is correct and valid. +With the presentation of the credential, the Claimer also presents evidence that a third party (i.e., an Attester) ensured the correctness of the Claimerโ€™s attributes. + +The Verifier trusts this third party either because they trust their reputation directly or they trust a delegation structure that this Attester is part of. +For example, a State department issuing driving licenses. + +For the verification process: + +- The Claimer needs their credential and the private key associated with their identifier +- The Verifier needs the identifier of the trusted Attester + +During the verification process the Claimer wants to prove the following things to the Verifier: + +- The credential is valid (i.e., not revoked by its Attester) +- The attributes in the credential actually refer to it's Presenter +- The credential contains information relevant for the Verifier for this use case +- That an Attester ensured the correct and trustworthy-ness of the Claimer's attributes + +## Requesting a credential from a Claimer + +The Verifier may request a credential from a Claimer, providing the following data: + +- `cTypeHash`: Which CType hashes the Verifier can work with for the use case. They can provide multiple options, to regard as alternatives. +- `trustedAttesters`: Which Attesters to consider trusted for each specified CType. +- `requiredProperties`: Which properties for each specified CType must at least be revealed for the Verifier to consider the presentation sufficient. + + :::info + + [Read more on selective disclosure](#presenting-a-credential-with-selective-disclosure). + + ::: +- `challenge`: A nonce, which the Verifier can use to ensure that the presentation generated by the Claimer is fresh and not replayed by some other older interactions. + +### Example + +```json +{ + "body": { + "content": { + "cTypes": [ + { + "cTypeHash": "0x3291bb126e33b4862d421bfaa1d2f272e6cdfc4f96658988fbcffea8914bd9ac", + "trustedAttesters": [ + "did:kilt:4pehddkhEanexVTTzWAtrrfo2R7xPnePpuiJLC7shQU894aY" + ], + "requiredProperties": [ + "Email" + ] + } + ], + "challenge": "0x5a1a17eca9ddf6b4d14dffb2abd1411fe9235927975a246b3963db86dfb7de5f" + }, + "type": "request-credential" + } +} +``` + +## Presenting a credential with selective disclosure + +Given the `requiredProperties` specified by the Verifier, the Claimer can decide how much of the information they wish to reveal before they generate the presentation and send it to the Verifier. +If supported by the Verifier, they can choose to hide attributes and thus only disclose a subset of the original claim data. + +:::caution +The presentations can still be correlated, since the hash of the credential always stays the same, even when creating new presentations and selecting different attributes to show. +::: + +For example, verifying a driving license only requires the verification of the driver's name and picture. A Claimer can decide to hide additional information such as age and place of residence. +This increases the privacy of the Claimer since they only need to show attributes required in the specific context. + +:::info + +For a detailed developer-oriented guide to KILT presentation creation, read the [presentation creation cookbook section](../../develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md). + +::: + +## Verifying a presentation + +The Verifier receives the presentation from the Claimer, re-calculates the root hash of the credential from which the presentation was generated, and queries the KILT blockchain to obtain the associated attestation information, including the revocation status of the credential. + +If the Claimer tampered with the credential, the re-calculated root hash won't match any attestation on the chain. +On the other hand, if the Verifier can find an attestation with the calculated hash on the chain and hasn't been revoked, the credential is valid. + +However, this doesn't give the Verifier the guarantee that the Claimer is the rightful/legitimate owner of the credential presented. + +### Verifying the owner of the presented credential + +When issued, a credential is linked to the KILT decentralized identifier (DID) of the original Claimer. +The Verifier can resolve the DID to the public key of the Claimer according to the [KILT DID specification](https://github.com/KILTprotocol/spec-kilt-did). + +The Verifier assumes that the private key for the DID public key is only known to the owner of the credential, and isn't shared across users. +Therefore, when requesting the Claimer to generate a presentation, the Verifier challenges the Claimer to sign a nonce (a random number used once) that the Verifier sends together with their request. + +If the Claimer can sign both the nonce and the presentation with the private key that only the credential's owner should have knowledge of, the Verifier can be sure that the Claimer is the legitimate owner of the credential. + +### Verifying the content of the presented credential + +After the Verifier has checked that the credential is valid and belongs to the presenting Claimer, they need to verify that they have received all the required information. +This is to verify that the presentation received contains the right values **and** the right semantics. + +For example, the `age` property could have different meanings depending on whether it's defined for a passport CType or a Whisky certificate CType. +Therefore, the Verifier has to check if the CType matches one of the requested CTypes, and that the properties disclosed in the presentation includes all the properties requested for that CType presentation. + +:::info + +For a detailed developer-oriented guide to KILT credential verification, read the [verification cookbook section](../../develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md). + +::: + diff --git a/versioned_docs/version-0.35.0/concepts/05_credentials/06_public_credentials.md b/versioned_docs/version-0.35.0/concepts/05_credentials/06_public_credentials.md new file mode 100644 index 000000000..e220b1962 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/05_credentials/06_public_credentials.md @@ -0,0 +1,27 @@ +--- +id: public-credentials +title: Public Credentials for Assets +--- + +import CodeBlock from '@theme/CodeBlock'; + +import PublicCredential from '@site/scripts/out/public-credential.json.raw!=!raw-loader!@site/scripts/out/public-credential.json'; + +[AssetDIDs][asset-did-concepts] give a way to uniquely identify assets regardless of the blockchain they live on or their current owner. +KILT allows owners of an on-chain DID with an assertion key (a.k.a. attesters) to issue credentials to those assets. + +Public credentials aren't that different in their structure from traditional KILT credentials. +The main difference is that, since they're public, they don't have selective disclosure capabilities. +This is because the cryptographic information required to enable this is stripped away from the credential content. + + + {PublicCredential} + + +:::warning Anyone can be an attester! +While the owner of normal KILT credentials holds them in their wallet and decides what credential to share with who, public credentials are, as the name suggests, public by design. + +This means that when reading the credentials issued for a given asset, consumers should be aware of the level of trust they have towards the issuer of each credential. +::: + +[asset-did-concepts]: ../04_asset_dids.md \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/concepts/05_credentials/_category_.json b/versioned_docs/version-0.35.0/concepts/05_credentials/_category_.json new file mode 100644 index 000000000..ff74ea971 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/05_credentials/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Credentials", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/concepts/06_distributed_trust.md b/versioned_docs/version-0.35.0/concepts/06_distributed_trust.md new file mode 100644 index 000000000..261a38b77 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/06_distributed_trust.md @@ -0,0 +1,66 @@ +--- +id: distributed_trust +title: Distributed Trust +--- + +import ThemedImage from '@theme/ThemedImage'; + +Sometimes, Attesters are individuals that attest to the validity of claims made by Claimers. +However, usually multiple Attesters group together to build up trust in a brand. +In this way, Verifiers no longer need to trust each and every Attester individually. +They can put trust in the brand as a whole, which in return ensures that all Attesters working for this brand are credible. +Such a brand can be organized in many different ways. +The KILT protocol provides mechanisms to form such brands on the blockchain. + +There are two ways for Attesters to create groups and build an organization. +The first is by creating a Delegation Hierarchy, which provides a basic and traditional hierarchical structure. +The second option is a Virtual Credential Organization (VCO), which isn't yet implemented in KILT. +VCOs will be more flexible and able to support more decentralized use cases than Delegation Hierarchies. + +## Delegation hierarchies + +Delegation Hierarchies organize their members in a traditional hierarchical structure, and are modeled as a [Tree data structure](https://en.wikipedia.org/wiki/Tree_(data_structure)), also shown in the graph below. +Everyone can use KILT to create a new hierarchy and immediately become the only member of the newly created organization. +Not only is the creator the only member of the organization, they're also the root of the hierarchy. +This means that the creator has full control over the whole hierarchy. + +
+ + + +
+ +Following the laws of Tree data structures, when the hierarchy root adds new members to the hierarchy, the new members become direct "children" of the root. +Similarly, when someone other than root adds new members, it becomes the parent of the new children. + +The graph above provides an example Delegation Hierarchy containing five Attesters. +**Attester 1** is the root (i.e., the creator) of the Delegation Hierarchy. +At some point, Attester 1 has added two more Attesters, Attester 2 and Attester 3. +**Attester 2** was given the right to both further delegate to other entities and to issue credentials on behalf of the organization. +**Attester 3**, on the other hand, was only given the right to add more Attesters to the Delegation Hierarchy, so they can't issue any credentials. +This is useful in cases where someone should only have powers over the members, but isn't authorized to do any work themselves. +For example, in companies this could be someone who manages a team of Attesters. +**Attesters 4** and **Attester 5** were added by Attester 3 and were only given attestation permissions, meaning that they can issue new credentials, but can't delegate any work to other Attesters. +In the company example, these would be employees that attest the work but have no authority to hire new staff. + +### Revocation + +Delegation hierarchies limit who can change or remove permissions. + +For delegations, only the parents of a given Attester can change or remove the Attester's delegation itself or any of its children. +E.g., Attester 2 can't change the delegation information for Attester 4, but Attester 1 and Attester 3 can both remove Attester 4 from the organization, or give them permission to also hire new people, which it can't do right now. + +Credential revocation works similarly, with the difference that any parent can revoke a credential (as with delegations), or by the original Attester. +E.g., Attester 2 can't revoke credentials issued by Attester 1, 3, 4 and 5, while Attester 1 can revoke credentials issued by any Attester since Attester 1 is, directly or indirectly, the parent of every other node. + +## Storing delegation node + +Adding a new node in the delegation hierarchies requires providing a constant deposit, which is currently 1 KILT. +The deposit serves as a security measure to ensure the integrity of the blockchain and incentivize users to manage their nodes responsibly. By requiring a deposit, it discourages spamming or unnecessary creation of nodes. +When a user deletes their node, they can reclaim the deposit. \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/concepts/07_dip/01_overview.md b/versioned_docs/version-0.35.0/concepts/07_dip/01_overview.md new file mode 100644 index 000000000..06583d003 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/07_dip/01_overview.md @@ -0,0 +1,71 @@ +--- +id: what-is-dip +title: Overview +--- + +:::version-label[DIP] + +::: + +The Decentralized Identity Provider (DIP) enables a cross-chain decentralized identity system that mirrors the functionality of OpenID. + +DIP has three key roles: the identity **provider**, the **consumer**, and the **user**. + +- The identity **provider** is any blockchain with an identity system that makes it available for other chains, e.g., KILT Protocol, Litentry, etc. +- The **consumer** is any blockchain that has chosen to delegate identity management to the provider, thus relieving it of needing to maintain its identity infrastructure. +- The **user** is an entity with an identity on the provider chain and wants to use it on other chains without setting up a new identity on each. A Dapp developer can use the DIP SDK to make this process easier for the user and add other DIP-related features to their app. + +This means that parachains requiring an identity solution donโ€™t need to build their own infrastructure. +Instead, they can leverage the infrastructure DIP provides. +DIP is open-source, and you can integrate it with existing Polkadot-compatible runtimes with minimal changes and without affecting the fee model of the consumer system. + +## Adding support to a parachain + +There are several steps to add DIP support to a Substrate-based parachain, depending on the chain's role. + +### Provider chain + +1. Define the format of identity proofs and how verification works with the consumer chains. +2. Add the DIP provider pallet as a dependency to the chain runtime. +3. Configure the DIP provider pallet using the required `Config` trait. + +:::info + +Find more details in the [Provider pallet](./02_provider.md) section. + +::: + +### Consumer chain + +1. Discover and retrieve the format of your identity proofs and how verification works with your identity provider +2. Add the DIP consumer pallet as a dependency to the chain runtime +3. Configure the DIP consumer pallet using the required `Config` trait. +4. Deploy it on chain, along with any additional pallets the identity provider requires. + +:::info + +Find more details in the [Consumer pallet](./03_consumer.md) section. + +::: + +## User accounts on KILT + +For an account to take advantage of DIP with KILT it needs a decentralized identity (DID) and to create a transaction on the provider chain to generate a cross-chain identity commitment. + +For an account to be able to do this, a Dapp developer needs to build the functionality into their app for a user using the DIP SDK. + +:::info + +Find more details in the [user account](./04_user_account_kilt.md) section. + +::: + +## Dapp developer + +The DIP SDK is a JavaScript library that makes it easier for Dapp developers to integrate DIP into their apps. The SDK includes methods for interacting with runtimes, generating proofs, and more. + +:::info + +Find more details in the [Dapp developer](./05_dapp_developer.md) section. + +::: \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/concepts/07_dip/02_provider.md b/versioned_docs/version-0.35.0/concepts/07_dip/02_provider.md new file mode 100644 index 000000000..1803e52dd --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/07_dip/02_provider.md @@ -0,0 +1,50 @@ +# Provider pallet + +This pallet is a core component of the Decentralized Identity Provider protocol. +It enables a Substrate-based chain (provider) to bridge the identities of its users to other connected chains (consumers) trustlessly. +A consumer chain is *connected* to a provider if there is a way for the consumer chain to verify state proofs about parts of the state of the provider chain. + +The pallet is agnostic over the chain-specific definition of *identity*, and delegates the definition of it to the provider chain's runtime. + +What the pallet stores are *identity commitments*, which are opaque byte blobs put in the pallet storage and on which the cross-chain identity bridging protocol can be built. +As for identities, the definition of an identity commitment must be provided by the runtime and is therefore provider-specific. +Naturally, this definition must be made available to consumers willing to integrate the identities living on the provider chain. + +Because providers and consumers evolve at different speeds, identity commitments are versioned. +This allows the provider chain to upgrade to a newer commitment scheme, while still giving its users the possibility to use the old version, if the chains on which they want to use their identity does not yet support the new scheme. + +Identity commitments can be replaced (e.g., if something in the identity info changes), or removed altogether by the identity subject. +After removal, the identity becomes unusable cross-chain, although it will still continue to exist on the provider chain and will be usable for local operations. + +## The `Config` trait + +Being chain-agnostic, most of the runtime configurations must be passed to the pallet's `Config` trait. Specifically: + +* `type CommitOriginCheck: EnsureOrigin`: The check ensuring a given runtime origin is allowed to generate and remove identity commitments. +* `type CommitOrigin: SubmitterInfo`: The resulting origin if `CommitOriginCheck` returns without errors. The origin is not required to be an `AccountId`, but must include information about the `AccountId` of the tx submitter. +* `type Identifier: Parameter + MaxEncodedLen`: The type of an identifier used to retrieve identity information about a subject. +* `type IdentityCommitmentGenerator: IdentityCommitmentGenerator`: The type responsible for generating identity commitments, given the identity information associated to a given `Identifier`. +* `type IdentityProvider: IdentityProvider`: The type responsible for retrieving the information associated to a subject given their identifier. The information can potentially be retrieved from any source, using a combination of on-chain and off-chain solutions. +* `type IdentityProvider: IdentityProvider`: Customizable external logic to handle events in which a new identity commitment is generated or removed. +* `type RuntimeEvent: From> + IsType<::RuntimeEvent>`: The aggregate `Event` type. + +## Storage + +The pallet contains a single storage element, the `IdentityCommitments` double map. +Its first key is the `Identifier` of subjects, while the second key is the commitment version. +The values are identity commitments. + +As mentioned above, a double map allows the same subject to have one commitment for each version supported by the provider, without forcing consumers to upgrade to a new version to support the latest commitment scheme. + +## Events + +The pallet generates two events: a `VersionedIdentityCommitted` and a `VersionedIdentityDeleted`. + +The `VersionedIdentityCommited` is called whenever a new commitment is stored, and contains information about the `Identifier` of the subject, the value of the commitment, and the commitment version. + +Similarly, the `VersionedIdentityDeleted`, is called whenever a commitment is deleted, and contains information about the `Identifier` of the subject and the version of the commitment deleted. + +## Calls (bullet numbers represent each call's encoded index) + +0. `pub fn commit_identity(origin: OriginFor, identifier: T::Identifier, version: Option ) -> DispatchResult`: Generate a new versioned commitment for the subject identified by the provided `Identifier`. If an old commitment for the same version is present, it is overridden. Hooks are called before the new commitment is stored, and optionally before the old one is replaced. +1. `pub fn delete_identity_commitment(origin: OriginFor, identifier: T::Identifier, version: Option) -> DispatchResult`: Delete an identity commitment of a specific version for a specific `Identifier`. If a commitment of the provided version does not exist for the given `Identifier`, an error is returned. Hooks are called after the commitment has been removed. diff --git a/versioned_docs/version-0.35.0/concepts/07_dip/03_consumer.md b/versioned_docs/version-0.35.0/concepts/07_dip/03_consumer.md new file mode 100644 index 000000000..e19a811d0 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/07_dip/03_consumer.md @@ -0,0 +1,60 @@ +# Decentralized Identity Provider (DIP) provider consumer pallet + +This pallet is a core component of the Decentralized Identity Provider protocol. +It enables entities with an identity on a connected Substrate-based chain (provider) to use those identities on the chain this pallet is deployed (consumers) without requiring those entities to set up a new identity locally. +A consumer chain is *connected* to a provider if there is a way for the consumer chain to verify state proofs about parts of the state of the provider chain. + +A cross-chain transaction with DIP assumes the entity submitting the transaction has already generated a cross-chain identity commitment on the provider chain, by interacting with the DIP provider pallet on the provider chain. +With a generated identity commitment, a cross-chain transaction flow for a generic entity `A` works as follows: + +1. `A` generates a state proof proving the state of the identity commitment on the provider chain. +2. `A` generates any additional information required for an identity proof to be successfully verified by the consumer runtime. +3. `A`, using their account `AccC` on the consumer chain, calls the `dispatch_as` extrinsic by providing its identifier on the provider chain, the generated proof, and the `Call` to be dispatched on the consumer chain. + 1. This pallet verifies if the proof is correct, if not it returns an error. + 2. This pallet dispatches the provided `Call` with a new origin created by this pallet, returning any errors the dispatch action returns. The origin contains the information revealed in the proof, the identifier of the acting subject and the account `AccC` dispatching the transaction. + +The pallet is agnostic over the chain-specific definition of *identity proof verifier* and *identifier*, although, when deployed, they must be configured to respect the definition of identity and identity commitment established by the provider this pallet is linked to. + +For instance, if the provider establishes that an identity commitment is a Merkle root of a set of public keys, an identity proof for the consumer will most likely be a Merkle proof revealing a subset of those keys. +Similarly, if the provider defines an identity commitment as some ZK-commitment, the respective identity proof on the consumer chain will be a ZK-proof verifying the validity of the commitment and therefore of the revealed information. + +For identifiers, if the provider establishes that an identifier is a public key, the same definition must be used in the consumer pallet. +Other definitions for an identifier, such as a simple integer or a [Decentralized Identifier (DID)](https://www.w3.org/TR/did-core/), must also be configured in the same way. + +The pallet allows the consumer runtime to define some `LocalIdentityInfo` associated with each identifier, which the pallet's proof verifier can access and optionally modify upon proof verification. +Any changes made to the `LocalIdentityInfo` will be persisted if the identity proof is verified correctly and the extrinsic executed successfully. + +If the consumer does not need to store anything in addition to the information an identity proof conveys, they can use an empty tuple `()` for the local identity info. +Another example could be the use of signatures, which requires a nonce to avoid replay protections. +In this case, a numeric type such as a `u64` or a `u128` could be used, and increased by the proof verifier when validating each new cross-chain transaction proof. + +## The `Config` trait + +Being chain-agnostic, most of the runtime configurations must be passed to the pallet's `Config` trait. +Nevertheless, most of the types provided must reflect the definition of identity and identity commitment that the identity provider chain has established. +The trait has the following components: + +* `type DipCallOriginFilter: Contains>`: A preliminary filter that checks whether a provided `Call` accepts a DIP origin or not. If a call such as a system call does not accept a DIP origin, there is no need to verify the identity proof, hence the execution can bail out early. This does not guarantee that the dispatch call will succeed, but rather than it will mostly not fail with a `BadOrigin` error. +* `type DispatchOriginCheck: EnsureOrigin<::RuntimeOrigin, Success = Self::AccountId>`: The origin check on the `dispatch_as` extrinsic to verify that the caller is authorized to call the extrinsic. If successful, the check must return a `AccountId` as defined by the consumer runtime. +* `type Identifier: Parameter + MaxEncodedLen`: The type of a subject identifier. This must match the definition of `Identifier` the identity provider has defined in their deployment of the provider pallet. +* `type LocalIdentityInfo: FullCodec + TypeInfo + MaxEncodedLen`: Any additional information that must be available only to the provider runtime that is required to provide additional context when verifying a cross-chain identity proof. +* `type ProofVerifier: IdentityProofVerifier`: The core component of this pallet. It takes care of validating an identity proof and optionally update any `LocalIdentityInfo`. It also defines, via its associated type, the structure of the identity proof that must be passed to the `dispatch_as` extrinsic. Although not directly, the proof structure depends on the information that goes into the identity commitment on the provider chain, as that defines what information can be revealed as part of the commitment proof. Additional info to satisfy requirements according to the `LocalIdentityInfo` (e.g., a signature) must also be provided in the proof. +* `type RuntimeCall: Parameter + Dispatchable::RuntimeOrigin>`: The aggregated `Call` type. +* `type RuntimeOrigin: From> + From<::RuntimeOrigin>`: The aggregated `Origin` type, which must include the origin exposed by this pallet. + +## Storage + +The pallet contains a single storage element, the `IdentityEntries` map. +It maps from a subject `Identifier` to an instance of `LocalIdentityInfo`. + +This information is updated by the proof verifier whenever a new cross-chain transaction and its proof is submitted. + +## Origin + +Because the pallet allows other `Call`s to be dispatched after an identity proof has been verified, it also exposes a `Origin` that can be used for those calls that require indeed a call to be DIP-authorized. + +The origin is created after the identity proof has been successfully verified by the proof verifier, and it includes the identifier of the subject, the address of the tx submitter, and the result returned by the proof verifier upon successful verification. + +## Calls (bullet numbers represent each call's encoded index) + +0. `pub fn dispatch_as(origin: OriginFor, identifier: T::Identifier, proof: IdentityProofOf, call: Box>) -> DispatchResult`: Try to dispatch a new local call only if it passes all the DIP requirements. Specifically, the call will be dispatched if it passes the preliminary `DipCallOriginFilter` and if the proof verifier returns an `Ok(verification_result)` value. The value is then added to the `DipOrigin` and passed down as the origin for the specified `Call`. If the whole execution terminates successfully, any changes applied to the `LocalIdentityInfo` by the proof verifier are persisted to the pallet storage. diff --git a/versioned_docs/version-0.35.0/concepts/07_dip/04_user_account_kilt.md b/versioned_docs/version-0.35.0/concepts/07_dip/04_user_account_kilt.md new file mode 100644 index 000000000..97c5fb035 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/07_dip/04_user_account_kilt.md @@ -0,0 +1,64 @@ +--- +id: dip-accounts-kilt +title: Enabling DIP for user accounts on the KILT blockchain +--- + +:::version-label[DIP] + +::: + +For an account to take advantage of DIP it needs a decentralized identity (DID) and to create a transaction on the provider chain to generate a cross-chain identity commitment. + +For an account to be able to do this, a Dapp developer needs to build the functionality into their app for a user using the DIP SDK. + +The implementation of this transaction is per-chain and this documentation provides an example of how to do this on the KILT blockchain. + +## Using the KILT DIP SDK + +Add the SDK as a dependency: + +```bash npm2yarn +npm install @kiltprotocol/dip-sdk +``` + +Include the following imports in your code: + +```typescript +import { generateDipAuthorizedTxForSibling } from '@kiltprotocol/dip-sdk' +``` + +The `generateDipAuthorizedTxForSibling` method returns a submittable extrinsic promise for the provided call which includes a complete DIP proof according to the parameters provided. You can then use this on a consumer chain as the `submitterAddress` parameter of which the provider chain is a sibling. + +:::info What is a valid call + +A valid call is a HEX-encoded call of the parent relaychain with the right key re-generated from the provided seedling information, i.e., either with the provided mnemonic or with the provided combination of base mnemonic and derivation path. + +You can generate valid HEX-encoded calls at [PolkadotJS Apps](https://polkadot.js.org/apps/) from the `Developer > Extrinsics` menu. + +Copy the value from `encoded call data` and pass it as a parameter. + +::: + +The command requires the following variables: + +- `call` The `Call` on the consumer chain that requires a DIP origin. +- `consumerApi` The [`ApiPromise`](https://polkadot.js.org/docs/api/examples/promise/) instance for the consumer chain. +- `didUri` The DID URI of the DIP subject performing the cross-chain operation. +- `keyIds` The verification method IDs of the DID are revealed in the cross-chain operation. +- `proofVersion` The version of the DIP proof to generate. +- `providerApi` The [`ApiPromise`](https://polkadot.js.org/docs/api/examples/promise/) instance for the provider chain. +- `relayApi` The [`ApiPromise`](https://polkadot.js.org/docs/api/examples/promise/) instance for the parent relay chain. +- `signer` The signing callback to sign the cross-chain transaction. +- `submitterAddress` The address of the transaction submitter on the consumer chain. +- `keyRelationship` The `VerificationKeyRelationship` required for the DIP operation authorized on the relay chain. + +And the following optional environment variables: + +- `blockHeight` The block number on the consumer chain to use for the DID signature. Uses the latest best block number, if not provided. +- `genesisHash` The genesis hash of the consumer chain to use for the DID signature. Retrieved at runtime from the consumer chain If not provided. +- `providerBlockHeight` The block number of the provider to use for the generation of the DIP proof. Uses the latest finalized block number if not provided. +- `accountIdRuntimeType` The runtime type definition for an `AccountId` on the consumer chain. Uses the `AccountId` type if not provided. +- `blockNumberRuntimeType` The runtime type definition for a `BlockNumber` on the consumer chain. Uses the `u64` type if not provided. +- `identityDetailsRuntimeType` The runtime type definition for the `IdentityDetails` on the consumer chain. Uses the `Option` type, representing a simple nonce if not provided. +- `includeWeb3Name` Flag indicating whether the generated DIP proof should include the web3name of the DID subject. If not provided, the web3name is not revealed. +- `linkedAccounts` The list of linked accounts to revealed in the generated DIP proof. No account is revealed if not provided. \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/concepts/07_dip/05_dapp_developer.md b/versioned_docs/version-0.35.0/concepts/07_dip/05_dapp_developer.md new file mode 100644 index 000000000..0083e33f7 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/07_dip/05_dapp_developer.md @@ -0,0 +1,152 @@ +--- +id: dapp-developer +title: Dapp developer +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +:::version-label[DIP] + +::: + +The Decentralized Identity Provider (DIP) SDK helps Dapp developers build DIP functionality into their apps. + +## Installation + +Add the SDK as a dependency: + +```bash npm2yarn +npm install @kiltprotocol/dip-sdk +``` + +Import the SDK into your code: + +```typescript +import { * } from '@kiltprotocol/dip-sdk' +``` + +## Example application + +This example application walks through the code you can find in the tests for the DIP SDK. + +### 1. Generate a base proof + +Start by generating the base proof for the DIP using the `[generateDipSiblingBaseProof](https://kiltprotocol.github.io/dip-sdk/functions/generateDipSiblingBaseProof.html)` method and passing the desired configuration: + +```typescript +const baseDipProof = await DipSdk.generateDipSiblingBaseProof(config) +``` + +:::info What's a base proof? +A base proof is a cross-chain state proof, revealing the parts of a DID Document stored on the KILT blockchain. +::: + +The configuration for the base proof takes the following parameters: + +- `didUri`: (Required) The DID URI of the DIP subject performing the cross-chain operation. +For example, `did:kilt:4q4QzFTs9hKh4QizLB3B7zuGYCG3QPamiBFEgwM6gTM7gK3g` +- `keyIds`: (Required) An array of verification method IDs of the DID revealed in the cross-chain operation. +- `proofVersion`: (Required) The version of the DIP proof to generate. +Currently only supports version 1. +- `blockNumber`: The block number of the relay chain to use for the generation of the DIP proof. +If not provided, uses the last finalized block. +- `linkedAccounts`: An array of [account addresses linked to the DID](../../develop/01_sdk/02_cookbook/03_account_linking/01_link.md#linking-an-account-to-a-did) to reveal in the generated proof. +- `web3Name`: Whether to reveal [the web3name of the DID subject](../../develop/01_sdk/02_cookbook/02_web3names/01_claim.md) in the generated proof. + +In the example code, the configuration also has extra parameters for the time-bound DID signature extension [mentioned below](#creating-extensions-for-specific-proofs). + +The configuration also has details of the provider, which in this case uses a value populated from an environment variable: + +```typescript +const providerAddress = `ws://127.0.0.1:${process.env['PROVIDER_ALICE_RPC']}` +``` + +### 2. Generate a submittable extrinsic + +The method returns the DID base proof. +You have to call a second method, the `[generateDipSubmittableExtrinsic](https://kiltprotocol.github.io/dip-sdk/functions/generateDipSubmittableExtrinsic.html)` method to generate a submittable extrinsic that includes the generated proof. + +You need to pass the following parameters: + +- The API of the consumer chain. +- The base proof. +- The call to the consumer chain. +- The DID URI. + +:::info Submittable extrinsics + +A transaction that originates from an external account and affects the state of the blockchain. +An extrinisc executes actions on the network, such as transferring funds, making governance decisions, using functionality of the parachain, or interacting with smart contracts. + +::: + +```typescript +const dipSubmittable = DipSdk.generateDipSubmittableExtrinsic({ + api: consumerApi, + baseDipProof, + call, + didUri: did.uri, +}) +``` + +The method returns the different components of the proof, [which you can see in the example code](https://github.com/KILTprotocol/dip-sdk/blob/9ad141b3757e076744ab8b2d29bcf10bbeaddd9f/tests/dip-provider-template-dip-consumer-template/develop.test.ts#L219): + +- The provider head proof, which is proof of the provider parachain header on the relay chain. +- The commitment proof, which proves the DIP commitment for the subject of the action, which is the DID URI. +- The DID proof, which reveals parts of the DID document as specified by key IDs, proof version, and whether to include the web3name and any of its linked accounts. + +Behind the scenes, the method uses the `dispatchAs` method ([and corresponding chain method](https://github.com/KILTprotocol/kilt-node/blob/4ddb8a0ef6258873458f19d3ee9dcb6d7c24e645/pallets/did/src/lib.rs#L1152)) to pass the extrinsic following the consumer's type registry. +You can now sign and submit to the consumer chain. + +```typescript +await signAndSubmitTx(consumerApi, dipSubmittable, submitterKeypair) +``` + +### 3. Linking accounts (optional) + +Linked accounts let you specify which accounts you want to prove that you control when you make the cross-chain proof. +As part of the proof provided, you can also include other values, such as the web3name. + +For all the accounts you want to link, use the `associateAccountToChainArgs` method, [as detailed in this guide](../../develop/01_sdk/02_cookbook/03_account_linking/01_link.md#linking-an-account-to-a-did). + +You can then batch all the linked account transactions and authorize them using the `authorizeTx` method. + +```typescript +const signedLinkedAccounts = await Kilt.Did.authorizeTx( + newFullDidUri, + providerApi.tx.utility.batchAll(linkAccountTxs), + signCallback, + newSubmitterKeypair.address as KiltAddress, + { txCounter: new BN(4) } +) +``` + +## Creating extensions for specific proofs + +If you need a specific proof type for a consumer chain, then a chain developer needs to submit a PR to the SDK repository in the `src > dipProof > extensions` folder. +The extension included with the SDK adds support for a time-bound DID signature, i.e., a signature which is valid only until a certain block number on the consumer chain. + +The extension can take any form, but must return [a SCALE encoded](https://docs.substrate.io/reference/scale-codec/) object. +There's an example of how the extension does this [on GitHub](https://github.com/KILTprotocol/dip-sdk/blob/9ad141b3757e076744ab8b2d29bcf10bbeaddd9f/src/dipProof/extensions/timeBoundDidSignature.ts#L113). + +To add the extension, use the `generateDipSubmittableExtrinsic` method and pass the additional proof elements along with consumer chain specific components. + +```typescript +const dipSubmittable = DipSdk.generateDipSubmittableExtrinsic({ + additionalProofElements: + DipSdk.dipProof.extensions.timeBoundDidSignature.toChain( + crossChainDidSignature + ), + api: consumerApi, + baseDipProof, + call, + didUri: did.uri, +}) +``` + +:::info + +Read the auto-generated [API documentation](https://kiltprotocol.github.io/dip-sdk) for more details on the methods the SDK provides. + +::: diff --git a/versioned_docs/version-0.35.0/concepts/07_dip/_category_.json b/versioned_docs/version-0.35.0/concepts/07_dip/_category_.json new file mode 100644 index 000000000..86efa9440 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/07_dip/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Decentralized Identity Protocol (DIP)", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/concepts/08_messaging.md b/versioned_docs/version-0.35.0/concepts/08_messaging.md new file mode 100644 index 000000000..1070ed633 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/08_messaging.md @@ -0,0 +1,44 @@ +--- +id: messaging +title: KILT Messaging +--- +import CodeBlock from '@theme/CodeBlock'; + + +import encryptedMessage from '@site/scripts/out/encrypted-message.json.raw!=!raw-loader!@site/scripts/out/encrypted-message.json'; + +Distributed trust on the internet only works if credentials and other information can be exchanged securely, and communicating parties can be confident that bad actors aren't fooling or eavesdropping on them. +KILT provides a **transport-agnostic messaging layer** that helps with securely exchanging data between the respective owners of two DIDs. + +This messaging layer provides **authenticated end-to-end encryption**, the gold standard in secure communication, in a way that hides the security of the technologies used for transporting the message over the internet โ€“ย be it sending the encrypted messages via email, or posting them to and fetching them from a centralized or decentralized messaging service. + +:::info +The messaging layer enables secure communication between two digital identities, DIDs. +A necessary condition for secure communication with a given person or organization is to make sure that the DID on the other side of the communication channel is really controlled by the other party to avoid attacks such as *Man in the Middle* (MitM) attacks. + + + +::: + +To be able to communicate, the two DIDs need to expose **key agreement public keys** for that purpose (a.k.a., an **encryption key**). +To send a message to the other party, a DID owner (called **Alice**) looks up her peer's (called **Bob**) encryption public key, which can be part of either a [full DID](./02_did.md#full-dids) or a [light DID](./02_did.md#light-dids). +Using this key in combination with her secret encryption key, **Alice** can now encrypt the message such that only she and **Bob** can decrypt it. A **nonce** introduces randomness and uniqueness into encryption operations, making it highly challenging for an attacker to predict or replicate the encryption process. +Each message has a different **nonce**, resulting in the creation of a unique encryption context for every message. + +**Bob** can decrypt this message after looking up **Alice's** encryption key. +An additional _message authentication code_ (MAC) added during encryption and verified on decryption protects against manipulation of the encrypted data. +As long as both parties keep their secret keys well protected, the combination of these measures allows **Bob** to be confident that if the message decrypts successfully, only **Alice** could have encrypted it and that malicious third party hasn't read or tampered with it while in transport. + +While encrypted, the message travels in a compact and privacy-preserving envelope format that only exposes data that the recipient needs to be able to decrypt. + + + {encryptedMessage} + + +The encrypted message not only references the DIDs of sender and recipient, it also references the unique identifier of the keys that used in encryption. +Therefore, this scheme still works if a DID should expose multiple encryption keys from which a message sender may choose. + +:::caution +While no one can read or change what's inside an encrypted message even if they intercept it while traveling on the network, a sophisticated attacker may try to guess what's inside and trick either side of the channel by resubmitting a copy of that message later. +For a detailed developer-oriented guide about how to protect against *replay attacks*, read the [Replay Protection Cookbook section](../develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md). +::: diff --git a/versioned_docs/version-0.35.0/concepts/09_advanced_concepts/01_terms_and_quote.md b/versioned_docs/version-0.35.0/concepts/09_advanced_concepts/01_terms_and_quote.md new file mode 100644 index 000000000..c79fcbb63 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/09_advanced_concepts/01_terms_and_quote.md @@ -0,0 +1,87 @@ +--- +id: terms-and-quotes +title: Terms and Quotes +--- + +During the attestation flow, it can happen that either the Claimer requests or the Attester sends the terms of the attestation, i.e., the requirements set by the both parties (the Claimer and the Attester) for the conditions of the attestation. + +These terms are defined and agreed upon before the credential is issued. +This part of the process requires interaction and communication between both parties. +This communication can be done independently, e.g., in person, via messaging, on social media etc., or via the KILT Software Development Kit (SDK). + +## Defining Terms + +The `Terms` object consists of following items: + +- **Claim**: A partial claim with information the Attester already has about the Claimer. + - This helps the Claimer to pre-fill their claims with information only known to the Attester. + - The partial claim has to at least contain the CType hash the attestation will be based on. +- **CTypes**: An optional list of full CTypes, in case the Claimer does not know the correct CType for the credential, yet. +- **Legitimations**: A legitimation is a credential, issued to the Attester, showing that the Attester has the authority or legitimacy to attest the claim requested. + - This is a way of establishing trust between the participants. +- **Delegation Id**: An Attester may be part of a top-down trust authority that has given them the right to attest in the name of an institution, or similar, as explained in the [Distributed Trust section](../06_distributed_trust.md). If the Attester has attestation rights, delegated from another entity, this should be stated clearly at this point. +- **Quote**: As shown in the [section below](#defining-a-quote). + +Only the CType hash in the partial claim is required, everything else is optional. + +## Sending Terms + +Both "request terms" and "submit terms" are part of the messaging system: the message is sent as "request terms" and received as "submit terms". + +The interaction is as follows: + +- The Claimer creates a partial `Claim` (optionally) and sends a message to the Attester, requesting the `Terms`. +- An Attester creates a `Terms` object and sends it, as part of a "submit terms" message, back to the Claimer. +- The Claimer receives the message, checks the `Terms` and, if all is in order, agrees to them. + + +## Defining a Quote + +A `Quote` object consists of costs, a time frame for delivering the attestation, and the terms and conditions of the work to be performed. +It may be sent to the Claimer by the Attester as part of the terms. +In cases where multiple Attesters provide the same attestation (for example, a car inspection) the Claimer may request a Quote from several Attesters to choose the Attester with the best conditions. + +To come to an agreement on the Quote, the participants may message back and forth, signing the object. +If the Attester wishes to add a Quote to their Terms, the Attester signs the `Quote` object before sending it as part of the "submit terms" message to the Claimer. +After the Claimer has received the signed Quote and accepts it, the Claimer counter-signs it and attaches the credential hash for linking the Quote to the credential that it refers to. +After the final exchange, the Attester checks all the information and issues the credential. + +```mermaid +classDiagram + class Quote { + String attesterDid + String cTypeHash + Cost cost + String currency + String timeframe + String termsAndConditions + } + + class Cost { + Number gross + Number net + Object tax + } + + Quote *-- Cost + + class Signature { + String keyId + String signature + } + + class QuoteAttesterSigned { + Signature attesterSignature + } + + QuoteAttesterSigned *-- Signature + QuoteAttesterSigned --|> Quote + + class QuoteAgreement { + String rootHash + Signature claimerSignature + } + + QuoteAgreement *-- Signature + QuoteAgreement --|> QuoteAttesterSigned +``` diff --git a/versioned_docs/version-0.35.0/concepts/09_advanced_concepts/02_nested_ctypes.md b/versioned_docs/version-0.35.0/concepts/09_advanced_concepts/02_nested_ctypes.md new file mode 100644 index 000000000..4b96cbced --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/09_advanced_concepts/02_nested_ctypes.md @@ -0,0 +1,16 @@ +--- +id: nested-ctypes +title: Nested CTypes +--- + +A Nested CType is a hierarchical composite schema that includes other CTypes as substructures by referencing them. +For example, a company could use a Nested CType that includes the required credentials, qualifications, health and safety certificates, etc. of its current employees. +When verifying a Nested CType, the sub-CTypes need to be available. + +## Referencing + +JSON-schema provides a referencing keyword `$ref` that can be used as a pointer from other JSON schemas. +This allows CTypes to either reference fields in other CTypes or nest entire CTypes within one another, providing flexibility for several different use cases. +A claim from a Nested CType requires the given CType, a list of comprised schemas, the claim content and the address of the owner. + +This facility requires all JSON objects to build the schema and allows the reuse of previous schemas, reducing the need for copy-and-paste. diff --git a/versioned_docs/version-0.35.0/concepts/09_advanced_concepts/_category_.json b/versioned_docs/version-0.35.0/concepts/09_advanced_concepts/_category_.json new file mode 100644 index 000000000..2a674ea41 --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/09_advanced_concepts/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Advanced Concepts", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/concepts/10_glossary.md b/versioned_docs/version-0.35.0/concepts/10_glossary.md new file mode 100644 index 000000000..b607253bc --- /dev/null +++ b/versioned_docs/version-0.35.0/concepts/10_glossary.md @@ -0,0 +1,102 @@ +--- +id: glossary +title: KILT Glossary +--- + +Here is a glossary of terms related to the KILT Protocol: + +## W3C: Self-Sovereign Identity (SSI) + +**Decentralized Identifier (DID)** โ€“ a unique digital identifier for entities (people, machines, services, and anything that identities can be built on) which can be anchored to a blockchain to provide the core of a verifiable digital identity. +For example, **did:kilt:4sxSYXakw1ZXBymzT9t3Yw91mUaqKST5bFUEjGEpvkTuckar**. +In KILT, identity is built by adding credentials to the DID. + +**DID Authentication** โ€“ the process of proving that an entity has control over a DID, typically by using a digital signature or other cryptographic mechanism. + +**DID Communication** โ€“ the use of DIDs to enable secure and decentralized communication between two or more parties, without the need for a central intermediary. + +**DID Controller** โ€“ an entity that has control over a DID. +This may be the entity that generated the DID or an entity that has been authorized by the DID owner to manage the DID. + +**DID Document** โ€“ a JSON-LD document that contains information about a DID, including public keys, services, and other metadata. + +**DID Method** โ€“ a set of rules and specifications for how a DID is created, resolved, and managed on a particular network or platform. + +**DID Resolver** โ€“ a software component that can resolve a DID to a DID Document, which contains information about the DID, such as public keys, services, and other metadata. + +**Self-Sovereign Identity (SSI)** - a decentralized digital identity management system that enables individuals to own and control their identity information using secure digital technologies, such as blockchain. +SSI eliminates the need for intermediaries and provides individuals with greater privacy, security, and control over their personal data. +It is an emerging concept that has the potential to transform how identity is managed and verified across various sectors. + +**Verifiable Credentials (VCs)** - digital credentials that can be used to prove claims about a person, organization, or thing, and are designed to be portable, interoperable, and privacy-preserving. +Verifiable credentials are often associated with DIDs and can be stored and managed using a DID-based identity system. + +## KILT Protocol Specific Terms + +**Attestation** -the act of formally confirming and certifying the validity of the data within a claim, typically performed by a trusted Attester. + +**Attester** - a trusted entity or organization that attests claims and issues credentials on the KILT Protocol. +The Attester confirms the truth of the claim requested based on the information presented by the Claimer. + +**Claimer** - an individual or entity that asserts a claim or statement about their identity or qualifications. +The Claimer can use credentials to provide evidence of their claims, which can be verified by third-party entities or systems. + +**Claim Type (CType)** - a specific type of claim that can be made about an individual, such as their education, work experience, or identity information. +Each claim type has a defined set of attributes that must be provided to support the claims data type and structure. +It can be used to generate verifiable credentials that can be shared with others. [See the CTypes concept page for more details](https://docs.kilt.io/docs/concepts/credentials/ctypes) + +**Credential** - a verifiable digital representation of a claim made by a Claimer, which has been attested to by a trusted entity, such as an Attester or Issuer. +It consists of a set of attributes that describe the claim and the proof of its validity, and can be shared with third parties to provide verifiable proof of the claim. + +**KILT Digital Identity** - a self-sovereign identity that is owned and controlled by the individual or entity it represents. +It consists of verifiable credentials that are issued by trusted entities, such as Attesters, and can be used to prove claims about the individual or entity's identity, qualifications, or other attributes. + +**KILT Coin** - the native token of the KILT blockchain used for paying for attestations and DIDs. It can also be used for governance, staking, transaction fees and as a means of exchange on the network. + +**KILT Protocol** - an open-source blockchain protocol for issuing self-sovereign, and verifiable credentials for Web3, the next generation of the Internet. +KILTโ€™s mission is to return control over personal data to its owner, restoring privacy to the individual. + +### Request for Attestation + + +**Trust Anchors** - entities that are trusted to issue or verify claims on the KILT network, such as governments, educational institutions, or professional organizations. + +**Trust Market** - a market that operates on trust and reputation in addition to financial incentives, where buyers and sellers exchange goods or services based on established reputation through digital platforms. +While trust markets offer benefits such as reducing the need for intermediaries, they also face challenges that need to be addressed to maintain trust and fairness in transactions. + +**Transport-Agnostic Messaging Layer** - a messaging system that is not dependent on any particular communication protocol or technology. +It allows different systems or applications to communicate with each other regardless of the underlying transport protocol used, providing a standardized way of exchanging messages across different platforms and technologies. + +**Verifier** - a person, organization, or system that checks the validity and authenticity of an individual's credentials or qualifications. +Verifiers play a critical role in building trust and ensuring that credentials are accurate and reliable. + +## Ecosystem Terms + +**Blockchain Technology** - a type of distributed ledger technology that allows multiple parties to have a synchronized, transparent, and immutable record of transactions. +It uses cryptographic techniques to secure and verify transactions, and it does not require a central authority or intermediaries. + +**Decentralized Network** - a network of computers or nodes that operate without a central authority or control. +In a decentralized network, each node has equal control over the network, and decisions are made through a consensus mechanism, rather than by a single entity or group. + +**Distributed Ledger Technology (DLT)** - a type of digital database that stores information across a network of computers or nodes. +It allows multiple parties to have a synchronized, transparent, and immutable record of transactions, without the need for a central authority or intermediaries. + +**Extrinsic** - a transaction that originates from an external account and affects the state of the blockchain. +It can be used to execute actions on the network, such as transferring funds, making governance decisions, using functionality of the parachain, or interacting with smart contracts. More details about Extrinsics can be found in the [official Polkadot documentation](https://wiki.polkadot.network/docs/learn-extrinsics) + +**Parachains** - sovereign blockchains running in parallel within the Kusama or Polkadot networks, connected via the Relay Chain of that network. +KILT launched as a parachain on the Kusama network in September 2021 and moved to Polkadot in September 2022. +More details about parachains can be found in the [offical Polkadot documentation](https://wiki.polkadot.network/docs/learn-parachains) + +**Polkadot** - a multi-chain network that allows for interoperability between different blockchain protocols, including the KILT Protocol. +More details about Polkadot can be found in the [official Polkadot documentation](https://wiki.polkadot.network/docs/getting-started#what-is-polkadot) + +**polkadot.js** - a JavaScript library that allows developers to interact with Substrate-based blockchains, including KILT Spiritnet and Peregrine. +It is the basis of the KILT SDK and provides many utilities and functions that may be useful for application developers. +More details about polkadot.js can be found in their [official documentation](https://polkadot.js.org/docs/). + +**Substrate** - a modular blockchain development framework used to build custom blockchain solutions, including the KILT Protocol blockchain. +More details about Substrate can be found in the [official Polkadot documentation](https://docs.substrate.io/) + +**Relay Chain** - the central chain in the Polkadot network that coordinates communication and consensus between different parachains. +More details about parachains can be found in the [official Polkadot documentation](https://wiki.polkadot.network/docs/learn-architecture) diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/01_quickstart.md b/versioned_docs/version-0.35.0/develop/01_sdk/01_quickstart.md new file mode 100644 index 000000000..02bd1c8f5 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/01_quickstart.md @@ -0,0 +1,227 @@ +--- +id: quickstart +title: Quickstart +--- + +import CodeBlock from '@theme/CodeBlock'; +import SnippetBlock from '@site/src/components/SnippetBlock'; +import TsJsSnippet from '@site/src/components/TsJsSnippet'; +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import PrintHelloWorld from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/01_print_hello_world.ts'; +import ConnectSpirit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/02_connect_spirit.ts'; +import ConnectPere from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/02_connect_pere.ts'; +import FetchDid from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/03_fetch_did.ts'; +import FetchEndpoints from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/04_fetch_endpoints.ts'; +import FetchEndpointData from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/05_fetch_endpoint_data.ts'; +import VerifyCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/06_verify_credential.ts'; +import Disconnect from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/07_disconnect.ts'; + +Get started with KILT by following this guide, which teaches you to: + +1. Import the **KILT SDK** into your project +2. Connect to the **KILT blockchain** +3. Query a **web3name** to retrieve its **DID** +4. Verify a **credential** using a **DID service** + +:::info Prerequisites + +This quickstart guide provides hands-on experience to enhance your understanding of KILT. +Basic knowledge of JavaScript and command-line tools is recommended. + +::: + +## Setup + +Create a new project and directory and move into the directory by running `mkdir kilt-rocks && cd kilt-rocks`. + + + + +Inside the `kilt-rocks` project directory, install the **KILT SDK**, **Typescript**, **ts-node**, and **Axios** dependencies: + +```bash npm2yarn +npm init -y +npm install @kiltprotocol/sdk-js ts-node typescript axios +``` + +With the required dependencies installed, create a TypeScript file with `touch quickstart.ts`. + + + + +From inside the `kilt-rocks` project directory, install the **KILT SDK**, **Node**, and **Axios** dependencies: + +```bash npm2yarn +npm init -y +npm install @kiltprotocol/sdk-js node axios +``` + +With the required dependencies installed, create a JavaScript file with `touch quickstart.js`. + +To enable ES modules in your project, add `"type": "module"` to the `package.json` file. + + + + +Declare an `async main` function in the `quickstart.ts` file that executes the rest of the code in this quickstart and call the `main()` function by default: + +{/* TODO: Do we need to test this or provide JS/TS equivalent? */} + +```js +async function main() { +} + +main() +``` + +**With the setup completed, let's get started! ๐Ÿ”ฅ** + +### Import the KILT SDK + +Begin by importing the **KILT SDK** and **Axios** at the top of the file: + +```js +import * as Kilt from '@kiltprotocol/sdk-js' +import axios from 'axios' +``` + +Now, you can access the SDK and all its functionality. +The next step is connecting to the **KILT blockchain**. + +### Connect to the KILT Blockchain + +To perform operations that rely on the **KILT blockchain**, such as querying and verifying a credential, you must first connect to the **KILT blockchain**. + +Within the `main` function, configure the SDK to connect to a KILT node using the `Kilt.connect()` method: + + + +

Peregrine is the development blockchain. + Connect to this network for testing and development purposes.

+ + {ConnectPere} + +
+ +

Spiritnet is the production blockchain. + When you are ready to publish your DApp, connect to the Spiritnet network for production purposes.

+ + {ConnectSpirit} + +
+
+ +To ensure proper cleanup, call the `Kilt.disconnect()` function at the bottom of the `main()` function. +You should add all other code before this function call: + + +{Disconnect} + + +By adding `await Kilt.disconnect()`, you ensure that the connection to the blockchain node is properly closed when the script finishes executing, which helps maintain the integrity of your application and is a good practice to follow. + +Run the code by calling the name of the file. +If you set up everything correctly, you should see no output showing that your code connected to the **KILT blockchain**. + + + + +```bash +yarn ts-node quickstart.ts +``` + + + + +```bash +node quickstart.js +``` + + + + +As you add to the code in this file, you can always run it with the same command. + +**Congratulations! ๐Ÿ”ฅ** + +You have connected to a KILT blockchain node. +The next step is to start querying data from the blockchain. + +## Query a KILT Identity + +The following code queries information related to a **web3name** (`kiltnerd123`) and uses it to retrieve the **KILT DID** linked to it. + +Between the `Kilt.connect()` and `Kilt.disconnect()` lines, add the following code: + + +{FetchDid} + + +Try running the code and check the result. + +Did you get the DID? You now have `kiltnerd123`'s DID. +The next step is to see if `kiltnerd123` has any publicly linked KILT credentials to retrieve and verify. + +## Retrieve and Verify a Credential + +A **KILT DID** can expose services that allow external resources to be linked to the DID. +**KILT credentials** represent one type of external resource. + +You can retrieve the **services** attached to kiltnerd123's DID and see if they link to any public credentials to **query** and **verify**. + +Add the following code after the code you added in the previous step but before the `await Kilt.disconnect()`. +It retrieves the services exposed by the DID found for `kiltnerd123`: + + +{FetchEndpoints} + + +The code should print endpoints as JSON. + +The next step is to see if you can find a credential among them. +You do this by selecting one of the endpoints and querying the URL to see if it returns a KILT credential collection as described in the [KiltPublishedCredentialCollectionV1 specification](https://github.com/KILTprotocol/spec-KiltPublishedCredentialCollectionV1). + +Add the following code after the code you added in the previous step but before `await Kilt.disconnect()`: + + + {FetchEndpointData} + + +If the script completes without errors, you retrieved the published credential using the URL specified in the service. + +The next step is to make sure the credential is **valid** and has a valid **structure**. + +The following code outputs a string depending on whether the credential is valid, revoked, or not valid. +Add it before `await Kilt.disconnect()`: + + +{VerifyCredential} + + +Run the code and wait to see if you can retrieve **and** verify one of kiltnerd123's credentials! + +:::info Next steps + +- If you want to explore more of KILT's features, read our [Concepts section](../../concepts/01_what_is_kilt.md). +- If you want to dive deeper into the SDK, read the next section, [the KILT Cookbook](./02_cookbook/01_dids/01_light_did_creation.md). + +::: diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/00_generate_keys.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/00_generate_keys.md new file mode 100644 index 000000000..1553de1f2 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/00_generate_keys.md @@ -0,0 +1,63 @@ +--- +id: key-generation +title: Generate DID keys +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import GenerateKeys from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/00_generate_did_keys.ts'; + +Creating a Decentralized Identifier (DID) on the KILT network involves generating keying material for authentication and encryption. +This guide shows how to create a set of key pairs suitable for generating a KILT DID. + +Before proceeding, it's important to note that this example assumes the usage of the `@kiltprotocol/sdk-js` library along with the `@polkadot/util-crypto` library for cryptographic operations. + +Additionally, it's important to securely store keys and the mnemonic seed phrase. +For production use, ensure that private keys are encrypted and stored safely, while also creating a backup of the mnemonic seed phrase. + +## Derivation paths + +The code example below derives different types of keys from a single account using derivation paths. + +A derivation path is a way to derive a new key from a parent key and is a sequence of indices separated by a delimiter. +The most common delimiter is `/` (forward slash). + +KILT uses the same derivation paths as the underlying Polkadot libraries, using soft and hard key derivation. + +## Soft derivation + +A soft derivation allows someone to potentially figure out the initial account's private key if they know the derived account's private key. +It is also possible to determine that different accounts generated from the same seed are linked to that seed. + +A `/` (single slash) indicates a soft derivation path. +For example, `deal rice sunny now boss cluster team use wreck electric wing deliver/0` is a soft derivation path. + +## Hard derivation + +A hard derivation path does not allow someone to do either of these. +Even if you know a derived private key, it's not possible to figure out the private key of the root address, and it's impossible to prove that the first account is linked with the second. + +A `//` (double slash) indicates a hard derivation path. +For example, `deal rice sunny now boss cluster team use wreck electric wing deliver//0` is a hard derivation path. + +## Creating new accounts from a seed + +This approach allows you to generate various key pairs for authentication, key agreement, assertion methods, and capability delegation from one mnemonic seed phrase. + +To create another account using the same seed, change the number at the end of the string. For example, `/1`, `/2`, and `/3` create different derived accounts. + +Using derivation paths simplifies key management, ensuring that a single mnemonic seed serves as the basis for multiple keys associated with a DID. +This method improves efficiency while maintaining security. +However, it's essential to handle and store private keys securely to prevent unauthorized access and ensure the overall integrity and privacy of the decentralized identity system. + +Below is an example code snippet illustrating the key pair generation for a KILT DID: + + + {GenerateKeys} + + +:::info +This example doesn't show how to store the keys. +It is recommended to store the keys in a secure manner, e.g. only storing the private keys encrypted on disk. +The mnemonic seed phrase can be used to regenerate the keys, so it is recommended to also store the mnemonic in a secure manner and create a backup of it. +::: diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md new file mode 100644 index 000000000..01c59ac8b --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md @@ -0,0 +1,36 @@ +--- +id: light-did-creation +title: Create a Light DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import LightDidSimple from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/01_light_did_simple.ts'; +import LightDidComplete from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/02_light_did_complete.ts'; + +The creation of a light DID requires the generation of some keying material for keys that are to be used for authentication and encryption. +For the sake of ease of use, the example snippets below show how to use keys generated with a `Keyring`, provided also by the `@polkadot/api` library, to generate key pairs that are kept in memory and disappear at the end of the program execution, unless saved to some persistent storage. + +The following is an example of how to create a light DID after creating an authentication keypair. + + + {LightDidSimple} + + +For cases in which an encryption key and some services also need to be added to a light DID: + + + {LightDidComplete} + + +:::info +In KILT, light DIDs are meant to be used in one of two cases: + +1. As *ephemeral, one-time identifiers* when establishing new communication channels with untrusted parties. +2. As an *entrypoint into the KILT ecosystem*, i.e., to obtain one's first credentials and get acquainted with KILT. + +As such, light DIDs do not support updates of any sort, but they retain the same identifier until they are upgraded to full DIDs. +They are not intended for use in complex and/or high-security use cases. +In those situations, a full DID should be used. +Visit the [next section](./02_full_did_creation.md) to see how to create and manage full DIDs. +::: diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/02_full_did_creation.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/02_full_did_creation.md new file mode 100644 index 000000000..389e8e940 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/02_full_did_creation.md @@ -0,0 +1,34 @@ +--- +id: full-did-creation +title: Create a Full DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import FullDidSimple from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/04_full_did_simple.ts'; +import FullDidComplete from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/05_full_did_complete.ts'; +import LightDidMigrate from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/03_light_did_migrate.ts'; + +The following is an example of how to create and write on the blockchain a full DID that specifies only an authentication key. + + + {FullDidSimple} + + +If additional keys or services are to be specified, they can be passed as parameters to the creation transaction. + + + {FullDidComplete} + + +## Upgrade a Light DID to a Full DID + +Another way to obtain a full DID is by upgrading a previously-created light DID. +KILT supports this operation in a way that does not invalidate any credentials that had been issued to the light DID before being upgraded. + +The following code shows how to migrate a light DID to a full DID. +Credentials, presentations, and verifications remain unchanged and remain valid. + + + {LightDidMigrate} + diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/03_full_did_update.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/03_full_did_update.md new file mode 100644 index 000000000..688385841 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/03_full_did_update.md @@ -0,0 +1,15 @@ +--- +id: full-did-update +title: Update a Full DID keys and service endpoints +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import FullDidUpdate from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/07_full_did_update.ts'; + +Once anchored to the KILT blockchain, a full DID can be updated. +For instance, the following snippet shows how to use the `authorizeBatch` function to update the authentication key, remove an old service *and* add a new one for a full DID in the same transaction. + + + {FullDidUpdate} + diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/04_did_query.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/04_did_query.md new file mode 100644 index 000000000..99f68590b --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/04_did_query.md @@ -0,0 +1,22 @@ +--- +id: did-query +title: Resolve a DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DidQuery from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/06_did_query.ts'; + +Querying the state of a DID is called **resolution**. +The entity that queries the DID Document for a given DID, i.e., resolves it, is called a **resolver**. + +The KILT SDK provides such a resolver to use with KILT DIDs, as the snippet below shows: + + + {DidQuery} + + +:::note +The DID resolver can resolve both light and full DIDs. +For a more in-depth explanation about the KILT DID method and resolution, refer to our [specification](https://github.com/KILTprotocol/spec-kilt-did). +::: diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/05_full_did_delete.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/05_full_did_delete.md new file mode 100644 index 000000000..4e4232956 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/05_full_did_delete.md @@ -0,0 +1,29 @@ +--- +id: full-did-delete +title: Delete a Full DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import FullDidDelete from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/11_full_did_delete.ts'; +import FullDidDepositReclaim from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/13_full_did_deposit_reclaim.ts'; + +Once a DID is no longer needed, it is recommended to deactivate it by removing it from the KILT blockchain. +The following snippet shows how to do it: + + + {FullDidDelete} + + +:::warning +Please note that once deleted, a full DID becomes unusable and cannot be re-created anymore. +This means that all credentials obtained with that DID are no longer valid and must be obtained with a different DID if needed. +::: + +## Claim back a DID deposit + +Claiming back the deposit of a DID is semantically equivalent to deactivating and deleting the DID, with the difference that the extrinsic to claim the deposit can only be called by the deposit owner and does not require a signature by the DID subject: + + + {FullDidDepositReclaim} + \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/06_full_did_tx.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/06_full_did_tx.md new file mode 100644 index 000000000..ace83349e --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/06_full_did_tx.md @@ -0,0 +1,57 @@ +--- +id: full-did-batch +title: Build DID Extrinsics +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import FullDidSignTx from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/09_full_did_tx.ts'; +import FullDidBatch from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/08_full_did_batch.ts'; + +DID keys can be used to sign extrinsic. +But not every extrinsic can be signed using a DID. +The Spiritnet blockchain offers two types of extrinsics. + +The first type can only be called using an account. +We call them account extrinsic. +The second callable type are DID extrinsics. +They must be used for all KILT features like creating CTypes, issue attestations, etc. +Since every extrinsic requires fees to be paid, this type needs to be wrapped inside an account extrinsic. +Accounts hold balances and can therefore pay fees and provide deposits. + +This document describes how to sign the DID extrinsics. +The KILT SDK provides two functions for signing DID extrinsics. +The first function signs a single extrinsic while the second one batches multiple extrinsics together. + +## Single extrinsics + +To sign a single extrinsic, you need to provide: + +* the DID that wants to sign the extrinsic (also called *origin* of the extrinsic) + * refer to the [full did creation guide](02_full_did_creation.md) to learn how to create a DID +* [a `SignCallback` that signs the extrinsic](../07_signCallback.md) +* the extrinsic that should be signed and submitted +* and the address of the account that pays for the fees. + + + {FullDidSignTx} + + + +## Batch multiple extrinsics + +Full DIDs can also be used to batch multiple extrinsics that require the signature of the DID. +For instance, a batch could create multiple services with a single submission to the blockchain. +This would save the user the time of generating one additional signature, as multiple extrinsics are batched and signed at once. +The extrinsics are also submitted and executed in the same block. +For more information, see the [official Substrate documentation](https://paritytech.github.io/substrate/master/pallet_utility/pallet/struct.Pallet.html). + +An example of a batch using the `authorizeBatch` is provided below. + + + {FullDidBatch} + + +DIDs have different keys that posses different capabilities. +Each key can only be used to authorize a specific subset of extrinsics. +If extrinsics are batched together that require different DID keys, the `authorizeBatch` function will call the sign callback multiple times. diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/07_did_signature.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/07_did_signature.md new file mode 100644 index 000000000..7c6659fb4 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/07_did_signature.md @@ -0,0 +1,25 @@ +--- +id: did-signature +title: Generate and Verify a DID Signature +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DidSignature from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/10_did_signature.ts'; + +In addition to being used to authorize chain operations, both light and full DIDs have off-chain applications. + +One such applications is generating digital signatures. +As a DID can have multiple keys, in addition to the signature data itself, a DID signature contains information about the signer's DID and key used, so that Verifiers have all the information needed to resolve the DID from the KILT blockchain and use the right key to verify the generated signature. + +The snippet below shows how to generate and verify a DID signature using the KILT SDK. + + + {DidSignature} + + +:::note +Notice that the snippet above takes a `DidDocument` instance to generate the signature. +A `DidDocument` can represent either a light or a full DID. +This means that both light and full DIDs can generate signatures, and the KILT SDK implements the right verification logic depending on whether the signer is a light or a full DID. +::: diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/08_did_export.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/08_did_export.md new file mode 100644 index 000000000..8b53f209d --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/08_did_export.md @@ -0,0 +1,21 @@ +--- +id: did-export +title: Exporting a KILT DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DidExport from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/12_did_export.ts'; + +The DID Document exporter provides the functionality needed to convert an instance of an SDK `DidDocument` object into a document that is compliant with the [W3C specification](https://www.w3.org/TR/did-core/). +This component is required for the KILT plugin for the [DIF Universal Resolver](https://dev.uniresolver.io/). + +## How to use the exporter + +The exporter interface and used types are part of the `@kiltprotocol/types` package, while the actual `DidDocumentExporter` is part of the `@kiltprotocol/did` package. +Both types and DID packages are accessible via the top-level `@kiltprotocol/sdk-js` import. +The following shows how to use the exporter to generate a W3C-compliant DID Document from a given `DidDocument`, which can represent either a light or a full DID. + + + {DidExport} + \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/_category_.json b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/_category_.json new file mode 100644 index 000000000..cd4de73d6 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/01_dids/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "KILT DIDs", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/01_claim.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/01_claim.md new file mode 100644 index 000000000..88f687ba8 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/01_claim.md @@ -0,0 +1,19 @@ +--- +id: web3name-claim +title: Claim a web3name +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import Claim from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/01_claim.ts'; + +A web3name can be claimed if it currently has no owner, using the following snippet as reference. + + + {Claim} + + +The claiming process requires the reservation of a deposit that is freed upon web3name release. + +Once claimed, the web3name will start appearing whenever the DID of its owner is resolved, for instance via the [Universal Resolver](https://dev.uniresolver.io/#did:kilt:4pZGzLSybfMsxB1DcpFNYmnqFv5QihbFb1zuSuuATqjRQv2g). +For more information about web3names and DIDs, see the official [KILT DID Specification](https://github.com/KILTprotocol/spec-kilt-did/blob/main/README.md). diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/02_credential_query.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/02_credential_query.md new file mode 100644 index 000000000..9213f6810 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/02_credential_query.md @@ -0,0 +1,21 @@ +--- +id: credential-query +title: Query Public Credentials for a web3name +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import QueryNameCredentials from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/03_query_name_credentials.ts'; + +web3names are linked to KILT DIDs, and KILT DIDs can define services to expose additional service/information. +One of the possible endpoint types is the [`KiltPublishedCredentialCollectionV1`][kilt-published-credential-collection-v1-type] type. +The type defines the structure to make KILT credentials public and accessible to anyone. + +Because of the relationship between web3names and DIDs, it is possible, given a certain web3name, to retrieve all public credentials that the DID subject identified by that web3name has made available. +Below is a code snippet showing how to do that using the KILT SDK, and how to perform the needed security checks/validation as recommended by the [specification][kilt-published-credential-collection-v1-type]. + + + {QueryNameCredentials} + + +[kilt-published-credential-collection-v1-type]: https://github.com/KILTprotocol/spec-KiltPublishedCredentialCollectionV1/blob/main/README.md diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/03_release.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/03_release.md new file mode 100644 index 000000000..a22050964 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/03_release.md @@ -0,0 +1,48 @@ +--- +id: web3name-release +title: Release a web3name +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import Release from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/04_release.ts'; +import ReclaimDeposit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/05_reclaim_deposit.ts'; + +If a web3name is no longer needed, either the DID owner or the deposit payer can release it, with deposit being released and returned to the original payer. + +## Releasing a Web3name by the DID Owner + +In the case of the DID owner willing to release the web3name, the following snippet provides a reference implementation on how to achieve that. + + + {Release} + + +In the code above, the `releaseWeb3Name` function takes the following parameters: + +* **did**: The DID URI of the owner. +* **submitterAccount**: The keyring pair of the submitter. +* **signCallback**: The sign extrinsic callback function. This function is used to sign the extrinsic, read more that in [the SignCallback section](../07_signCallback.md). + +The function `releaseWeb3Name` uses the KILT SDK to create a *web3name release transaction* using `api.tx.web3Names.releaseByOwner`. +It then authorizes the transaction using the `Kilt.Did.authorizeTx` method and submits the authorized transaction to the blockchain using `Kilt.Blockchain.signAndSubmitTx`. +This process ensures that the release transaction is signed by the DID owner. + + +## Reclaiming a Web3name Deposit by the Deposit Payer + +If the web3name is being released by the deposit payer, the signature of the DID owner is not required; a regular signed extrinsic can be submitted to the KILT blockchain, as shown below. + + + {ReclaimDeposit} + + +In the code above, the `reclaimWeb3NameDeposit` function takes the following parameters: + +* **submitterAddress**: The keyring pair of the submitter. +* **web3Name**: The web3name for which the deposit is to be reclaimed. + +The function creates a web3name deposit reclaim transaction using `api.tx.web3Names.reclaimDeposit` and submits the signed transaction to the blockchain using `Kilt.Blockchain.signAndSubmitTx`. +Since the web3name is being released by the deposit payer, the signature of the DID owner is not required. + +By using these code examples, you can easily release or reclaim the deposit of a web3name, depending on the scenario and the role of the entity initiating the release. diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/04_query.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/04_query.md new file mode 100644 index 000000000..8112e5886 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/04_query.md @@ -0,0 +1,24 @@ +--- +id: web3name-query +title: Resolve a web3name +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import QueryDid from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/02_query_did_name.ts'; + + +A web3name can be resolved in a similar manner to [how a DID is resolved](../01_dids/04_did_query.md). +Resolving the web3name will provide the same information as resolving a DID does. + +To query and retrieve the DID document associated with a web3name, you can use the following code example: + + + + {QueryDid} + + +In the code example above, the `queryDidDocument` function takes a web3Name parameter, which represents the web3name to be resolved. +It internally uses the `api.call.did.queryByWeb3Name` method to query the information of the provided web3name from the blockchain. + +The function then decodes the result using `Kilt.Did.linkedInfoFromChain` to extract the associated DID document and any other linked blockchain accounts. Finally, it returns the resolved DID document. diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/_category_.json b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/_category_.json new file mode 100644 index 000000000..6dab303b4 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/02_web3names/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "web3names", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/01_link.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/01_link.md new file mode 100644 index 000000000..db6735186 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/01_link.md @@ -0,0 +1,87 @@ +--- +id: account-link +title: Link an Account to a KILT DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import SubAccLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/01_sub_link.ts'; +import EthAccLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/01_eth_link.ts'; +import EthWeb3AccLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/01_eth_link_web3js.ts'; +import EthMetamaskAccLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/01_eth_link_metamask.ts'; +import SenderLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/02_sender_link.ts'; + +Sometimes there is the need to link a DID to an account publicly. +The link makes it possible to lookup a DID for an account. +The other directions is also possible. +With a DID you can lookup a list of linked account. + +Linking accounts can be useful when your account should have an identity. +E.g. as a collator, you might want to provide some public information so that delegator can better decide who earned their stake. + +An account can be linked to a DID in one of two ways. +Either the account that sends the transaction links itself to the DID, or the sender is unrelated to the DID and a third account is linked. +In the latter case, a challenge needs to be signed using the third account, to prove ownership. + +The second option is useful in cases where the account that should be linked doesn't own KILT tokens and the transaction is paid for by a third party. +This option also allows to link account schemes that are not native to the Spiritnet Blockchain. +Right now the only other address scheme supported are ethereum accounts. + +:::warning Don't use linked accounts for asset transfers + +Don't use these linked accounts for asset transfers. +Since these accounts are not limited to KILT accounts, but can be used on any chain, the recipient might not be able to access the transferred asset on other chains. +When a link to an account on a different Polkadot chain is created, this account might only be usable on this specific chain. + +If you want transfer assets to a DID have a look at [the asset transfer service](https://github.com/KILTprotocol/spec-KiltTransferAssetRecipientV1). + +::: + +## Linking the sender to a DID + +Link the sender of the transaction to the DID. +The sender will provide the deposit and pay the fees. +They will also be linked to the DID. + + + {SenderLink} + + +## Linking an account to a DID + +Link another account to the DID. +The sender will provide the deposit and pay the fees, but will not be linked to the DID in any way. +The account that should be linked must sign a challenge to prove that the account agrees to be linked. + +The proof contains the DID that the account will be linked to and an expiration date (in terms of blocks), to prevent replay attacks. +The proof will only be valid up until the blocknumber is reached. + +With this option you can link addresses that are supported by the Spiritnet blockchain (Sr25519, Ed25519, Ecdsa), but also ethereum addresses. + + + + + {SubAccLink} + + + + + {EthAccLink} + + + + + {EthWeb3AccLink} + + + + Refer to the Metamask documentation for further information. + + {EthMetamaskAccLink} + + + diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/02_account_name.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/02_account_name.md new file mode 100644 index 000000000..ed7357fb6 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/02_account_name.md @@ -0,0 +1,27 @@ +--- +id: account-name +title: Query the web3name of an Account +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import AccountWeb3NameQuery from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/03_account_web3name_query.ts'; +import AccountWeb3NameQueryNoSDK from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/04_account_web3name_query_no_sdk.ts'; + +For accounts that have been linked to DIDs that have claimed a web3name, the linking feature opens the way to a host of possibilities, e.g., showing the web3name of a collator's account on the [KILT Stakeboard][kilt-stakeboard]. + +This section shows how to perform the `account -> web3name` querying both with and without the support of the KILT SDK. + +## Query an Account's web3name with the KILT SDK + + + {AccountWeb3NameQuery} + + +## Query an Account's web3name without the KILT SDK + + + {AccountWeb3NameQueryNoSDK} + + +[kilt-stakeboard]: https://stakeboard.kilt.io/ diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/03_unlink.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/03_unlink.md new file mode 100644 index 000000000..08711f178 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/03_unlink.md @@ -0,0 +1,30 @@ +--- +id: account-unlink +title: Unlink an Account From a KILT DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DidUnlink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/05_did_unlink.ts'; +import AccountUnlink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/06_account_unlink.ts'; +import ReclaimDeposit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/07_reclaim_deposit.ts'; + +Similar to the way a new account to DID link is created, removing a link can happen in one of three ways: + +1. The DID owner submits a transaction indicating which account to unlink: + + + {DidUnlink} + + +2. The linked account submits a transaction indicating that the link with the DID should be removed: + + + {AccountUnlink} + + +3. The deposit payer submits a transaction indicating that they want to reclaim their deposit, which in turn removes the existing link between the specified account and DID: + + + {ReclaimDeposit} + \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/_category_.json b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/_category_.json new file mode 100644 index 000000000..ac71ff896 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/03_account_linking/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Account <-> KILT DID Relationship", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md new file mode 100644 index 000000000..12d3aba54 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md @@ -0,0 +1,44 @@ +--- +id: ctype-creation +title: Create a CType +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import CreateCType from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/01_create_ctype.ts'; +import FetchCType from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/02_fetch_ctype.ts'; + +Every KILT credential has to conform to a CType. +A CType describes which properties a credential has and what type these properties have. +CTypes must be registered on the Spiritnet blockchain. +To learn more about CTypes, see the [CType concept section](../../../../concepts/05_credentials/02_ctypes.md). + +The creation of a CType in KILT involves two steps: the definition of a CType and the anchoring of its hash on the KILT blockchain. + +:::info DID required +The creator of a CType is required to have a full DID with an attestation key. +To see how to manage DIDs, please refer to the [DID section](../01_dids/03_full_did_update.md). +::: + +:::info CTypes are unique +The creation of a new CType requires the CType hash to be unique. +Before writing a new CType, Attesters should check whether there is already an existing CType which matches their requirements. + +Visit our [CType index repository](https://github.com/KILTprotocol/ctype-index) for a non-exhaustive list of existing CTypes. +::: + +The following snippets show how to create a CType: + + + {CreateCType} + + + +## Retrieve a CType from its ID + +CTypes can be queried directly from any KILT archive nodes. +The following example shows how to query a CType using the SDK: + + + {FetchCType} + diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md new file mode 100644 index 000000000..bd602126f --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md @@ -0,0 +1,21 @@ +--- +id: attestation-request +title: Request an Attestation +--- +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import RequestAttestation from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/03_request_attestation.ts'; + +To obtain credentials, Claimers have to request an attestation for a set of claims from an Attester. +The resulting object is a `Credential`, which can be created following the snippet below. + +This process does not involve any interaction with the KILT blockchain, but is simply a communication channel where the Claimer and the Attester can communicate. + + + {RequestAttestation} + + +:::note +The structure of the claims must respect the schema defined in the specified CType. +Attesters (and Verifiers) will reject claims that fail to verify correctly. +::: \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md new file mode 100644 index 000000000..1a53d3755 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md @@ -0,0 +1,21 @@ +--- +id: attestation-creation +title: Attest a Claim (Issue a Credential) +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import CreateAttestation from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/04_create_attestation.ts'; + +Once an Attester has received a to-be-attested `Credential` from a Claimer, they will typically verify the information in the claim. +If the claims correspond to truth, the Attester will proceed by attesting the root hash of the credential on the KILT blockchain, timestamping the attestation operation. +A deposit is reserved from the balance of the KILT account submitting the creation transaction, which is returned if and when the attestation is removed from the chain. + +:::info +An Attester is required to have a full DID with an attestation key. +To see how to manage DIDs, please refer to the [DID section](../01_dids/03_full_did_update.md). +::: + + + {CreateAttestation} + \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md new file mode 100644 index 000000000..facd14d49 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md @@ -0,0 +1,26 @@ +--- +id: presentation-creation +title: Present a Credential +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import CreatePresentation from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/05_create_presentation.ts'; + +With a valid credential, Claimers can now go to Verifiers to request some service upon providing proof of validity of a certain credential. +The process of presenting one or more credentials to a Verifier is called `Presentation`. + +This step, similar to the [attestation request](./02_attestation_request.md), requires that a communication channel exist between the Claimer and the Verifier so that information about the presentation can be shared. +To verify the revocation status of the presented credential(s), a Verifier must be able to interact with a KILT full node. + +:::info +KILT supports selective disclosure of claims when creating presentations. +This means that given a credential, it is possible for the Claimer to reveal only a subset of its claims, depending on the requirements set by the Verifier. +Check the snippet below to see how that is done using the KILT SDK. +::: + +The Claimer can generate a presentation starting from a credential, optionally specifying the fields to reveal and a presentation challenge, which is useful to prove freshness of the generated presentation. + + + {CreatePresentation} + \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md new file mode 100644 index 000000000..480cc236d --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md @@ -0,0 +1,27 @@ +--- +id: presentation-verification +title: Verify a Credential or a Presentation +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import VerifyPresentation from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/06_verify_presentation.ts'; + +Whether a presentation involves selective disclosure or a whole credential is not technically relevant to Verifiers. +This is because in KILT a presentation **is** a credential. +This means that the logic for Verifiers does not change depending on the case, thus verifying a presentation is as easy as calling one SDK function, like the following code snippet: + + + {VerifyPresentation} + + +:::warning Check if the presenter is the credential subject +Verifying a presentation provides proof that all the information is correct and authentic, and that the credential has not been revoked. +Verifiers still need to match the subject of the credential to the entity that is presenting it. +One way of achieving this is by asking the Claimer to include a challenge in the presentation signature, as shown in the snippet above. +Without a challenge, Verifiers must implement other measures to be certain about the identity of the presenter. +::: + +:::warning Evaluation of the attester's trust is up to the Verifiers +Verifiers must also have a registry of attesters they trust, and verify that the issuer of the credential they are verifying belongs to such list and, where necessary, whether it is still in operation or not, i.e., whether its DID still exists or has been deleted. +::: \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/06_credential_revocation.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/06_credential_revocation.md new file mode 100644 index 000000000..da6ff398b --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/06_credential_revocation.md @@ -0,0 +1,26 @@ +--- +id: attestation-removal +title: Revoke a Credential +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import RevokeCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/07_revoke_credential.ts'; +import ReclaimDeposit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/08_reclaim_attestation_deposit.ts'; + +If the conditions that make a credential valid cease to exist, an Attester can revoke and optionally remove their attestation from the KILT blockchain. +This does not automatically delete the credential from the Claimer's wallet, of course, but it makes it impossible for the Claimer to use the credential in the future. + +Since the attestation creation reserved some KILT tokens from the submitter's balance, removing an attestation would return those funds into the payer's pockets. + + + {RevokeCredential} + + +## Claim Back an Attestation Deposit + +Claiming back the deposit of an attestation is semantically equivalent to revoking and removing the attestation, with the difference that the extrinsic to claim the deposit can only be called by the deposit owner and does not require the Attester's signature: + + + {ReclaimDeposit} + \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/_category_.json b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/_category_.json new file mode 100644 index 000000000..21073c229 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/04_claiming/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "KILT Credentials", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/01_credential_issuance.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/01_credential_issuance.md new file mode 100644 index 000000000..2bd743f12 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/01_credential_issuance.md @@ -0,0 +1,44 @@ +--- +id: public-credential-issuance +title: Credential Issuance +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import CreateCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/01_create_credential.ts'; +import IssueCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/02_issue_credential.ts'; + +As for traditional KILT credentials, public credentials also have their structure defined by a [CType][ctypes-link], although CTypes that can be used to represent information about assets would probably differ from the ones used to represent information about people. + +As mentioned in the section about credentials, the creation of a CType in KILT involves two steps: the definition of a CType and the anchoring of its hash on the KILT blockchain. + +We will not cover the creation of a CType, please refer to the [CType creation](../04_claiming/01_ctype_creation.md) + +## Create and Issue the Credential + +Using the existing CType, the new public credential object can be created with the actual content, and then written to the chain for the rest of the KILT users (and beyond) to consume. + +Creating a public credential is as simple as creating an object that conforms to the required structure of the CType: + + + {CreateCredential} + + +:::note +The creation of the credential object does not require any interaction with the blockchain per se. +This also means that, until the object is written to the blockchain (see below), it cannot be used/retrieved/verified by anyone else, so it is, by all means, not existing. +::: + +Once the credential object is created, it must be written to the blockchain for other people to be able to use it. + + + {IssueCredential} + + +:::info Credential has to be CBOR-encoded! +Given a public credential object, the SDK internally CBOR-encodes it before firing the extrinsic to the blockchain! +This is to save space on credentials that actually benefit from CBOR compression (e.g., if they contain a lot of binary information). +Hence, creating public credentials without the SDK requires the credential to be CBOR-encoded! +::: + +[ctypes-link]: ../../../../concepts/05_credentials/02_ctypes.md diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/02_credential_retrieval.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/02_credential_retrieval.md new file mode 100644 index 000000000..925becd7f --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/02_credential_retrieval.md @@ -0,0 +1,68 @@ +--- +id: public-credential-retrieval +title: Retrieve Public Credentials +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import RetrieveCredentialbyId from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/03_retrieve_credential_by_id.ts'; +import RetrieveCredentialsbySubject from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/04_retrieve_credentials_by_subject.ts'; +import VerifyCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/05_verify_credential.ts'; + +Public credentials have their best capability in the fact that they are, indeed, public by design. +This means that once issued, anyone who has access to an archive or full node for the KILT blockchain can retrieve them, making them very decentralized in nature. + +The KILT SDK exposes different ways to fetch public credentials. + +## Retrieve a Credential by its Identifier + +Some use cases might involve the communication of just the ID of one or more public credentials, e.g., to offload the retrieval of the full credential to the receiver, and save some communication bandwidth. + +The KILT SDK accounts for this use case, and makes it very easy to query a public credential given its ID: + + + {RetrieveCredentialbyId} + + +If a credential with the provided ID cannot be found, then the ID is invalid and should be treated as such by the received. + +## Retrieve All Credentials for an Asset + +Other use cases might work differently: given an asset identified by an [AssetDID][asset-did-concept], a user might want to retrieve all the credentials that have been issued to that asset. + +The KILT SDK makes also this use case very easy: + + + {RetrieveCredentialsbySubject} + + +## Verify a Public Credential + +A third class of use cases might involve users exchanging whole public credentials, for instance when showing some sort of proof. + +This case is also supported by the KILT SDK, and relies on an important feature of public credentials: **the identifier (ID) of a public credential is generated from its content and from the KILT DID of its attester**. +This means that even a minimal change in the content of a public credential object before being shared with other parties, will result in those parties deriving a different identifier from the credential, which will then lead to an error during the verification process. + +Verifying a public credential is shown in the following snippet: + + + {VerifyCredential} + + +What the `verifyCredential` function does internally is the following: + +1. Derive the credential identifier from the provided content and attester information. +2. Fetch the actual credential from the blockchain, as shown in the [section above](#retrieve-a-credential-by-its-identifier), failing if the credential does not exist. +3. [OPTIONAL] Verify that the credential structure matches what the optionally-provided CType defines. +4. Verify that the rest of the fields in the provided credential (i.e., revocation status, identifier, creation block number) match the retrieved credential. + +If all the tests above pass, the credential is considered valid! โœ… + +:::info How are public credentials stored on the blockchain? +Because public credentials need to be public and accessible by everyone, their full content needs to be somehow stored on the blockchain. +Nevertheless, the credential itself is not stored as part of the blockchain database. +Rather, the block number in which the extrinsic is submitted is stored inside the blockchain database, and serves as a "pointer" to the block containing the whole information, that clients (including the SDK) can use. +This represents a very good tradeoff between **security** - because the blockchain itself dictates what the creation block number is for any given public credential - and **storage efficiency** - since the full credential is stored off-chain, accessible via any KILT archive node or indexing service. +::: + +[asset-did-concept]: ../../../../concepts/04_asset_dids.md diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/03_credential_revocation.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/03_credential_revocation.md new file mode 100644 index 000000000..23f9a79f9 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/03_credential_revocation.md @@ -0,0 +1,63 @@ +--- +id: public-credential-revocation +title: Revoke (and remove) Public Credentials +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import RevokeRemoveCredentialById from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/06_revoke_remove_credential_by_id.ts'; +import RevokeCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/07_revoke_remove_credential_by_content.ts'; +import UnrevokeCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/08_unrevoke_credential.ts'; +import ReclaimDeposit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/09_reclaim_deposit.ts'; + +Depending on the use cases, some credentials, as with any other type of credential, might need to be temporarily or permanently revoked. + +The KILT SDK provides different features depending on the needs of the use case. + +## Revoke and Remove a Credential + +As we have seen for [public credential retrieval][credential-retrieval], a credential identifier is sufficient to perform most operations on public credentials. +This is true also for revocation and removal. + +Some use cases might need a revoked credential to remain on chain and marked as revoked, while other use cases might combine together revocation and removal, removing a credential whenever it is to be marked as revoked, fulfilling the same goal of marking the credential as invalid. + +In the former case, the deposit taken at the time when the credential is created is not returned, since the credential is still on chain. +In the latter case, all information about the information is cleared, hence the deposit is returned to its original payer. + + + {RevokeRemoveCredentialById} + + +Because a credential identifier can also be calculated starting from the credential itself and the information about its attester, it is also possible to revoke (and optionally remove) a credential given the credential itself. + + + {RevokeCredential} + + +## Unrevoke a Credential + +For public credentials that have been revoked but not removed from chain, it is possible to un-revoke them, making them valid again. + +For instance, a driving license can be marked as "suspended" for three years, without being completely invalidated. +At the end of the suspension period, it is enabled again by being unrevoked. + +As for revocation, both the credential ID and the whole credential can be used, since the SDK provides the primitives to always obtain the former from the latter, but here we show how the whole credential can be used to generate and submit an un-revocation transaction. + + + {UnrevokeCredential} + + +## Reclaim the Deposit for a Credential + +All the operations mentioned so far, always require the participation of the public credential attester, who must use their assertion key to sign all operations before they are submitted to the KILT blockchain. + +The only operation that can be submitted directly by someone else, as with other places in the SDK, is the transaction to remove a credential and obtain the initial deposit. + +This is, technically speaking, a different operation compared to the one to remove a credential, albeit the two yield the same result: all traces of the credential are removed from the chain and the deposit is returned to its payer. +The difference between the two is about who is authorized to perform the operation: while credential removal requires a DID signature by the original credential creator (a.k.a. issuer), the deposit claiming operation requires a regular transaction signature by the KILT account that paid the original deposit, with no involvement of the original attester. + + + {ReclaimDeposit} + + +[credential-retrieval]: ./02_credential_retrieval.md \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/_category_.json b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/_category_.json new file mode 100644 index 000000000..ddf9ba6eb --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/05_public_credentials/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Public Credentials and AssetDIDs", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/06_messaging/01_messaging.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/06_messaging/01_messaging.md new file mode 100644 index 000000000..406b53343 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/06_messaging/01_messaging.md @@ -0,0 +1,55 @@ +--- +id: messaging_book +title: Generate a Message +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import GenerateRequestCredentialMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/01_generate_request_credential_message.ts'; +import EncryptMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/02_encrypt_message.ts'; +import DecryptMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/03_decrypt_message.ts'; + +KILT defines a [unicast](https://en.wikipedia.org/wiki/Unicast) messaging protocol + +Each of the messages sent is encrypted using the [DID key agreement key](https://www.w3.org/TR/did-core/#key-agreement). +A message consists of the sender's DID URI, the receiver's DID URI, the message type and the body. +There are multiple different message types, each of them with a different structure and containing different information. +In this example we are going to build a `request-credential` message. +The message structure is checked and validated on by the KILT SDK to ensure the users are sending correctly structured messages. + +The following example here will generate a message by constructing the message content. +The message content includes a valid `cTypeHash` and a list of `trusted attesters`. +The message requires a `messageBody`, sender and receiver uri. + + + {GenerateRequestCredentialMessage} + + +## Encryption + +The messages data are encrypted and decrypted using [nacl's](https://github.com/dchest/tweetnacl-js) 'x25519-xsalsa20-poly1305' algorithm, which provides repudiable authenticated encryption based on an x25519 key agreement protocol. +The DID holds keys for the encryption and decryption. +The key is called `KeyAgreement` keys. +They may also be known as encryption keys. + +The content of the object is converted from a serialized string to a byte array, which is passed into the callback function along with the sender's DID and key agreement public key of the receiver. + +The following example here will take a generated message and encrypt the message for the receiver to decrypt later. + + + {EncryptMessage} + + +The encrypted data is converted into a hex string which is known as the ciphertext along with the nonce that was generated during encryption. + +## Decryption + +The decryption takes the encrypted message and decyphers its content. +The following example here will take a encrypted message and decrypt using the private key of the receiver. +Once decrypted, it checks the content is a valid message. +The decrypted data can be used for additional steps. +After decrypting, the receiver may wish to present a credential from the trusted attester list with a given CType. + + + {DecryptMessage} + diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md new file mode 100644 index 000000000..4c5d93b87 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md @@ -0,0 +1,43 @@ +--- +id: replay_protection +title: Protect Against Replay Attacks +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DefineRange from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_01.ts'; +import EvaluateMessageTime from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_02.ts'; +import PurgeTimeout from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_03.ts'; + +Whenever data travels on a public network, even when encrypted or signed, the communicating parties need to make sure they never accept and process a message more than once to protect against exploits by malicious third parties (so-called replay attacks). +When requesting and submitting credential presentations, vulnerabilities for replay attacks can be prevented by requesting that the Claimer sign a unique piece of data as part of the presentation, as shown in the [Verification Cookbook section](../04_claiming/04_presentation_creation.md). + +However, protection against replay attacks can also happen on the message layer. +To help prevent these types of attacks, KILT messages are timestamped and expose a unique identifier as part of their encrypted content, which therefore cannot be tampered with. +It is good practice to impose limits on an acceptable range for timestamps on incoming messages and to keep a record of the ids of previous submissions, which can be purged after their acceptance range has run out. +This way, any resubmission is either rejected because its id is known to the recipient, or because its timestamp is too old. +Below you can find example code of how this could be implemented. + +1. Define acceptance range and set up a record of past submissions: + + + {DefineRange} + + +2. Check record for each incoming message and update if accepted: + + + {EvaluateMessageTime} + + +3. Purge at regular intervals: + + + {PurgeTimeout} + diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/06_messaging/_category_.json b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/06_messaging/_category_.json new file mode 100644 index 000000000..2c3437f16 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/06_messaging/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Messaging", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/07_signCallback.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/07_signCallback.md new file mode 100644 index 000000000..e704093ab --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/07_signCallback.md @@ -0,0 +1,83 @@ +--- +id: signCallback +title: SignCallback +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import SignCallback from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/signCallback/useSignCallback.ts'; +import SignExtrinsicCallback from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/signCallback/useExtrinsicCallback.ts'; +import GetStoreTxSignCallback from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/signCallback/useStoreTxSignCallback.ts'; + +Signing data involves using the private key and therefore needs to be secure. +There are many different options how data could be signed. +You might have the private key stored in memory and are therefore able to simply sign the data. +This is the easiest option but also comes with higher security risk. +Storing the private key on a separate device or inside a sandboxed application can increase security. +But to enable these security options, we need a generic interface to talk to the signer. +This is what the `SignCallback` does. + +The `SignCallback` defines an interface between the SDK and an arbitrary signing strategy. +May it be a ledger, an air gapped phone or your browser extension. +The interface is generic enough to support implementations for all these security measures. + +## The SignCallback Family + +There are three types of signing callbacks: +1. The `SignCallback` is the most general and can be used in almost all cases, except when signing a full DID creation transaction. +2. The `SignExtrinsicCallback` is a special `SignCallback` which can only be used to sign extrinsics. + Thus, every `SignCallback` can also be used as a `SignExtrinsicCallback`. +3. The `GetStoreTxSignCallback` can only be used to sign the creation of a new DID. + +### SignCallback + +The plain `SignCallback` signs arbitrary data. +It is called with `SignRequestData` which contains + +* the `data` as `UInt8Array` that should be signed +* the `keyRelationship` which specifies which DID key must be used +* and the `did` (`DidUri`) which specifies the DID that must sign the data + +The callback is expected to return a `SignResponseData` which contains + +* the `signature` as an `UInt8Array` +* the `keyUri` which identifies the key that was used for signing +* and the `keyType` which specifies the signature scheme that was used (either `sr25519`, `ed25519` or `ecdsa`) + +The signed callback can be used as a closure. +If you already have the private key of the DID stored in the surrounding scope, you can just use this key. + + + {SignCallback} + + +### SignExtrinsicCallback + +The `SignExtrinsicCallback` is a special case of the `SignCallback`. +Signing an extrinsic doesn't require the `keyUri` as a return value since the chain will pick the appropriate key using information from the extrinsic. +The extrinsic that is submitted has a specific `VerificationKeyRelationship`, which defines which key must be used to sign the extrinsic. +Using this relation between extrinsic and key, the chain looks up the public key and verifies the signature. + +The `SignExtrinsicCallback` is called with the same `SignRequestData`, but can return a `SignResponseData` that doesn't contain the `keyUri` but only + +* the `signature` as an `UInt8Array` +* and the `keyType` which specifies the signature scheme that was used (either `sr25519`, `ed25519` or `ecdsa`). + + + {SignExtrinsicCallback} + + +### GetStoreTxSignCallback + +The `GetStoreTxSignCallback` is only used to sign the data that is submitted to the blockchain when a DID is being created. +Because there is no DID identifier before the DID is registered on chain, this callback doesn't receive the DID as a parameter. +There is also no DID document and no public key stored if the DID hasn't yet been created. +Therefore the `keyUri` cannot point to a valid DID key and is not included in the return data. + + + {GetStoreTxSignCallback} + + +## Signing using an extension + +๐Ÿšง This section is work in progress ๐Ÿšง diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/01_backward_compatibility.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/01_backward_compatibility.md new file mode 100644 index 000000000..5cd11e026 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/01_backward_compatibility.md @@ -0,0 +1,93 @@ +--- +id: v29-backward-compatibility +title: Backward Compatibility with Pre-0.29.x Versions +--- + +Depending on how exactly your application interacts with other applications, changes to some data formats and interfaces might mean that conversions are required for them to remain compatible. + +To align with breaking changes to data structures in messaging, credentials, and CTypes, we published version 3.0 of the [Credentials API specification](https://github.com/KILTprotocol/spec-ext-credential-api) that specifies how browser extensions like the [Sporran credential wallet](https://github.com/BTE-Trusted-Entity/sporran-extension) interact with web applications that produce or consume credentials. + +When upgrading to a 0.29.x version of the SDK and to the Credentials API version 3.0, we recommend backward support of Credentials API version 2.0, as supporting only the latest version may result in poor user experience. In what follows, we outline an upgrade strategy for implementers of the Credentials API specification. + +These instructions will also help with translating from and to data types of pre-0.29 SDK versions in other scenarios, such as when sending messages between clients, or when importing older data (e.g. credentials). + +## General Strategy + +Since version 3.0, the specification requires conformant web apps as well as extensions to announce the versions of the API they use, allowing for version negotiation. +Because extensions inject themselves into web pages that signal support for kilt features via the `window.kilt` property, the recommended strategy is to handle backward compatibility on the extension side. +This way, extensions can be upgraded ahead of time, and implement a fallback to a version 2.0 compatible interface if a web application does not signal version 3.0 support. +Following this strategy, backward compatibility on the application side is not strictly necessary. +We recommend notifying users of web apps that have upgraded to version 3.0 if they try to connect with an older extension, pointing them to the need to upgrade their extension to use this app. + +## Message Conversion + +Breaking changes introduced with version 3.0 of the Credential Api exclusively affect selected data types of messages passed between the application backend and extension. +In the attester (credential issuance) flow the message types `submit-terms` and `request-attestation` have changed. +In the verifier (presentation exchange) flow the message type `submit-credential` message is affected. + +Version 3.0 extensions can achieve backward compatibility by translating messages received from and sent to the application which implements an earlier version of the specification. +Below you can find brief descriptions of how these conversions can be implemented. + + + +### `submit-terms` + +When receiving a `submit-terms` message from the old web app, replace the items of the `cTypes` content property with the values of their `schema` properties: + +```ts +interface Old { + cTypes: Array<{ + schema: ICTypeSchema + hash: HexString // duplicates `schema.$id` + owner: DidUri | null // apparently unused + }> + ... +} + +interface New { + cTypes: Array // Note that 0.29 renames ICTypeSchema to ICType + ... +} +``` + + + +### `request-attestation` + +Before encrypting a `request-attestation` type message destined for an older web app, rename `credential` to `requestForAttestation`: + +```ts +interface New { + credential: { claim, ... } + quote?: IQuoteAgreement +} + +interface Old { + requestForAttestation: { claim, ... } + quote?: IQuoteAgreement +} +``` + +:::info +The old `IRequestForAttestation` interface optionally allowed claimers to attach a signature for authentication. +There is no property intended for this purpose on the new interface, as the message encryption scheme already takes care of authentication. +What has changed is that this form of authentication is __not publicly verifiable__. +Attesters can instead require claimers to sign a quote agreement for the purpose of bookkeeping, which contains the credential hash and thus represents a commitment to any claims made. +::: + +### `submit-credential` + +Before encrypting a `submit-credential` message for the older application, replace every item with an object having the property `request` with the value of item itself, and the property `attestation` with the attestation for this credential. + +```ts +interface New extends Array<{ claim, ..., claimerSignature }> {} + +interface Old extends Array<{ + attestation: { claimHash, owner, ... } + request: { claim, ..., claimerSignature } +}> {} +``` diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/_category_.json b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/_category_.json new file mode 100644 index 000000000..a58847a1c --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Upgrading to v0.29", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/index.md b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/index.md new file mode 100644 index 000000000..810b3c4c0 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/index.md @@ -0,0 +1,15 @@ +--- +id: howto-upgrade-v29-index +title: Upgrading to v0.29 +--- + +Version 0.29.0 is the result of our efforts to make the SDK easier to understand and to use. + +As a consequence, quite a few things have changed relative to previous versions. +These pages serve as a reference point for what to consider when upgrading to make your transition as smooth as possible. + + + +Find out what has changed and how to upgrade in the [release notes](https://github.com/KILTprotocol/sdk-js/releases/tag/0.29.0). + +Also make sure to read up on [how to remain interoperable](./01_backward_compatibility.md) with previous versions of the SDK. diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/_category_.json b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/_category_.json new file mode 100644 index 000000000..3eda769a1 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/02_cookbook/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Cookbook", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/01_standalone_setup.md b/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/01_standalone_setup.md new file mode 100644 index 000000000..5ba705d44 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/01_standalone_setup.md @@ -0,0 +1,113 @@ +--- +id: standalone-chain-setup +title: BYOB - Bring Your Own Blockchain +--- + +If you want to have full control over your blockchain deployment, e.g., if you want to reset the state repeatedly or need more funds than a faucet can provide for a single account, you will need to run your own blockchain. +For this purpose, we provide a Docker image which runs in standalone mode. +This means that the blockchain doesn't act as a parachain but as an independent chain. +There is no need to run a Relay Chain and register the KILT chain as a parachain. +This greatly simplifies the setup. + +You only need to start the Docker image: + +```bash +docker run --rm -it -p 9944:9944 -p 9933:9933 kiltprotocol/standalone-node:latest --dev --ws-external --rpc-external +``` + +You should see output similar to the following: + +``` +2022-05-05 13:25:12 KILT Node +2022-05-05 13:25:12 โœŒ๏ธ version 1.6.2 +2022-05-05 13:25:12 โค๏ธ by KILT , 2019-2022 +2022-05-05 13:25:12 ๐Ÿ“‹ Chain specification: Development +2022-05-05 13:25:12 ๐Ÿท Node name: subdued-chair-0035 +2022-05-05 13:25:12 ๐Ÿ‘ค Role: AUTHORITY +2022-05-05 13:25:12 ๐Ÿ’พ Database: RocksDb at /tmp/substrateufCNUV/chains/development/db/full +2022-05-05 13:25:12 โ›“ Native runtime: kilt-kestrel (kilt-kestrel-0.tx3.au4) +2022-05-05 13:25:13 ๐Ÿ”จ Initializing Genesis block/state (state: 0xb4a2โ€ฆ94b3, header-hash: 0x09fcโ€ฆ3a2b) +2022-05-05 13:25:13 ๐Ÿ‘ด Loading GRANDPA authority set from genesis on what appears to be first startup. +2022-05-05 13:25:14 Using default protocol ID "sup" because none is configured in the chain specs +2022-05-05 13:25:14 ๐Ÿท Local node identity is: 12D3KooWMCqWaxXTQbmG9feCe4cMzjCzUKfm5T6VvGDmh8X5QHe9 +2022-05-05 13:25:14 ๐Ÿ“ฆ Highest known block at #0 +2022-05-05 13:25:14 ใ€ฝ๏ธ Prometheus exporter started at 127.0.0.1:9615 +2022-05-05 13:25:14 Listening for new connections on 0.0.0.0:9944. +2022-05-05 13:25:19 ๐Ÿ’ค Idle (0 peers), best: #0 (0x09fcโ€ฆ3a2b), finalized #0 (0x09fcโ€ฆ3a2b), โฌ‡ 0 โฌ† 0 +2022-05-05 13:25:20 Accepted a new tcp connection from 172.17.0.1:56636. +2022-05-05 13:25:23 ๐Ÿ™Œ Starting consensus session on top of parent 0x... +2022-05-05 13:25:23 ๐ŸŽ Prepared block for proposing at 1 (3 ms) [hash: 0x...; parent_hash: 0x09fcโ€ฆ3a2b; extrinsics (1): [0xae1aโ€ฆ0701]] +2022-05-05 13:25:23 ๐Ÿ”– Pre-sealed block for proposal at 1. Hash now 0x..., previously 0x.... +``` + +Congratulations! +You are running your own KILT blockchain. ๐ŸŽ‰ + +The blockchain exposes a RPC endpoint on port `9944`. +You can test that by calling an RPC endpoint using curl. + +```bash +curl -H "Content-Type: application/json" -d '{"id":1, "jsonrpc":"2.0", "method": "system_name", "params":[]}' http://127.0.0.1:9944/ +``` + +This should give you `{"jsonrpc":"2.0","result":"KILT Node","id":1}` as a response. + +The `--dev` parameter provides a pre-funded account which you can use as a faucet, and that has the following mnemonic: `receive clutch item involve chaos clutch furnace arrest claw isolate okay together`. + +You can create the account with the following SDK function: + +```ts +// Creates an ed25519 key by default which is required to access the funds. +const devFaucet = Crypto.makeKeypairFromUri(faucetSeed) +``` + +With the new `devFaucet`, you can transfer funds to other accounts and test all the KILT features that require tx fee payment. + +## Standalone vs. Parachain (Peregrine/Spiritnet) + +The standalone chain is close in functionality to Kilt parachains but there are a few fundamental differences between them. + + + +### Governance + +While governance is an important part of Kilt parachains, it's not used in the standalone version and the **Sudo** pallet replaces it. +None of the following pallets are part of the standalone chain, but they are all part of the parachain runtime: + +* Democracy +* Council +* TechnicalCommittee +* TechnicalMembership +* Treasury +* Scheduler + +### Staking + +Staking is part of the consensus protocol and is used to elect who is allowed to produce blocks. +Parachains need to have this election process as decentralized as possible. +On the other hand, for a standalone development chain, it's not necessary since all nodes are probably controlled by you or your organization. + +### Deployment Complexity + +Deploying a parachain is more complex than deploying a standalone chain. +For the standalone node, a single Docker command is enough. +In contrast, the task of spinning up a parachain is split into three steps. + +1. Setup a Relay Chain with 4 validators. +2. Start and connect your parachain node to the Relay Chain. +3. Register your parachain using the runtime WASM and the genesis state. + +Since these steps are not trivial to execute and take some time to do manually, you can use this [Docker-based setup script](https://github.com/KILTprotocol/local-parachain-setup) to automate the steps. + +### Transaction Encoding + +Before transactions are sent to the chain, they are encoded and signed. +The encoding depends on the runtime and can differ from chain to chain. +Even the same call in the same pallet can have a different encoding for different chains, for instance, the `vest`()` call of the `vesting` pallet: + +| Chain | Encoding of Vesting.vest() | +| ---------- | -------------------------- | +| Spiritnet | `0x2900` | +| Standalone | `0x2100` | diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/02_peregrine_setup.md b/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/02_peregrine_setup.md new file mode 100644 index 000000000..9d23c2544 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/02_peregrine_setup.md @@ -0,0 +1,21 @@ +--- +id: peregrine-chain-setup +title: Connect to Peregrine +--- + +Before connecting to the production Spiritnet, it is recommended to test applications using its canary network _Peregrine_. +In contrast to [running your own blockchain](./01_standalone_setup.md), you will neither have control over the blockchain, nor have any initial funds. + +In this section we will guide you through the process of receiving funds on Peregrine and connecting to one of the network nodes. +Additionally, we explain the difference between the Standalone and Parachain runtimes. + +## Receive Funds + +Since the native token of Peregrine, the _PILT_, does not have any economic value, you can request 100 PILT from the [Peregrine faucet](https://faucet.peregrine.kilt.io). + +## Connect to the Network + +Replace the WebSocket address of [your script](./index.md#set-up-your-project) or application with `wss://peregrine.kilt.io`. + +You can either use your own frontend or the [Polkadot JS Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine.kilt.io%2Fparachain-public-ws#/explorer) to interact with the chain. +For a full list of deployments and services, take a look [here](../../02_chain/03_deployments.md). diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/03_prod_chain_setup.md b/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/03_prod_chain_setup.md new file mode 100644 index 000000000..121c34335 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/03_prod_chain_setup.md @@ -0,0 +1,25 @@ +--- +id: prod-chain-setup +title: Connect to Spiritnet +--- + +For production setups it is important to run your own full node. +Running your own full node has several advantages over relying on a public full node. + +The most important advantage is security. +You rely on the full node to provide you with correct data. +When using a public full node, you rely on a third party: there is no 100% guarantee that the information returned is correct. + +Another important aspect when hosting a full node is availability. +Public full nodes typically do not come with a Service Level Agreement (SLA) and might go down for maintenance or are simply too slow. +With your own full node infrastructure, you can ensure that there is always enough capacity to serve your needs and your customers. + +In our [blockchain section](../../02_chain/01_introduction.md), you can find a [tutorial on how to run your own full node](../../02_chain/04_fullnode.md). + +## Connect to the Network + +Replace the WebSocket address of [your script](./index.md#set-up-your-project) or application with `wss://kilt-rpc.dwellir.com`. + +You can either use your own frontend or the [Polkadot JS Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkilt-rpc.dwellir.com/explorer) to interact with the chain. +Moreover, you can use [Subscan](https://spiritnet.subscan.io/) as a chain explorer. +For a full list of deployments and services, see [here](../../02_chain/03_deployments.md). diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/_category_.json b/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/_category_.json new file mode 100644 index 000000000..88da89b23 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Chain Setup for Development", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/index.md b/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/index.md new file mode 100644 index 000000000..76cb5d16e --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/03_chain_setup/index.md @@ -0,0 +1,24 @@ +--- +id: dev-chain-setup +title: Chain Setup for Development +--- + +If you want to develop solutions that integrate KILT, such as a dapp, a wallet, or a Web3 login, you will need a blockchain environment that can be used for development and testing without requiring you to buy actual KILT tokens. +For that purpose, you can either use the public KILT Peregrine testnet or run your own development blockchain. + +The **Peregrine** network is a parachain that is similar to Spiritnet (our mainnet) in functionality, but its coin, the PILT, doesn't hold any monetary value. +Any new features that we plan to add to our Spiritnet runtime will first undergo a testing period on Peregrine. +This gives developers like you the chance to test your software with any new features before they are available on Spiritnet. + +Nevertheless, there are a scenarios where a public network (that everyone else is also using) is not ideal. +For instance, if you need more funds than the faucet can provide, or if you need to reset the state of the blockchain at any time, you will need to setup your own little KILT blockchain. + +In this section, we will guide you through the process of +1. [Running your own KILT blockchain](./01_standalone_setup.md) +2. [Connecting to the Peregrine test network](./02_peregrine_setup.md) +3. [Connecting to the Spiritnet production network](./03_prod_chain_setup.md) + +## Set up your Project + +We expect you to already have a small project which can connect and potentially interact with a KILT blockchain given the WebSocket address of a KILT node. +If that is not the case, please take a look at our [Quickstart section](../01_quickstart.md) which will provide you with all necessary means to create and run a basic script. diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/01_nodejs.md b/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/01_nodejs.md new file mode 100644 index 000000000..57a4acf2e --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/01_nodejs.md @@ -0,0 +1,29 @@ +--- +id: howto-integrate-nodejs +title: NodeJS +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import QueryAccountName from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/03_account_web3name_query.ts'; + +NodeJS is natively supported and doesn't require any additional setup. + +Have a look at these example `package.json` and `index.js` files for reference: + +```json +{ + "name": "kilt-sdk-node-test", + "type": "module", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "@kiltprotocol/sdk-js": "0.35.0" + } +} +``` + + + {QueryAccountName} + diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/02_browser.md b/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/02_browser.md new file mode 100644 index 000000000..b0a291ec4 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/02_browser.md @@ -0,0 +1,45 @@ +--- +id: howto-integrate-browser +title: Browser +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Our JavaScript SDK (`@kiltprotocol/sdk-js`) is ready to be used in a browser context. For rapid prototyping of simple web apps, we provide a code bundle of the entire SDK which you can embed in a site by adding the following script tag: + +```html + +``` + +The SDK's functions then become available via a new `kilt` property on the global `window` object. + +To get started with your first **React application** using KILT, we recommend using either the [KILT Distillery](./03_distillery.md) CLI tool for bootstrapping or a framework like [Vite](https://vitejs.dev) or [Next.js](https://nextjs.org) that takes away some of the complexity in building and testing a React application. You can find a broader selection of popular React-powered frameworks on the [React project's homepage](https://react.dev/learn/start-a-new-react-project). + +After completing the respective tool's recommended steps to initialize your project, simply add the SDK to your dependencies and you are ready to hack away! + +:::info + +You should of course familiarize yourself with the tool of your choice, but these commands have served us well in the past: + + + +```bash +yarn create vite my-kilt-app --template react-ts +cd my-kilt-app +yarn add @kiltprotocol/sdk-js +``` + + + + +```bash +yarn create next-app my-kilt-app +cd my-kilt-app +yarn add @kiltprotocol/sdk-js +``` + + + + +::: diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/03_distillery.md b/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/03_distillery.md new file mode 100644 index 000000000..f61dd9fb2 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/03_distillery.md @@ -0,0 +1,12 @@ +--- +id: howto-integrate-distillery +title: KILT Distillery +--- + +Different types of projects can be bootstrapped using our [KILT distillery CLI](https://github.com/KILTprotocol/kilt-distillery-cli). + +Please read the README.md file for more information, but if you are impatient you can execute this command and follow the instructions: + +```bash +npx git+https://github.com/KILTprotocol/kilt-distillery-cli +``` diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/_category_.json b/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/_category_.json new file mode 100644 index 000000000..6ca72770c --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Integrate the KILT SDK", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/index.md b/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/index.md new file mode 100644 index 000000000..bac181a29 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/04_integrate/index.md @@ -0,0 +1,11 @@ +--- +id: howto-integrate-index +title: How to Integrate +--- + +Integrating with KILT is easy. +If your project needs to integrate KILT in a frontend and/or a backend application, we've got you covered! + +These pages are dedicated to helping you set up a [NodeJS application](./01_nodejs.md) or [web app](./02_browser.md). + +We also introduce the [KILT distillery CLI tool](./03_distillery.md) which helps you quickly spin up your first KILT-based project. diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/05_troubleshoot.md b/versioned_docs/version-0.35.0/develop/01_sdk/05_troubleshoot.md new file mode 100644 index 000000000..369a3e616 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/05_troubleshoot.md @@ -0,0 +1,36 @@ +--- +id: troubleshoot-sdk +title: Troubleshoot +--- + +Solutions and workarounds for common or unresolved issues. + +## Webpack < 5 used to include polyfills + +``` +ERROR in ./node_modules/cbor/lib/commented.js 3:15-32 +Module not found: Error: Can't resolve 'stream' in 'node_modules/cbor/lib' + +BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default. +This is no longer the case. +Verify if you need this module and configure a polyfill for it. +``` + +### Solution + +The problem occurs because one of the dependecies you are using in your project (or used by a library you depend on) relies on NodeJS built-ins which are not available in a browser context. +You should aim to identify and replace these dependencies with browser-compatible alternatives. + +You might see the above error when using older versions of the KILT SDK with `create-react-app`. Make sure that you are using `@kiltprotocol/sdk-js` version 0.33.0 and above, which work in a browser context out-of-the-box. + +If the affected dependencies cannot be removed or replaced, you may need to look into setting up polyfills for the required NodeJS built-ins. + +## `redeclaration of import Buffer` + +``` +Uncaught SyntaxError: redeclaration of import Buffer +``` + +### Solution + +Your project might be using polyfills for the NodeJS built-in `Buffer`, which can cause conflicts with some polkadot-js libraries such as `@polkadot/react-identicon`. You can try upgrading the SDK and its dependencies to their latest versions. It's possible that upgrading will allow you to drop these polyfills from your configuration. diff --git a/versioned_docs/version-0.35.0/develop/01_sdk/_category_.json b/versioned_docs/version-0.35.0/develop/01_sdk/_category_.json new file mode 100644 index 000000000..13d35e4e8 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/01_sdk/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "SDK", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/02_chain/01_introduction.md b/versioned_docs/version-0.35.0/develop/02_chain/01_introduction.md new file mode 100644 index 000000000..20b625490 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/02_chain/01_introduction.md @@ -0,0 +1,10 @@ +--- +id: introduction +title: Introduction +--- + +The section covers KILT chain specific topics. + +* Learn about the different [KILT pallets](./02_pallets/01_did.md) (still a WIP) +* Learn about the different [KILT deployments](./03_deployments.md) +* Learn how to run a [KILT full node](./04_fullnode.md) diff --git a/versioned_docs/version-0.35.0/develop/02_chain/02_pallets/01_did.md b/versioned_docs/version-0.35.0/develop/02_chain/02_pallets/01_did.md new file mode 100644 index 000000000..d0e8c3385 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/02_chain/02_pallets/01_did.md @@ -0,0 +1,115 @@ +--- +id: pallet-did +title: DID pallet +--- + +In KILT a DID is a decentralized identifier that the user owns and controls. +It consists of a unique set of keys that can be used for different operations on the blockchain. +For an in-depth explanation see the [KILT DID spec](https://github.com/KILTprotocol/kilt-did-driver/blob/master/docs/did-spec/spec.md). + +A DID may be a "light" DID, which is not stored on-chain, or a "full" on-chain DID. +A light DID is issued by default, with the keys stored locally on your device. +By upgrading this to a full DID registered on the blockchain, all the keys associated with it can be retrieved from the KILT blockchain storage. + +A full DID can then be used to perform certain on-chain actions which include: + +* Writing CTypes to the chain +* Writing attestations to the chain +* Setting delegations +* Doing key rotations on the DID keys + +## Register a Full DID + +A full DID is needed if the user wants to become an Attester or wants to setup delegations. +A full DID also allows the user to embed a list of URLs, known as services, into the DID document so that they can be retrieved from the chain as part of the DID document. +To create a full DID the user first has to create some keys, and optionally some services: + +* one authentication key for signing extrinsics from your DID +* zero or more key agreement keys for encrypting messages that are sent to you +* (optional) one attestation key for signing attestations +* (optional) one delegation key for authorizing delegations +* (optional) service that point to external hostings for others to find + +After the relevant components have been created, they are ready to write the DID to the KILT blockchain. +The user then has to create the `did::create` extrinsic and sign it with any KILT account that has enough funding to pay both the transaction fees and the DID deposit. +The extrinsic consists of + +* The `DidCreationDetails` object containing keys, services and the account id of the submitter for the creation +* The `DidSignature` which is a signature using your authentication key over the scale encoded `DidCreationDetails` from above +* A regular signature authenticating the sender of the extrinsic + +The DID owner and the submitter can be two different parties. +This allows the creation of a DID without having to pay any fees or deposits. +Beware that this also means that the DID creator gives up some power over the DID: The submitter who pays the deposit will be able to delete the DID from the blockchain and claim back its deposit. +Once the `did::create` extrinsic is submitted and executed, the DID is written to the chain. + +## Use a Full DID + +Once the DID is successfully registered on chain, it can be used to perform certain on-chain actions that are not possible to do with a regular account. +This includes the handling of attestations and CTypes, setting up trust hierarchies through delegations, managing web3names and much more. + +Those actions need to be signed by the DID before they can be submitted to chain by any account that the DID owner specifies when signing. +We are naming those actions "DID-Calls". +To submit those there is a special extrinsic called `submit_did_call`. + +The process of doing any DID-Call is always the same: + +* Construct the actual call you want to execute including all arguments of that extrinsic. +* Wrap the call in a `DidAuthorizedCallOperation` together with the + * Senders DID to indicate who wants this operation to happen + * Senders DID tx_counter + 1 to prevent replay attacks + * Current block number to prevent the operation being submitted too far in the future + * Account of the submitter to allow the DID owner to specify who is allowed to submit +* Create a signature over the `DidAuthorizedCallOperation` by scale-encoding it and signing it using the appropriate key + * Most operations require the authentication key of the DID to be used + * Managing Attestations requires the attestation key + * Managing Delegations requires the delegation key +* Construct the `submit_did_call` extrinsic consisting of + * The `DidAuthorizedCallOperation` + * The DID signature +* Pass the call over to the submitter who can now sign and submit it to the chain + * The submitter will have to pay for all fees and deposits that result from the operation + * In general the submitter will have the power to delete all on-chain objects to reclaim their deposit +* The chain now checks that + * The submitter's signature is correct + * The submitter is the one specified in the `DidAuthorizedCallOperation` + * The DID signature is correct + * The tx_counter is valid (current tx_counter + 1) + * The blocknumber is not older than an hour (given 12s block time) +* After that the actual call gets dispatched with a special `DidOrigin` + * This allows the executer of the actual call to get the DID and the account of the submitter + +## Update a Full DID + +There is a set of extrinsics available to update a full DID. +These are: + +* `set_authentication_key` +* `set_delegation_key` +* `remove_delegation_key` +* `set_attestation_key` +* `remove_attestation_key` +* `add_key_agreement_key` +* `remove_key_agreement_key` +* `add_service_endpoint` +* `remove_service_endpoint` +* `delete` + +All of them have to be authenticated using the DID that is updated following the process described above. + +## What About the Deposit? + +When writing a DID to the chain the submitter of the extrinsic has to pay a deposit. +The base deposit is currently 2 KILT. +For additional used storage, for example by adding more services, more tokens are taken as deposit, depending on the amount of additional storage taken. +Freeing up storage reduces the deposit. +This is to incentivize deleting unused DIDs or keys to reduce the total storage of the chain. +The deposit is always bound to the account that submitted the extrinsic to create the DID, and not to the DID itself. +Consequently there are also two ways of reclaiming the deposit: + +1) The DID owner decides to delete the DID using the `did::delete` extrinsic. + This call needs to be authorized by the DID and can therefore be submitted by any account. + Despite the fact that this account can differ from the deposit owner, the deposit will always be reimbursed to the account that paid for it. +2) The deposit owner can decide to claim their deposit back using the `did::reclaim_deposit` extrinsic. + This will also cause the DID to be fully deleted but it doesn't require a signature from the DID. + Only the signature of the account that created the DID is needed for this. diff --git a/versioned_docs/version-0.35.0/develop/02_chain/02_pallets/_category_.json b/versioned_docs/version-0.35.0/develop/02_chain/02_pallets/_category_.json new file mode 100644 index 000000000..fd547d13d --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/02_chain/02_pallets/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "KILT Pallets", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/02_chain/03_deployments.md b/versioned_docs/version-0.35.0/develop/02_chain/03_deployments.md new file mode 100644 index 000000000..e1ae294c1 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/02_chain/03_deployments.md @@ -0,0 +1,32 @@ +--- +id: deployments +title: Deployments and Services +--- + +KILT has two public deployments: a production one, called **Spiritnet**, and a test/dev one, called **Peregrine**. +To learn more about how to set up a node for either environment, please check our [fullnode set up guide](./04_fullnode.md). + +**Spiritnet** is the production blockchain, and has been live since September 2021. + +**Peregrine** is the public testnet, which can be used to build and test products that use the KILT blockchain, before switching to Spiritnet. + +| Service | Spiritnet | Peregrine | +| :--------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------: | +| Faucet | - | [Peregrine Faucet][pere-faucet] | +| Public Endpoints | [BOTLabs: wss://spiritnet.kilt.io][spirit-wss-kilt]
[OnFinality: wss://spiritnet.api.onfinality.io/public-ws][spirit-wss-onfinality]
[Dwellir: wss://kilt-rpc.dwellir.com][spirit-wss-dwellir] | [BOTLabs: wss://peregrine.kilt.io][pere-wss-kilt] | +| Wallet | [Sporran](https://www.sporran.org/) | [GitHub](https://github.com/BTE-Trusted-Entity/sporran-extension/releases) (manual loading into the browser) | +| Staking UI | Collators' performance (view only): [Stakekilt](https://stakekilt.com/)
Delegation staking platform: [Stakeboard](https://stakeboard.kilt.io) | - | +| Governance UI | [Polkassembly][spirit-polkassembly] | - | +| Chain Explorer | [Subscan](https://spiritnet.subscan.io) | - | +| w3n Service | [w3n.id](https://w3n.id) | [test.w3n.id](https://test.w3n.id/) | +| Link Accounts | [linking.trusted-entity.io](https://linking.trusted-entity.io/) | [test.linking.trusted-entity.io](https://test.linking.trusted-entity.io/) | +| DIDsign | [didsign.io](https://didsign.io/) | [test.didsign.io](https://test.didsign.io/) | +| SocialKYC | [socialkyc.io](https://socialkyc.io/) | [test.socialkyc.io](https://test.socialkyc.io/) | + + +[spirit-polkassembly]: https://kilt.polkassembly.network +[spirit-wss-kilt]: https://polkadot.js.org/apps/?rpc=wss://spiritnet.kilt.io +[spirit-wss-onfinality]: https://polkadot.js.org/apps/?rpc=wss://spiritnet.api.onfinality.io/public-ws +[spirit-wss-dwellir]: https://polkadot.js.org/apps/?rpc=wss://kilt-rpc.dwellir.com +[pere-faucet]: https://faucet.peregrine.kilt.io +[pere-wss-kilt]: https://polkadot.js.org/apps/?rpc=wss://peregrine.kilt.io diff --git a/versioned_docs/version-0.35.0/develop/02_chain/04_fullnode.md b/versioned_docs/version-0.35.0/develop/02_chain/04_fullnode.md new file mode 100644 index 000000000..80264abf7 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/02_chain/04_fullnode.md @@ -0,0 +1,227 @@ +--- +id: fullnode-setup +title: Set Up a KILT Full Node +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +We will guide you through the process of setting up and connecting to a KILT full node. +In contrast [to a collator](../../participate/01_staking/01_become_a_collator/03_setup_node.md), full nodes do not author blocks. +They act as a backend for websites and help to verify new blocks or validate extrinsics (e.g., coin transfers and other transactions) directly on the network without relying on a centralized infrastructure provider. + +## Setup + +There are currently two different runtimes (i.e., two different parachain environments) that a KILT full node can be part of: + +- **Spiritnet**: the official public network, which contains only stable and thoroughly-tested features +- **Peregrine**: the public test network whose runtime is as close to that of Spiritnet as possible. It can be used to test applications that use KILT before connecting them to the production Spiritnet chain, which requires tokens that have real monetary value + +Each runtime has its own benchmark measurements. + +:::info +The remainder of this guide will focus on the official **Spiritnet**. +Nevertheless, we recommend trying out the setup on our Peregrine testnet first. +Hence, at each step where it is applicable, we indicate what differs between the Peregrine and Spiritnet configuration for the full node to join either network. +::: + +### WASM Runtime Execution + +A KILT full node should use the `--execution=wasm` parameter for both the Relay Chain and parachain collation. +The alternative to WASM runtime execution is native runtime execution, which might be faster but can, in some cases, deviate from the WASM execution logic and result in a different state. +When this happens, the full node will crash and will stop synchronizing with the network. +Since the WASM runtime logic is part of the blockchain state itself and hence represents the single source of truth, all nodes should execute the WASM version of the runtime logic. + +### Specify the Right Chainspec + +The `--chain` parameter indicates which blockchain the KILT full node will join. +This parameter must be specified for both the parachain **and** the Relay Chain, since both chains are, as a matter of fact, separate blockchains. +The KILT parachain accepts an additional parameter to select the environment to use for the WASM runtime execution. +This can either be `peregrine` or `spiritnet`. + +Hence, to start a full node for the Spiritnet network, the parameter would be `--chain=spiritnet`. +Unfortunately, there is no hardcoded chain spec for the Peregrine network, so the full path of the chainspec file must be provided `--chain=/node/dev-specs/kilt-parachain/peregrine-kilt.json`. +Please refer to the [KILT node repository](https://github.com/KILTprotocol/kilt-node/blob/master/chainspecs/peregrine/peregrine-paseo.json) or the [Docker image](https://hub.docker.com/r/kiltprotocol/kilt-node/tags) for more information. + +### Specify the Blockchain Storage Path + +The `--base-path` parameter specifies where all the persistent files must be stored. +By default, the session keys will also be stored in the *base path*, but we recommend separating them from the other files. +This makes sure that the keyfiles are not accidentally lost or published when the blockchain database is either backed up or restored. +You can configure where to store the session keys using the `--keystore-path` option. +Since the collator will collate only for the parachain, there is no need to add this to the Relay Chain part of the command. + +## Join the Network + + + + + +### Build the Full Node + +In order to build the KILT full node executable, you need to have [rustup and Rust installed](https://www.rust-lang.org/tools/install). +After cloning the repository, you can build the executable by running the `cargo build` command below from the root directory. + +```bash +# Clone the repository +git clone https://github.com/KILTprotocol/kilt-node.git +# Check out master branch +git checkout master +# Build the executable from source enabling all the optimizations with --release. +cargo build --release -p kilt-parachain +``` + +:::info +You must not use the default `develop` branch to build the executable. +Instead, the [latest release](https://github.com/KILTprotocol/kilt-node/releases) from `master` should be used. +::: + +The compiled executable can be found in `./target/release/kilt-parachain` after the build process completes successfully. + +### Run an Archive Node + +To run an Archive full node, add the option `--pruning archive` to the command. + + + + + +```bash +./target/release/kilt-parachain \ + --chain=spiritnet \ + --runtime=spiritnet \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-external \ + --name="name of full node" \ + --execution=wasm \ + --pruning archive \ + -- \ + --chain=polkadot \ + --execution=wasm +``` + + + + +```bash +./target/release/kilt-parachain \ + --chain=/node/dev-specs/kilt-parachain/peregrine-kilt.json \ + --runtime=peregrine \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-external \ + --name="name of full node" \ + --execution=wasm \ + --pruning archive \ + -- \ + --chain=/node/dev-specs/kilt-parachain/peregrine-relay.json \ + --execution=wasm +``` + + + + + + + +### Run an Archive Node + +The full node can also be started as a Docker container. +To expose the WebSockets ensure that the `--rpc-external` flags is set. + +To run an Archive full node add the option `--pruning archive` to the command. + +First, you can fetch the latest pre-built image: + +```bash +docker pull kiltprotocol/kilt-node:latest +``` + +Once you have the image, you can spin up the container. +Make sure to choose whether you want to start a full node for Peregrine or Spiritnet by selecting the correct runtime and chain. + + + + + +```bash +docker run -v kilt-node-data:/data kiltprotocol/kilt-node:latest \ + --base-path=/data/para \ + --chain=spiritnet \ + --runtime=spiritnet \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-external \ + --name="name of full node" \ + --execution=wasm \ + --pruning archive \ + -- \ + --base-path=/data/relay \ + --chain=polkadot \ + --execution=wasm +``` + + + + +```bash +docker run -v kilt-node-data:/data kiltprotocol/kilt-node:latest \ + --base-path=/data/para \ + --chain=/node/dev-specs/kilt-parachain/peregrine-kilt.json \ + --runtime=peregrine \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-external \ + --name="name of full node" \ + --execution=wasm \ + --pruning archive \ + -- \ + --base-path=/data/relay \ + --chain=/node/dev-specs/kilt-parachain/peregrine-relay.json \ + --execution=wasm +``` + + + + + + + +## Sync the Blockchain State + +Once started, the full node needs to fully sync up with both the parachain and the Relay Chain states. +Depending on the size of both blockchain states and the node hardware specs, it may take from a number of hours to a few days for the node to fully synchronize. +More details can be found in the [Polkadot network documentation](https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#synchronize-chain-data). + +:::note Example of node sync + +```Example of node sync +2021-06-17 02:34:34 ๐Ÿ” Discovered new external address for our node: /ip4/100.102.231.64/tcp/30333/ws/p2p/12D3KooWLE7ivpuXJQpFVP4fuuutAqEsk8nrNEpuR3tddqnXgLPB +2021-06-17 02:34:36 โš™๏ธ Syncing 409.2 bps, target=#8062689 (5 peers), best: #3477 (0x63adโ€ฆe046), finalized #3072 (0x0e4cโ€ฆf587), โฌ‡ 153.2kiB/s โฌ† 12.9kiB/s +2021-06-17 02:34:37 ๐Ÿ” Discovered new external address for our node: /ip4/100.111.175.0/tcp/30333/ws/p2p/12D3KooWLE7ivpuXJQpFVP4fuuutAqEsk8nrNEpuR3tddqnXgLPB +2021-06-17 02:34:38 ๐Ÿ” Discovered new external address for our node: /ip4/100.100.176.0/tcp/30333/ws/p2p/12D3KooWLE7ivpuXJQpFVP4fuuutAqEsk8nrNEpuR3tddqnXgLPB +2021-06-17 02:34:41 โš™๏ธ Syncing 386.2 bps, target=#8062690 (7 peers), best: #5409 (0x1d76โ€ฆ8c3d), finalized #5121 (0x8ad1โ€ฆb6dc), โฌ‡ 96.1kiB/s โฌ† 10.9kiB/s +2021-06-17 02:34:46 โš™๏ธ Syncing 394.8 bps, target=#8062691 (11 peers), best: #7383 (0x0689โ€ฆ6f1e), finalized #7168 (0x72a9โ€ฆ8d8c), โฌ‡ 352.9kiB/s โฌ† 5.1kiB/s +2021-06-17 02:34:51 โš™๏ธ Syncing 347.0 bps, target=#8062692 (12 peers), best: #9118 (0x66fcโ€ฆcce3), finalized #8704 (0x14c9โ€ฆ705e), โฌ‡ 62.7kiB/s โฌ† 1.7kiB/s +``` + +::: diff --git a/versioned_docs/version-0.35.0/develop/02_chain/_category_.json b/versioned_docs/version-0.35.0/develop/02_chain/_category_.json new file mode 100644 index 000000000..1b41abda0 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/02_chain/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Chain", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/01_welcome.md b/versioned_docs/version-0.35.0/develop/03_workshop/01_welcome.md new file mode 100644 index 000000000..6ed35f2f3 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/01_welcome.md @@ -0,0 +1,38 @@ +--- +id: welcome +title: ๐Ÿ‘‹๐Ÿป Welcome +--- + + + + +SDK version **0.35.0**. + +:::info What you can expect to learn + +๐Ÿ“ฆ **Topics**: [KILT SDK](https://github.com/KILTprotocol/sdk-js) essentials, basic credential workflow. +This includes creating a CType and a claim, attesting a claim, and finally verifying the credential. + +โณ **Duration**: 15-45 minutes. + +๐Ÿค“ **Prerequisites**: + +- Basic JavaScript or TypeScript knowledge. +- [Node.js](https://nodejs.org/) installed. Any stable LTS version >= 16.0. + +โ“ **Questions?** Join our [developer community channel](https://discord.gg/hX4pc8rdHS)! + +::: + +## Welcome, curious mind! + +In this tutorial, you will: + +โœ” Get familiar with the essential concepts in KILT: accounts, DIDs, CTypes, claims, credentials, and more. + +โœ” Use the KILT SDK to implement the basic flow of a KILT claim, from creation until verification. +You'll create a claim as a Claimer, attest it as an Attester and verify it as a Verifier. + +โœ” Use the KILT SDK to write onto and read from the KILT blockchain. + +Ready? Let's go! \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/02_setup.md b/versioned_docs/version-0.35.0/develop/03_workshop/02_setup.md new file mode 100644 index 000000000..c63d7c19e --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/02_setup.md @@ -0,0 +1,108 @@ +--- +id: setup +title: ๐ŸŽ’ Setup +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Project setup + +Create a new project in a fresh directory and navigate into it by running `mkdir kilt-rocks && cd kilt-rocks`. + + + +The dependencies needed are the following: + +- [KILT SDK-JS](https://github.com/KILTprotocol/sdk-js#readme) - for KILT functionality +- [dotenv](https://github.com/motdotla/dotenv#readme) - to load environment variables +- If you use Typescript and not JavaScript [ts-node](https://www.npmjs.com/package/ts-node) and [Typescript](https://www.typescriptlang.org/) - to execute TS code + + + + + Initialize the project and install dependencies. + + ```bash npm2yarn + npm init -y + npm install @kiltprotocol/sdk-js dotenv ts-node typescript + ``` + + + + + Initialize the project and install dependencies. + + ```bash npm2yarn + npm init -y + npm install @kiltprotocol/sdk-js dotenv + ``` + + + + +## Project Folder + + + + + Create the following remaining files and folders to end up with the folder structure below: + + ``` + โ””โ”€ kilt-rocks/ # project + โ”œโ”€ attester/ # all attester code + โ”œโ”€ claimer/ # all claimer code + โ”œโ”€ verify.ts # all verifier code + โ””โ”€ .env # environment variables + ``` + ``` + mkdir attester claimer && touch verify.ts .env + ``` + + + + + + Create the following remaining files and folders to end up with the folder structure below: + + ``` + โ””โ”€ kilt-rocks/ # project + โ”œโ”€ attester/ # all attester code + โ”œโ”€ claimer/ # all claimer code + โ”œโ”€ verify.js # all verifier code + โ””โ”€ .env # environment variables + ``` + ``` + mkdir attester claimer && touch verify.js .env + ``` + + + + +## PILT Tokens + +This workshop interacts with the Peregrine test blockchain, which requires you to pay for each transaction with Peregrine Kilt (PILT) tokens. + +But don't worry. PILT tokens have no value, and you can request them from the [faucet](https://faucet.peregrine.kilt.io). + +## Blockchain Connection + +Before using any SDK functionality, you must initialize and configure the Kilt SDK. + +As this workshop uses the [Peregrine Testnet](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine.kilt.io%2Fparachain-public-ws%2F#/explorer) you use its address whenever using the SDK to interact with the Kilt blockchain. + +You do this by calling the following function: + +```JavaScript +await Kilt.connect({address}) +``` + +Where `address` is the address of the full node you want to connect to, which for this workshop, is `wss://peregrine.kilt.io`. + +For convenience, add the address to the `.env` file. + +```env title=".env" +WSS_ADDRESS=wss://peregrine.kilt.io +``` + +That's it for the basic setup - You're good to go! \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/03_overview.md b/versioned_docs/version-0.35.0/develop/03_workshop/03_overview.md new file mode 100644 index 000000000..bcb80e36d --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/03_overview.md @@ -0,0 +1,96 @@ +--- +id: overview +title: ๐Ÿ‘“ Overview +--- + +This tutorial runs through the full story of a claim. + +It involves three actors which work together to create **distributed trust**: + +- A Claimer is an actor who claims to possess certain credentials, abilities, or other attributes. +- An Attester is an actor that verifies the claims of a Claimer. +- A Verifier is an actor that asks for proof of a claim. + +For the workshop, you play all three roles. + +In a real-world use case, these actors would be different people and services, which this workshop simulates using different folders for each service. +Each actor typically performs different roles: + +- Both the Verifier and the Attester have to interact with the KILT blockchain. +- But only the Attester is required to own KILTs since they have to pay for storing the attestation on chain. +- The Verifier only needs to query the KILT blockchain to ensure that the attestation is still valid and was not revoked. +- The Claimer is not required to query the blockchain, but they might do so to check whether their credential is still valid or if the Attester has revoked it in the meantime. + +## Request an Attestation + +Before the Claimer can attest a credential, they need to generate a [light DID](../01_sdk/02_cookbook/01_dids/01_light_did_creation.md), which can happen off-chain. + +The Attester has to register their DID on chain and needs KILT coins. + +After both the Attester and the Claimer have set up their identities, the Claimer can start the attestation process by requesting an attestation from the Attester. + +```mermaid +sequenceDiagram +actor C as Claimer +actor A as Attester +participant B as KILT Blockchain + C->>+C: Create credential from provided claims + C->>+A: Transmit credential to request attestation + A->>A: Validate received attributes + A->>+B: Store attestation + B-->>-A: Attestation hash + A-->>-C: Attestation Hash +``` + +1. The Claimer prepares the Credential to attest, along with some proof, for example, a bank statement and ID. +2. They send the document to the Attester for attestation. +3. Upon receiving the credential, the Attester decides whether the claim is valid by examining the proofs. If the Attester trusts the claim, they store the attestation document's hash value on the chain, which is a non-functional copy of the document. +4. The Attester sends this hash value to the Claimer, which represents verification of a document. + +## Verify an Attestation + +The Verifier requests a presentation from the Claimer for a specific required CType. Without a specific CType, the presentation is meaningless. + + + +A presentation is derived from a credential and does not need to contain all attributes. + +After the request, the Claimer can choose to hide elements of their credentials that aren't relevant to the claim. +For example, hide their address from their ID if the Verifier is only interested in their age. + +:::info + +A later step in the workshop [explains CTypes in more detail](./04_attester/03_ctype.md). + +::: + +```mermaid +sequenceDiagram +actor C as Claimer +actor V as Verifier +participant B as KILT Blockchain + V->>+C: Request presentation for CType + C->>C: Derive a presentation from a credential + C-->>-V: submit presentation + V->>B: check validity of presentation +``` + +### Example: Requesting a travel visa + +To take an example of applying for a travel visa: + +1. The Embassy (analogous to the Verifier) asks a traveler (analogous to the Claimer) for a specific document or CType. For example, it could be a bank statement. The Embassy asks, "Provide proof of financial stability, and we'll grant you a visa." The traveler gets the bank statement from their bank, gets it attested by the bank (The Attester), and prepares the document. +2. The document is ready, but the Embassy doesn't need all the information in the document. The embassy wants to know if a traveler has sufficient funds, but they don't need to know any transaction details. The traveler redacts or hides these details while presenting. +3. The traveler presents the document to the embassy. +4. The embassy verified the document's authenticity by comparing its hash value with the one on their internal system or a decentralized ledger. +5. Since they trust the Attester (in this case, the bank that attested the bank statement), they approved the visa application. + +:::tip Summary + +As you can see, the Embassy didn't need to trust the Claimer directly in this system. +They trust the Attester, whom they had previously worked with, or respect due to their position. +And with that trust, they grant the visa with no knowledge of what the Claimer has used the credential for. +Even though this process emerged due to the trust in the Attester, the Attester was not involved in the second stage, so they were unaware of it. +Privacy was achieved with distributed trust. + +::: \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/01_account.md b/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/01_account.md new file mode 100644 index 000000000..e2710f623 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/01_account.md @@ -0,0 +1,111 @@ +--- +id: account +title: Account +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import GenerateAccount from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/attester/generateAccount.ts'; + +With the [project structure setup](./) in the last step, you can create your Attester account. + +With KILT, an account is an object that interacts with the blockchain. + +:::info KILT Account + +A KILT account is a set of cryptographic elements: + +- The address, generated from the public key, is the entity's unique and public on-chain identifier, used to pay fees and deposits. +- A signing key pair to write transactions on-chain + +::: + +To create an account, you need a mnemonic. + +:::info Mnemonic + +In cryptography, a mnemonic consists of a series of 12 or 24 random words. + +For example, `waste frown beach save hidden bar inmate oil mind member junk famous` is a mnemonic. + +You use a mnemonic to generate signing key pairs. +What's great about a mnemonic is that it's **human-readable**, and a person could memorize it to later re-generate their key pairs and address. +A mnemonic is critical for security, so it's crucial to keep it safe! + +::: + +## Create the Account + +To generate an account, use the `addFromMnemonic()` function on the [`KiltKeyringPair`](https://kiltprotocol.github.io/sdk-js/interfaces/types_src.KiltKeyringPair.html) interface of the SDK. +The function uses the underlying polkadot `mnemonicGenerate()` function to generate a 12-word mnemonic. + +:::info polkadot.js + +The KILT SDK is built on top of the [polkadot.js](https://polkadot.js.org/) library, so this workshop uses several functions from the library. + +The library provides tools to interact with the KILT blockchain and other Substrate-based blockchains. + +In addition, the polkadot.js library offers cryptographic primitives and a serialization framework to encode/decode data sent to and received from the blockchain. +Read the [API documentation](https://polkadot.js.org/docs/) to learn more about the functions available. + +::: + +Add the following code to the `generateAccount` file. + + + {GenerateAccount} + + +The `generateAccount` method returns an object with the following two properties: + +- A key `account` with the type `Kilt.KiltKeyringPair`. +- A key `mnemonic` with the type `string`. + +Generating these values takes two steps: + +1. Create the `mnemonic` value using the `mnemonicGenerate()` method from the `Utils.Crypto` package. +2. The `account` value first needs a `keyring` value defined, which is a data structure for defining the key pair type. This example uses `ed25519`, but `sr25519` or `ecdsa` are also valid. + +The function then returns the value using the `makeKeypairFromUri()` method to create a key pair for the address using the given mnemonic. + +The rest of the code runs the `generateAccount` function and logs the results to the console. + +## Run code + +Run the code above to receive your Attester `
` and ``. + + + + +```bash +yarn ts-node ./attester/generateAccount.ts +``` + + + + +```bash +node ./attester/generateAccount.js +``` + + + + +The output provides you with an `ATTESTER_ACCOUNT_MNEMONIC` and `ATTESTER_ACCOUNT_ADDRESS`. +Save both values in your `.env` file, which should look similar to the below. + +```env title=".env" +WSS_ADDRESS=wss://peregrine.kilt.io + +ATTESTER_ACCOUNT_MNEMONIC="warrior icon use cry..." +ATTESTER_ACCOUNT_ADDRESS="4ohMvUHsyeDhMVZF..." +``` + +:::warning Get PILT coins! + +You now have a blockchain account to use to pay fees and deposits. +If you haven't already requested PILT, go to the [faucet](https://faucet.peregrine.kilt.io) and request tokens for your `
`. + +::: diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/02_did.md b/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/02_did.md new file mode 100644 index 000000000..fa4bc03cd --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/02_did.md @@ -0,0 +1,139 @@ +--- +id: did +title: DID +--- + +import CodeBlock from '@theme/CodeBlock'; +import TsJsBlock from '@site/src/components/TsJsBlock'; +import SnippetBlock from '@site/src/components/SnippetBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import GenerateKeypairs from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/attester/generateKeypairs.ts'; +import GenerateDid from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/attester/generateDid.ts'; + +The next step is to generate a KILT decentralized identifier (DID) using the account you created for the Attester in [the previous step](./01_account.md). + +A DID may represent any entity, such as a person, an organization, or a machine. + +A DID is a string uniquely identifying each KILT user. +You can store information about a DID on the KILT chain, which is useful for different use cases. + +One use case is messaging. +You could store a public encryption key and a service on chain, and a user can query both using a DID. +Other users can now encrypt messages using your public encryption key and send a message to your service. + +## Light and full DIDs + +Kilt supports two DID types: **light** and **full**. + +There are differences between the two types, but the most crucial is that you can use a light DID offline, but a full DID needs access to the blockchain to work. +Read the [DID documentation](../../../develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md) to learn more about the difference between the light and full types. + +:::info KILT DID + +A DID supports four different key types: + +- An _authentication key pair_, used to sign claims and present authenticated credentials +- A _key-agreement key pair_, used to encrypt/decrypt messages +- An _assertion-method key pair_, used to write CTypes and attestations on chain +- A _capability-delegation key pair_, used to write delegations on chain + +You can replace keys over time, e.g., if a key becomes compromised. + +::: + +## What's the difference between a DID and an account? + +A DID and an account sound quite similar, but there are some differences: + +- You record both to chain +- You can have a DID without an account +- You can have an account without a DID +- Only an account can pay deposits and fees and attest claims +- DIDs don't hold any coins + +In summary, you register a DID on the blockchain by an account submitting the DID creation transaction and paying the fees. + +## Create a DID + +As an Attester needs to interact with the chain, you must create a full DID. + +### Write DID to chain + +The KILT SDK provides multiple methods to create DIDs, this workshop highlights the `createFromAccount` method, that creates a DID from any pre-existing substrate-compatible account. + + + + +:::info Bring your own account + +This workshop assumes you followed the [create account step](./01_account.md), but if you have a pre-existing account, you can use that instead. + +::: + +Create and submit the extrinsic (aka transaction) that registers the DID. + + + {GenerateDid} + + +The `publicKeyToChain` helper method returns a public key of the correct type. + +The `txs` array holds the two transactions containing the extrinsics needed to submit to the chain for the Attester's DID creation. + +The `createFromAccount` method takes the authenticated key of the account to attach the DID to, and the `setAttestationKey` method takes the same parameter to set the attestation key the DID needs and uses. + +An Attester account needs to have an attestation key to write CTypes and attestations on chain. Use the `setAttestationKey` method to set this. For this example transaction, the Attester account uses the `dispatchAs` proxy method to assign the attestation key to the same account. However, you can also use this method to assign the attestation key to another account. + +The `signAndSubmitTx` method then takes those transactions and submits them as a batch to the chain. + +## Run the code + +Now run the code with: + + + + + ```bash + yarn ts-node ./attester/generateDid.ts + ``` + + + + + ```bash + node ./attester/generateDid.js + ``` + + + + +Once you have run the script, the output should provide you with the `ATTESTER_DID_URI`. + +The output should look like the following, but not identical since the code creates the DIDs from your account: + +``` +ATTESTER_DID_URI="did:kilt:4ohMvUHsyeDโ€ฆ" +``` + +Save the values in the `.env` file, which should now look like the following: + +```env title=".env" +WSS_ADDRESS=wss://peregrine.kilt.io + +ATTESTER_ACCOUNT_MNEMONIC="warrior icon use cry... +ATTESTER_ACCOUNT_ADDRESS=4ohMvUHsyeDhMVZF... +ATTESTER_DID_URI="did:kilt:4ohMvUHsyeD..." +``` + +Well done - You've generated a full DID! The next step is to create a CType! + +## Generate Keys + +Add the following code to the `generateKeypairs` file. + + + {GenerateKeypairs} + + diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/03_ctype.md b/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/03_ctype.md new file mode 100644 index 000000000..417885275 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/03_ctype.md @@ -0,0 +1,120 @@ +--- +id: ctype +title: CType +--- + +import CodeBlock from '@theme/CodeBlock'; +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import CtypeSchema from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/attester/ctypeSchema.ts'; +import GenerateCtype from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/attester/generateCtype.ts'; + + +import Ctype from '@site/scripts/out/ctype.json.raw!=!raw-loader!@site/scripts/out/ctype.json'; + +A claim type (CType) is a KILT-specific term, but the concept is simple: +A CType is a JSON schema that defines the structure of a claim, and you can think of it as the data model for your claim. + +:::info CType + +A CType ensures that a credential contains all required attributes, e.g., a driver's license has to contain a name, date of birth, and the vehicle types that the claimer can drive. +The CType is important since a Verifier requests credentials for a specific CType. +For example, the traffic police want to see your driver's license, not your gym membership. + +To learn more about CTypes, read the [in-depth CType documentation](../../../concepts/05_credentials/02_ctypes.md). +You can also [read through existing CTypes in the CType-index](https://github.com/KILTprotocol/ctype-index). +::: + +Before the Attester can attest credentials, they must decide which CType they support. +For example, a traffic authority only issues driver's licenses (A CType for driver's license), not a university diploma. + +Since CTypes enable interoperability between Attesters, using existing CTypes rather than creating new ones is highly recommended. +However, this workshop creates a new CType to show the process. + +Creating CTypes requires an account and a full DID. +Make sure your account holds KILT tokens so that you can pay the fees for creating a CType. + +For example, a basic CType for a driver's license could look like this: + + + {Ctype} + + +The CType has the following attributes: + +| Key | Value | +| -------------| ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `$id` | The KILT id of this CType. It's the most important property as it represents the **digital footprint** of the CType. | +| `$schema` | A reference to the meta-schema describing what a CType may look like. There are two versions. | +| `title` | The title of the CType. | +| `properties` | The properties that a claim conforming to this CType may have. | +| `type` | Type is an object for all CTypes. | +| `additionalProperties` | The default is false. This restricts unwanted properties in a claim. | + +A CType is stored on the KILT blockchain. + +In a real-world situation, a user would retrieve an existing CType from the chain or a CType registry. +For example, via a Credential Registry's REST API. + +In this tutorial, the Attester creates and attempts to store a CType on the KILT test blockchain. + +## Create CType + +Copy the following to define a `CType` with a given schema: + + + {CtypeSchema} + + +:::warning + +As many people follow this workshop, using the CType schema defined above will result in a duplicate error when you run the code later. +To avoid this, change the value of `fromProperties` to something unique, such as adding your name to the "Drivers License" string. + +::: + +## Get CType + +Copy the following to create a `CType` on the chain: + + + {GenerateCtype} + + +The `ensureStoredCType` function takes the Attester's account, DID, and a callback to sign the function and checks if the CType is already on chain. +It uses the `verifyStored` method to pass the CType to the KILT blockchain and make the check. +If it does not exist, it stores it on chain, using the `toChain` method to encode the CType into a unique hash and the `add` method to create a new CType from the given unique hash and associate it with the Attester. +The function then uses the `authorizeTx` to authorize the transaction and `signAndSubmitTx` to sign and submit the transaction containing the new CType. + +:::warning + +Remember, an account must have the required amount of tokens to pay the transaction fee and deposit. + +::: + +## Run + + + + + Run the `attester/generateCtype.ts` file. + + ```bash + yarn ts-node attester/generateCtype.ts + ``` + + + + + Run the `attester/generateCtype.js` file. + + ```bash + node attester/generateCtype.js + ``` + + + + +Before you can attest Credentials, you need a Claimer to request it diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/_category_.json b/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/_category_.json new file mode 100644 index 000000000..6c31a6f8e --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "๐Ÿข Attester", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/index.md b/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/index.md new file mode 100644 index 000000000..5da9f6d70 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/04_attester/index.md @@ -0,0 +1,59 @@ +--- +id: attester +title: ๐Ÿข Attester +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This section of the workshop covers creating the Attester code. The steps are the following: + +1. [Create an account](./01_account.md) to pay for all transactions and storage deposits. +2. [Create a DID](./02_did.md), which is the identity used to create attestations. + + While you can always switch the KILT account and pay deposits and fees with any account you like, your DID stays the same and is the way Claimers identify and trust you. + +1. Before you can attest claims, [you need a CType](./03_ctype.md) that describes and gives context to what you attest. +2. Once you have a way to pay fees and deposits, have an identity, and a CType, [you can create attestations](../06_attestation.md). + +## Folder Structure + +Create the following files in the `attester` folder. +These folders mimic an Attester service. + + + + + ```bash + โ””โ”€ kilt-rocks/ # project + โ””โ”€ attester/ # all attester code + โ”œโ”€ attestCredential.ts # issues attestations + โ”œโ”€ ctypeSchema.ts # create a local CType definition + โ”œโ”€ generateAccount.ts # functions for setting up and loading the attester's account + โ”œโ”€ generateCtype.ts # register the CType on chain + โ”œโ”€ generateDid.ts # registers the attester's on-chain DID + โ””โ”€ generateKeypairs.ts # setup the keys for the attester's DID + ``` + ```bash + cd attester && touch attestCredential.ts ctypeSchema.ts generateAccount.ts generateCtype.ts generateDid.ts generateKeypairs.ts && cd .. + ``` + + + + ```bash + โ””โ”€ kilt-rocks/ # project + โ””โ”€ attester/ # all attester code + โ”œโ”€ attestCredential.js # issues attestations + โ”œโ”€ ctypeSchema.js # create a local CType definition + โ”œโ”€ generateAccount.js # functions for setting up and loading the attester's account + โ”œโ”€ generateCtype.js # register the CType on chain + โ”œโ”€ generateDid.js # registers the attester's on-chain DID + โ””โ”€ generateKeypairs.js # setup the keys for the attester's DID + ``` + + ```bash + cd attester && touch attestCredential.js ctypeSchema.js generateAccount.js generateCtype.js generateDid.js generateKeypairs.js && cd .. + ``` + + + diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/01_did.md b/versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/01_did.md new file mode 100644 index 000000000..e6abbde43 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/01_did.md @@ -0,0 +1,75 @@ +--- +id: did +title: DID +--- + +import CodeBlock from '@theme/CodeBlock'; +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import GenerateKeypairs from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/claimer/generateKeypairs.ts'; +import GenerateLightDid from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/claimer/generateLightDid.ts'; + +This section covers creating a light DID using the account you created for the Claimer. + +Since a light DID is not registered on the blockchain, you don't need funds to create one. + +:::info + +Remember, light DIDs can do the following: + +- Sign attestation requests and presentation with the authentication keys +- Encrypt messages with the encryption keys + +Read the [DID documentation](../../../develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md) to learn more about DIDs and the difference between their light and full versions. + +::: + +## Generate Keys + +Like the Attester, the Claimer must also set up the DID keys. + + + {GenerateKeypairs} + + +The code above is similar to the `generateKeyAgreement` function used in the Attester section but simpler, as the Claimer only needs an authentication key and an encryption key. + +Both the keys are derived from the same seed, but they could also have two different seeds. + +## Generate Light DID + +With the `keypairs` generated, you can create the light DID. +Because it's off-chain you can create the DID object every time, but you still need to save the mnemonic to the `.env` file with a different variable name. + + + {GenerateLightDid} + + +The Claimer doesn't have an `account`, as the Claimer doesn't need to hold funds. + +The `generateKeypairs` function takes the `mnemonic` value and generates the `authentication` and `keyAgreement` keys. + +The `createLightDidDocument` method takes these two values and generates the light DID. + +## Run + + + + + ```bash + yarn ts-node ./claimer/generateLightDid.ts + ``` + + + + + ```bash + node ./claimer/generateLightDid.js + ``` + + + + +Well done - You successfully generated a light DID! diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/02_request.md b/versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/02_request.md new file mode 100644 index 000000000..8dbc992ff --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/02_request.md @@ -0,0 +1,73 @@ +--- +id: request +title: Request an Attestation +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import CreateClaim from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/claimer/createClaim.ts'; +import GenerateCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/claimer/generateCredential.ts'; + +This section covers creating a `Claim` and a `Credential`. + +KILT is a premissionless system. +Anyone or anything can claim something and attest to it. +But an attested credential only has value if the Verifier of the credential _trusts_ the Attester of the credential. + + +## Create Credential + +Use the previously created `light DID`, `ctype`, and Claimer provided `content` to generate the `Claim` object. + +A claim consists of attributes that we claim to be true about us. + + + {CreateClaim} + + +The `fromCTypeAndClaimContents` function takes the `lightDid`, `ctype`, and `content` values and generates a `Claim` object. + +## Receive attestation for claim + +Since you want to receive an attestation for those claims, build a `Credential` in the `generateCredential` function below. + +The credential contains all necessary information so the Attester can attest it. + + + {GenerateCredential} + + + +The `main` function takes the Claimer mnemonic and generates the light DID following the steps outlined in the [DID section](./01_did.md). +It then calls the `generateCredential` function using the supplied claim attributes. +It then uses the `createClaim` method from the previous step to create the `Claim` object and the `Kilt.Credential.fromClaim` method takes the claim and returns the `Credential` object. + +When Attesters issue `Attestations`, they are written to the chain, which requires a deposit. +Each new `Credential` is unique. +During testing, you can store and reuse credentials into `./claimer/_credential.json` to avoid multiple attestations. + +You can share this credential with others following the workshop to see how they get denied from fraudulent senders. + +## Run + + + + + ```bash + yarn ts-node claimer/generateCredential.ts + ``` + + + + + ```bash + node claimer/generateCredential.js + ``` + + + + +OK, you've made a claim as a Claimer and created a credential from it. +The next step is to finish the Attester and get the credential attested! diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/_category_.json b/versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/_category_.json new file mode 100644 index 000000000..5656d275e --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "๐Ÿ‘ค Claimer", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/index.md b/versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/index.md new file mode 100644 index 000000000..0c9431ac7 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/05_claimer/index.md @@ -0,0 +1,76 @@ +--- +id: claimer +title: ๐Ÿ‘ค Claimer +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This section covers the steps undertaken by the Claimer. + +Here's an overview: + +1. [Create a DID](./01_did.md), which is the identity used to interact with Attesters and Verifiers. +2. Create a claim, request an attestation, and generate a credential using the attestation for our claim. +3. Present the claim to a Verifier. + +## What is a Claimer? + +Claimers are a crucial part of the Self-Sovereign Identity system. + +A Claimer is an individual or institution that makes a claim or statement about their identity or abilities. +They can use their identity credentials to prove these claims, and third-party institutions verify them. + +Anyone can be a Claimer. +All you need to do is complete a CType and create a claim. +Then, you can send these claims to Attesters for verification. + +They store their identity credentials in their digital wallets, so they decide which information to provide to which service. +They have full control over their data and decide which data to share, where, and how. + +You don't need to create a DID on the chain, meaning you are entirely independent! + +Claimers can use their accounts without needing a chain connection. + + +## Folder Structure + +Create the following files in the Claimer folder. +This folders serves to mimic a Claimer's perspective. + + + + + ```bash + โ””โ”€ kilt-rocks/ # project + โ””โ”€ claimer/ # all claimer code + โ”œโ”€ createClaim.ts # creates a claim + โ”œโ”€ createPresentation.ts # creates a presentation for verifiers + โ”œโ”€ generateCredential.ts # create the credential object that is sent to the attester for attestation + โ”œโ”€ generateKeypairs.ts # create keypairs for the light DID + โ””โ”€ generateLightDid.ts # create the light DID for the claimer + ``` + + ```bash + cd claimer && touch createClaim.ts createPresentation.ts generateCredential.ts generateKeypairs.ts generateLightDid.ts && cd .. + ``` + + + + + ```bash + โ””โ”€ kilt-rocks/ # project + โ””โ”€ claimer/ # all claimer code + โ”œโ”€ createClaim.js # creates a claim + โ”œโ”€ createPresentation.js # creates a presentation for verifiers + โ”œโ”€ generateCredential.js # create the credential object that is sent to the attester for attestation + โ”œโ”€ generateKeypairs.js # create keypairs for the light DID + โ””โ”€ generateLightDid.js # create the light DID for the claimer + ``` + + ```bash + cd claimer && touch createClaim.js createPresentation.js generateCredential.js generateKeypairs.js generateLightDid.js && cd .. + ``` + + + diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/06_attestation.md b/versioned_docs/version-0.35.0/develop/03_workshop/06_attestation.md new file mode 100644 index 000000000..a433f6110 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/06_attestation.md @@ -0,0 +1,55 @@ +--- +id: attestation +title: ๐Ÿงพ Attestation +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import AttestCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/attester/attestCredential.ts'; + +This section covers how the Attester receives and processes a `Credential` and how you can: + +- Attest or deny it +- Store the attestation information on the chain + +## Attest a Credential + + + {AttestCredential} + + +The `attestCredential` function loads the account and DID of the Attester and issues an attestation for the credential received from the Claimer. +The credential is valid from the time an Attester attests it on chain until the time it is revoked. + +In the `attestingFlow` function, the Claimer generates the demo credential and sends it to the Attester. +The Attester checks the attributes and either attests or denies the attestation if the attributes are invalid. +Once the attestation is written on the chain, the Attester can share all or part of the attested credentials with verifiers. + +## Run + +Run the code from the command line: + + + + + ```bash + yarn ts-node attester/attestCredential.ts + ``` + + + + + ```bash + node attester/attestCredential.js + ``` + + + + +## Summary + +Your job as an Attester is complete. You've attested a credential and written the attestation hash onto the chain. + +Let's move on to set up the Verifier! diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/07_verification.md b/versioned_docs/version-0.35.0/develop/03_workshop/07_verification.md new file mode 100644 index 000000000..e0a154733 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/07_verification.md @@ -0,0 +1,72 @@ +--- +id: verification +title: ๐Ÿค Verification +--- + +import CodeBlock from '@theme/CodeBlock'; +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Verify from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/verify.ts'; +import CreatePresentation from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/claimer/createPresentation.ts'; + +In this section, you play the role of a Verifier that does the following: + +1. Take a `Presentation` object supplied by a Claimer +2. Verify that its data is correct +3. Verify that the attestation is valid, i.e., its hash exists on-chain and the attestation has not been revoked +4. Verify that the Claimer sending the `Credential` owns it + +:::info Presentation object + +The Claimer uses a Credential to create the `Presentation` object. +Unlike the credential, a `Presentation` can hide some attributes that are not required by the Verifier and can contain a claimer-signed challenge. +A `Presentation` also contains a proof that the Claimer owns the credential. + +::: + +## Create Presentation + +A Claimer needs to send more than a credential, as they also need to prove ownership of the credential. +A Claimer does this by creating a presentation and signing the Verifier's challenge. + + + {CreatePresentation} + + +The `createPresentation` method returns a presentation, taking the credential, a callback to sign data, and the Verifier's challenge as input. + +## Verify + +The verification code exposes the `getChallenge` method which returns a random and unique challenge for the Claimer to sign. +This unique challenge is used to prove ownership. + + + {Verify} + + +The `verifyPresentation` method performs the actual verification, taking a presentation and the Claimer's challenge as input. + +## Run + +Run the code from the command line: + + + + + ```bash + yarn ts-node verify.ts + ``` + + + + + ```bash + node verify.js + ``` + + + + +That's it! All done :-) \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/08_done.md b/versioned_docs/version-0.35.0/develop/03_workshop/08_done.md new file mode 100644 index 000000000..ff6558e53 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/08_done.md @@ -0,0 +1,25 @@ +--- +id: done +title: ๐Ÿš€ Done +--- + +## Congrats! + +Well done! +You now understand the main actors in KILT, the `Claimers`, `Attesters` and `Verifiers`. + +You have also learned how to: + +- create accounts +- create light and full DIDs +- create claims and attestation requests +- process requests and attest credentials +- generate and sign credential presentations +- receive and verify presentations + +## Resources + +Here are some resources to help you continue your journey in the KILT ecosystem: + +- [Discord](https://discord.gg/5VZnPdTZMy) - DAO-inspired, outcome-focused community +- [Element](https://matrix.to/#/%23kilt-general:matrix.org) - Technical, Governance, Treasury discussion diff --git a/versioned_docs/version-0.35.0/develop/03_workshop/_category_.json b/versioned_docs/version-0.35.0/develop/03_workshop/_category_.json new file mode 100644 index 000000000..65d6b088b --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/03_workshop/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Workshop", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/04_specifications.md b/versioned_docs/version-0.35.0/develop/04_specifications.md new file mode 100644 index 000000000..b36bed2b5 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/04_specifications.md @@ -0,0 +1,28 @@ +--- +id: specifications +title: Technical Specifications +--- + +:::note +This section is a WIP. +The end goal is for it to host all KILT specifications. +::: + +List of core specifications KILT has defined in an effort to standardize APIs and data structures across applications: + +- [KILT DID Method (GitHub repo)][kilt-did-method] +- [KiltPublishedCredentialCollectionV1 Service Type (GitHub repo)][kilt-published-credential-collection-v1] +- [Asset DID Method (GitHub repo)][asset-did-method] +- [KiltTransferAssetRecipientV1 Service Type (GitHub repo)][kilt-transfer-asset-receipient-v1] + +List of extensions to the core KILT protocol that standardize communication with the core KILT components (e.g., API for wallets to present credentials): + +- [Wallet Credential API (GitHub repo)][kilt-wallet-credential-api] +- [Wallet DIDSign API (GitHub repo)][kilt-wallet-didsign-api] + +[kilt-did-method]: https://github.com/KILTprotocol/spec-kilt-did +[kilt-published-credential-collection-v1]: https://github.com/KILTprotocol/spec-KiltPublishedCredentialCollectionV1 +[asset-did-method]: https://github.com/KILTprotocol/spec-asset-did +[kilt-transfer-asset-receipient-v1]: https://github.com/KILTprotocol/spec-KiltTransferAssetRecipientV1 +[kilt-wallet-credential-api]: https://github.com/KILTprotocol/spec-ext-credential-api +[kilt-wallet-didsign-api]: https://github.com/KILTprotocol/spec-ext-didsign-api diff --git a/versioned_docs/version-0.35.0/develop/05_builtonkilt.md b/versioned_docs/version-0.35.0/develop/05_builtonkilt.md new file mode 100644 index 000000000..e03487106 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/05_builtonkilt.md @@ -0,0 +1,78 @@ +--- +id: builtonkilt +title: Built on KILT +--- + +import ThemedImage from '@theme/ThemedImage'; +import LogoText from '@site/src/components/LogoText'; + +This section contains a non-exhaustive list of apps, wallets and websites that are built on KILT. +If you are not on the list and want to be added, you are welcome to [open a PR](https://github.com/KILTprotocol/docs/edit/master/docs/develop/05_builtonkilt.md). + +## Wallets + +Wallets are the gateway to Web3. +They store private information like secret keys for KILT DIDs and credentials. +Each time a website needs to access some information about the visitor, the wallet first asks its ownerโ€™s permission to share the requested information. + + + + Sporran is the first wallet to support the KILT protocol. + It is maintained by _BOTLabs Trusted Entity B.T.E GmbH_ and it is [open source](https://github.com/BTE-Trusted-Entity/sporran-extension). + + +## Web Apps + +Decentralized applications have already been built that use the functions of the wallet. + + + Help secure the KILT Spiritnet! + On Stakeboard you can influence who is allowed to build blocks on Spiritnet by delegating KILT tokens to a collator you trust. + + +--- + + + w3n.id is a website that helps you claim and search web3names. + Learn more about KILT web3names in our [concepts section](../concepts/03_web3names.md). + + +--- + + + DIDsign provides a decentralized way to sign any file directly in your browser using your KILT DID. + Your data stays locally on your device and is never transferred or held in a centralized place. + + +--- + + + Get your first KILT credential today! + SocialKYC issues credentials that prove ownership of several social profiles, including email addresses, and Telegram, Twitter and GitHub accounts, with more being continuously added. + It's free to use, and credentials expire after one year. + diff --git a/versioned_docs/version-0.35.0/develop/06_contribute.md b/versioned_docs/version-0.35.0/develop/06_contribute.md new file mode 100644 index 000000000..63430b580 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/06_contribute.md @@ -0,0 +1,101 @@ +--- +id: contribute +title: Contribution Guidelines +--- + +As a decentralized network, KILT depends on the support of its community. +There are many ways to contribute to KILT Protocol and the products and services built on it. +The following guide is to **help builders and contributors** find the resources needed to take action and work under the guidance of the core developers. + +If you are interested in contributing but unsure how to begin, start in our [Clan KILT Discord](https://discord.gg/7uyfMXh6AT) channel. +The developers active there, which include the team that originally developed KILT and the wider KILT community, can: + +- Provide feedback on proposals or ideas +- Discuss possible use cases and feature requests +- Make suggestions for non-technical contributions, including events, writing, or business models +- Answer questions about the protocol, services and products + + +## Feature Requests + +A feature request may be used to change the KILT Protocol and its services by adding new features or changing/removing existing ones. + + +A feature request is a meaningful way for anyone to contribute following the guidelines below: + + - Begin a discussion with the community to ensure most see that the proposed feature adds real and meaningful value to KILT Protocol, supporting its goals + - Open an Issue on the corresponding repository + - Give your Pull Request a clear title + - Provide a written outline of the feature request for discussion + +After discussion, if the community agrees that the change should be implemented, the proposer may also submit a Treasury proposal to support the work. +The guidelines of how to do that are presented in the next section. + +## Treasury Proposals + +A Treasury proposal is a request to receive funds from the Treasury pool. +The proposal should begin with a clear title, a written outline of the idea, and a discussion about implementation or deliverables as outlined above for feature requests. +The proposal should be for something that changes or adds value to KILT in a meaningful way. + +:::info +In general, a Treasury proposal spend occurs after completing all outlined deliverables and not before. +Thus, it is recommended to open multiple consecutive milestone-based proposals rather than one large proposal to fund contributions. +::: + +In addition you should: + +- Explain any milestones that have already been achieved +- Outline what needs to be done for the proposal to be completed + +The proposal should then be discussed with the community (including, for example, the KILT Technical Committee, governance, or relevant project team) using community channels such as [Discord](https://discord.gg/7uyfMXh6AT) or [Polkassembly](https://kilt.polkassembly.network/discussions). +If the community is not in agreement with the proposal, it is unlikely that it would be approved by governance. +See the [guide to creating a proposal](../participate/03_treasury_proposal.md) for additional details. + +## Tips + +Tips are a more agile and lightweight process to receive rewards for contributing to the KILT Protocol. +Even though the funds also come from the Treasury, the procedure is more straightforward. +The major difference compared to Treasury proposals is that for tips, determining the bounty amount is part of the course of tipping. +In other words, the final tip amount is not clear beforehand and the group of pre-determined stakeholders comes to consensus on how much should be paid. +Eventually, the median of proposed tips will be awarded from the Treasury. +Currently, the tippers include all Council members and other core code contributors. + +Both proposals and tips are similar in the sense that there must be someone (called the _Finder_) to open the tipping process by providing a reason in the form of a URL or an explanation on [Polkassembly](https://kilt.polkassembly.network/). +In contrast to proposals, tips do not require an extensive document; a URL to the pull request or the blog post suffices. +If the Finder is part of the group that decides about the bounty award, no deposit needs to be made. +Moreover, the beneficiary will receive the entire tip without any deductions. +Otherwise, a small deposit, which depends on the length of the message explaining the reason for the tip, needs to be reserved. +The deposit will be released after the tipping process has finished. +Additionally, the Finder also receives a minor Finder's fee of 20% which is subtracted from the final tip amount. + +Therefore, **even if you are not a contributor, you can open a tipping process for someone else and receive a smaller portion of their potential reward**. +Of course, you can also suggest potential tip candidates to the Council, which would then tip if they are deemed worthy. + +## Bug Reports + +We try our best, but bugs are an everyday reality with all software and are bound to happen. +We can't fix bugs we don't notice, so your potential findings give us the best possibility of keeping the project running smoothly and securely. + +If you are unsure if a bug is a bug, it is best to open an issue and report it anyway. +The active developers will evaluate it and help to figure out the issue. + +It is helpful to check if a report has already been filed in the related project. +Search the issues board for possible phrases that match the description of the bug. +It's possible you may not find an issue, but it's better to file a duplicated bug than not report one. + +Once you begin reporting the bug, write a descriptive title so that if others find the same issue they can either add to your findings or know that the bug has already been reported. +A bug report should be as detailed as possible, including steps to reproduce, screenshots, error reports, or code snippets. +The more details you provide, the easier it is to fix the issue. + +## Pull Requests + +Pull Requests (PR) are an integral part of contributions to evolve KILT. +GitHub itself has some [excellent documentation](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests) on using the Pull Request feature. +KILT uses the "[fork and pull](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/getting-started/about-collaborative-development-models)" model, where contributors push changes to their personal fork and create Pull Requests to bring those changes into the original source repository. + +Before starting a PR, itโ€™s best to contact other active developers and discuss the proposed changes. +Open an issue or directly contact some of the developers on [Discord](https://discord.gg/7uyfMXh6AT) to kick off the discussion and present the proposal. +Once approved, contributors can open a PR for review. +The PR will be reviewed and, if accepted, merged into the corresponding repository. + +The following section is inspired by the Rust Programming Language [Bug Report](https://rustc-dev-guide.rust-lang.org/contributing.html) contribution guide. diff --git a/versioned_docs/version-0.35.0/develop/07_dApp/01_welcome.md b/versioned_docs/version-0.35.0/develop/07_dApp/01_welcome.md new file mode 100644 index 000000000..8f04305cc --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/07_dApp/01_welcome.md @@ -0,0 +1,13 @@ +--- +id: welcome +title: Overview +--- + +This section expands on the [Credential API Specification](https://github.com/KILTprotocol/spec-ext-credential-api) and includes code examples to help you build a decentralized application (dapp). + +This documentation assumes that you already have a browser extension capable of exposing the credential API to your dapp. +We suggest using Sporran: + +- [Sporran Full Version](https://github.com/BTE-Trusted-Entity/sporran-extension) +- [Sporran Test Version for Peregrine](https://github.com/BTE-Trusted-Entity/sporran-extension/releases) +- [Sporran Lite (Credentials only)](https://github.com/BTE-Trusted-Entity/sporran-extension/tree/sporran-lite) diff --git a/versioned_docs/version-0.35.0/develop/07_dApp/02_well-known-did-config.md b/versioned_docs/version-0.35.0/develop/07_dApp/02_well-known-did-config.md new file mode 100644 index 000000000..825387701 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/07_dApp/02_well-known-did-config.md @@ -0,0 +1,110 @@ +--- +id: well-known-did-config +title: Well-Known DID Configuration +--- + + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DomainLinkageCtype from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/01_domain_linkage_ctype.ts'; +import DomainLinkageClaim from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/02_domain_linkage_claim.ts'; +import SignPresentation from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/03_sign_presentation.ts'; +import AttestCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/04_attest_credential.ts'; +import FormatCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/05_format_credential.ts'; + +:::danger This is a working draft + +The KILT support of the *Well-Known DID Configuration* uses unpublished specifications and will change in the future. + +::: + +The *Well-Known DID Configuration* is implemented as a security measure when setting up the communication session between the dapp and extension. +It ensures that the DID the browser extension is communicating to is linked to the domain that is visited by the browser. +This rule is currently enforced by the KILT Wallet reference implementation (Sporran Extension), but might be relaxed in the future. +The implementation is based on the [*Well-Known DID Configuration*][well-known-spec] specified by the Decentralized Identity Foundation. + +Once a communication session between a dapp and an extension is opened, the extension will query `/.well-known/did-configuration.json`. +This JSON-file must contain a credential presentation that conforms to the [Domain Linkage CType][CType-Domain-Linkage]. + +## Set up the Well-Known DID Configuration + +For the *Well-Known DID Configuration* you need to go through the following steps: + +0. Create a full DID + * You will need the `assertionMethodKey` a.k.a. `attestationKey` for signing the credential + * The `authenticationKey` is required for signing the transaction +1. Create a claim +2. Attest the claim +3. Create a presentation +4. Host the presentation on your website at `https:///.well-known/did-configuration.json` + +### Create a DID + +Your dapp needs a DID to identify itself to the extension. +If your dapp does not have a DID yet, follow the [*create a full DID* guide][create-full-did]. +Make sure to create the DID with an `assertionMethodKey` so that you are able to issue attestations. + +### Making the claim + +After you get a DID, you can make a claim about that DID. +The claim has to be based on the [Domain Linkage CType][CType-Domain-Linkage], whose definition you can get from the linked GitHub repository, or fetch from the blockchain using the CType's id: + + + {DomainLinkageCtype} + + +The credential is built from the CType, claim contents, and your dapp's unique DID: + + + {DomainLinkageClaim} + + +The credential isn't attested yet and is therefore not valid yet. + +### Self-attesting the credential + +A valid credential requires an attestation. +Since the website wants to link itself to the DID just created, it has to self-attest the domain linkage credential, i.e., write the credential attestation on chain using the same DID it is trying to link to. + +In order to attest the credential we go through the following steps: + +1. calculating the claim hash +2. creating the attest transaction +3. authorizing the transaction with your DID +4. paying for the transaction with a KILT account and submitting it to the chain + + + {AttestCredential} + + +If you want to learn more about attestations you can refer to our [concept guide][concept-attestations] or the [cookbook][cookbook-attestations]. + +### Presenting the credential + +To use the newly attested credential, we need to derive a presentation from it to host on the dapp website. + + + {SignPresentation} + + +The Well-Known DID Configuration specification requires a verifiable credential. +For now we have to manually convert our KILT credential into the required format. + + + {FormatCredential} + + +### Host the Presentation + +Now that you generated a presentation, you need to host it in your web app, so that the extension can query the presentation. +The extension will make an HTTP GET request to the following URI, and your dapp must respond with the presentation. + +`/.well-known/did-configuration.json` + +How the file is hosted depends on your project setup and is out of scope for this guide. + +[concept-attestations]: ../../concepts/05_credentials/04_attestation.md +[cookbook-attestations]: ../01_sdk/02_cookbook/04_claiming/03_attestation_creation.md +[create-full-did]: ../01_sdk/02_cookbook/01_dids/02_full_did_creation.md +[well-known-spec]: https://identity.foundation/specs/did-configuration/ +[CType-Domain-Linkage]: https://github.com/KILTprotocol/ctype-index/tree/main/ctypes/0x9d271c790775ee831352291f01c5d04c7979713a5896dcf5e81708184cc5c643 diff --git a/versioned_docs/version-0.35.0/develop/07_dApp/03_session.md b/versioned_docs/version-0.35.0/develop/07_dApp/03_session.md new file mode 100644 index 000000000..12b04afce --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/07_dApp/03_session.md @@ -0,0 +1,59 @@ +--- +id: session +title: Setting Up the Communication Session +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DappIntroduction from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/06_dapp_introduction.ts'; +import SessionCheck from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/07_session_check.ts'; + +The first step in creating your dapp is to set up the communication session. +The purpose of the session is to pass encrypted messages back and forth between your dapp and the extension. + +## Dapp Indicates Credential API Support + +In order to indicate its support of the extension's API, the dapp creates the `window.kilt` object as soon as possible. +To indicate the API version that the dapp supports, we also create the properties `window.kilt.meta.versions.credentials`. +Since `meta` is not an extension, this property is not enumerable. +For example: + +```html + + + +``` + +## Dapp Introduces Itself + +The dapp introduces itself to the extension with its name, encryption key URI, and a challenge. +A copy of the challenge should be stored on the server side. +For example: + + + {DappIntroduction} + + +At this point the extension has received the introduction of the dapp and returned a new session along with the encrypted challenge. + +## Dapp checks the session values + +The extension has provided the session along with an encrypted challenge. +The dapp decrypts the challenge and verifies that it matches the original challenge. +This should happen on the server side: + + + {SessionCheck} + + +That's it! The communication session has been securely established and you're ready to start sending and receiving messages. diff --git a/versioned_docs/version-0.35.0/develop/07_dApp/04_verifier.md b/versioned_docs/version-0.35.0/develop/07_dApp/04_verifier.md new file mode 100644 index 000000000..1f44af1c6 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/07_dApp/04_verifier.md @@ -0,0 +1,84 @@ +--- +id: dapp-verifier +title: Verifying a Credential +--- + +import TsJsSnippet from '@site/src/components/TsJsSnippet'; +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import EmailCtype from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/verifier/01_email_ctype.ts'; +import GenerateChallenge from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/verifier/02_generate_challenge.ts'; +import CreateRequestCredentialMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/verifier/03_create_request_credential_message.ts'; +import EncryptRequestCredentialMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/verifier/04_encrypt_request_credential_message.ts'; +import DecryptCredentialMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/verifier/05_verify_credential_message.ts'; + +This section demonstrates how to build a basic verifier according to the [Credential API Specification](https://github.com/KILTprotocol/spec-ext-credential-api). +Before continuing, please make sure you have already set up the [communication session](03_session.md) and [Well-Known DID Configuration](02_well-known-did-config.md). + +This guide explains specifically how a web server can request a credential presentation from one of its visitors (the claimer). +After the browser extension verified the Well-Known DID Configuration and the encrypted communication channel between the extension and the server was established, the web server can request the credential presentation. +This is a two step process. + +First the server sends a message to the extension that request the presentation of a credential. +Since we don't want to see just any credential, but expect specific content, we also require that the credential conforms to a specific [CType](../../concepts/05_credentials/02_ctypes.md). +When the extension receives the request, it will prompt the user to select a credential that should be presented to the server. +The user can also choose to reject this request and not to show any presentation. + +The second step is to verify the received credential. +After the user chooses the credential, the extension will pass a response to the website which contains the credential presentation. +The server of that website needs to ensure that this presentation is actually valid. + +## Request a Credential Presentation + +Before the website can request a credential, it needs the type of credential (CType) that it wants to request. +In this guide the website requests an email address that is owned by the DID. +For that it uses the Email CType. +You can search through existing CTypes in the [CType Index](https://github.com/KILTprotocol/ctype-index). + + + {EmailCtype} + + +After settled on a CType, the server can build the request for the visitor. +Since we want to ensure that the presentation of the credential is fresh, the server first has to create a random challenge. +The presentation must include this challenge and since it's random, the presentation must be created and signed from scratch. +This ensures that it's not possible to record a presentation and just send this, pretending to be the owner of the DID. +The challenge can be generated using the polkadot crypto utilities: + + + {GenerateChallenge} + + +With the challenge the server can construct the `request-credential` message. +The request is sent to the light DID (`claimerSessionDid`) that is used to encrypt the messages (see [Session](03_session.md) for more information). + + + {CreateRequestCredentialMessage} + + +:::note Privacy + +The credential itself doesn't need to be issued to this DID since the light DID is only used to encrypt the messages. +We don't use the full DID of the claimer to establish the encrypted communication, so that the claimer first can ensure the origin of the `request-credential` message. + +::: + +After the server has built the message object, it must encrypt the message for the claimer. +Once the message is encrypted the server can pass on the message to the extension. + + + {EncryptRequestCredentialMessage} + + +## Verify the Presentation + +After sending the `request-credential` message to the extension, the verifier listens for a message of type `submit-credential` in response. + +After the response from the extension is received, forwarded to the server and decrypted, the verifier must check that it has the expected CType and that it contains a valid credential. +Since everyone can run an attestation service, you need to make sure that you also verify that the attester is trusted. + + + {DecryptCredentialMessage} + + +That's it! Your verifier has successfully requested and verified a credential. diff --git a/versioned_docs/version-0.35.0/develop/07_dApp/_category_.json b/versioned_docs/version-0.35.0/develop/07_dApp/_category_.json new file mode 100644 index 000000000..235e97018 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/07_dApp/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "DApp", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/08_opendid/01_overview.md b/versioned_docs/version-0.35.0/develop/08_opendid/01_overview.md new file mode 100644 index 000000000..235e4223d --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/08_opendid/01_overview.md @@ -0,0 +1,40 @@ +--- +id: what-is-opendid +title: Overview +--- + +[OpenDID](https://github.com/KILTprotocol/opendid) is an OpenID Provider implementation capable of authenticating users through their [Decentralized Identifier (DID)](../../concepts/02_did.md) and Verifiable Credentials. + +It follows the [OpenID Connect 1.0 Specification](https://openid.net/specs/openid-connect-core-1_0.html#Introduction) and acts as a bridge between the decentralized identity world and the centralized authentication world supporting both the implicit and Authorization Code Flow. + +A major use of OpenDID is Single Sign-On (SSO), which allows users to use the same DID and credentials to sign into multiple platforms and web services. For instance, by adding a "Sign in with KILT" button to a webpage. + +Although integrating that functionality into a webpage is relatively simple, configuring and running OpenDID is more involved. + +:::info + +To learn more about the flow of OpenDID, see the [OpenDID Flow](./02_opendid_flow.md) documentation. + +::: + +## Project container structure + +The project consist of multiple parts that supplement and interact with each other all shipped as Docker containers and released to Docker Hub. + +### opendid-setup container + +The OpenDID Service needs configuration to run, which you can apply using this +container. +For example, it requires a DID to establish a session with an identity wallet. +This container creates a DID and the necessary configuration by providing an account with enough funds. + +Learn more in the [run setup container documentation](./03_opendid_service.md#run-setup-container). + +### kiltprotocol/opendid container + +This container [runs the OpenDID Service](./03_opendid_service.md#run-the-service), both the OpenDID front and back end. +This container requires the configuration file created from the `opendid-setup` container. + +### kiltprotocol/opendid-demo + +This container is a [web app demo](./05_demo_project.md), including front and back end services to demonstrate the use of OpenDID. \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/develop/08_opendid/02_opendid_flow.md b/versioned_docs/version-0.35.0/develop/08_opendid/02_opendid_flow.md new file mode 100644 index 000000000..5a1046ce7 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/08_opendid/02_opendid_flow.md @@ -0,0 +1,74 @@ +--- +id: flow +title: OpenDID Flow +--- + +This guide explains the internal workings of OpenDID. +Understanding this flow is helpful for setting up and configuring an OpenDID Service but less important if you only need to integrate it in an application. + +OpenDID includes interactions between multiple apps to authenticate and authorize users. +Common use cases include the following: + +- Web app front end (app that includes the login button, for example, the demo app) +- Web app back end +- OpenDID front end +- OpenDID back end +- Identity wallet that follows [the Credential API spec](https://github.com/KILTprotocol/spec-ext-credential-api) (typically a browser extension, for example, [Sporran](https://www.sporran.org/)) + +The following steps outline the interactions necessary to implement [the implicit flow](https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth): + +1. The user clicks the login button on the _web app front end_. +2. The _web app front end_ redirects the user to the _OpenDID front end_. +3. The user chooses what wallet to authenticate with. +4. The _OpenDID back end_ establishes a secure session with the _identity wallet_. +5. The _OpenDID back end_ optionally requests a credential that implements a specific CType. +6. The _identity wallet_ provides the _OpenDID back end_ with the requested credential, after authenticating the DID holder. +7. The _OpenDID back end_ returns a `id_token` as a JSON web token (JWT) to the _OpenDID front end_. +8. _OpenDID front end_ redirects the user back to a specific `redirect_url` on the _web app front end_ including the `id_token`. +9. The _web app front end_ detects the `id_token` and sends it to the _web app back end_. +10. The _web app back end_ verifies the `id_token` and ensures the validity of the credential. + +The following sequence diagram summarizes the flow: + +```mermaid +sequenceDiagram + +participant AB as WebApp Backend +participant AF as WebApp Frontend +participant OF as OpenDID Frontend +participant OB as OpenDID Backend +participant IW as Identity Wallet + +AF->>OF: (1, 2) Authorize (redirect_uri: /callback) +OF->>OF: (3) Pick Identity Wallet +critical (4) Key Exchange +OF->>OB: GET Challenge +OB-->>OF: Challenge +OF->>IW: Start Session +IW-->>OF: Encrypted Challenge +OF->>OB: POST Challenge +OB-->>OF: OK +end + +critical Authenticate +OF->>OB: (5) GET Credential Requirements +OB-->>OF: Credential Requirements +OF->>IW: (6) Request Credential +IW->>IW: Authenticate User +IW->>OF: Credential +OF->>OB: POST Credential +OB->>OB: Verify Credential +OB->>OF: (7) `id_token`) +end + +OF->>AF: redirect to /callback with `id_token` +AF->>AB: (8) `id_token` +AB->>AB: (9) verify `id_token` +AB->>AF: (10) Access granted. + +``` + +:::info +Although this example describes the implicit flow, [the authorization code flow](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth) is similar. +Instead of returning an `id_token` directly, the OpenDID service instead returns a `code` to exchange for an `id_token` using the `token` endpoint. +::: diff --git a/versioned_docs/version-0.35.0/develop/08_opendid/03_opendid_service.md b/versioned_docs/version-0.35.0/develop/08_opendid/03_opendid_service.md new file mode 100644 index 000000000..311f3fc60 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/08_opendid/03_opendid_service.md @@ -0,0 +1,115 @@ +--- +id: opendid_service +title: Run OpenDID Service +--- + +## Configuration + +Running the OpenDID service requires some configuration and a KILT DID. +The DID establishes a secure session with an identity wallet using a key agreement key of type `X25519KeyAgreementKey2019` included in the DID Document generated by the setup container. + +OpenDID serves a [well-known DID configuration](https://identity.foundation/.well-known/resources/did-configuration/), which the identity wallet uses to ensure that the domain is linked to the specified DID. + +### Run setup container + +Before running the `opendid-setup` container, set two environment variables: + +1. `SEED` to provide an account with funds (minimum of 3 KILT) for the DID generation. + + ```bash + export SEED="dont try this seed its completely made up for this nice example" + ``` + +2. `ENDPOINT` + + Set to "spiritnet" if the account is on the spiritnet production network. + + ```bash + export ENDPOINT="spiritnet" + ``` + + Set to "peregrine" if the account is on the peregrine test network. + + ```bash + export ENDPOINT="peregrine" + ``` + + Then run the setup with the following command: + + ```bash + docker run --rm -it -e "ENDPOINT=${ENDPOINT}" -v $(pwd):/data docker.io/kiltprotocol/opendid-setup:latest "${SEED}" + ``` + +The command generates a set of new mnemonics and then derives a DID from them and generates multiple files into the current directory: + +1. `config.yaml` The configuration file used by the OpenDID service. + + :::warning + You only need the `config.yaml` to run the OpenDID service. + This file includes the generated mnemonic and secret keys and you should protect it from unauthorized access. + ::: + +2. `did-secrets.json` This file contains the public and secret keys in the DID Document. + + :::warning + Keep a secure backup of this file as it contains all the secret keys. + ::: + +3. `did-document.json` contains the DID Document generated by this setup. + +The container generates sensible defaults in the `config.yaml` file, but here are some values you might want to change: + +- Set `production` to true, this only allows secure connections. +- Set the `WellKnownDid` > `origin`, which should match the host running the OpenDID service. +- Set the keys used for JWT issuance in the `jwt` section. +- The `client` section, including: + + - The client ID as a key (The default is: `example-client`). + - The `requirements` section, including: + + - What CTypes are required for authentication. + - The trusted attesters as an address (The default is for the [SocialKYC attester](https://socialkyc.io/)). + + :::note info + + The generated default `config.yaml` requires an [email credential](https://test.ctypehub.galaniprojects.de/ctype/kilt:ctype:0x3291bb126e33b4862d421bfaa1d2f272e6cdfc4f96658988fbcffea8914bd9ac) issued by an attester. + + ::: + + - What `redirect_url`s the service accepts (The default is `http://localhost:1606/callback.html` for the demo project). + - The `clientSecret` is optional but recommended. If you use the authorization code flow, the `token` endpoint requires it. + +## Run the service + +When you've made changes to the `config.yaml` file, you can run the OpenDID service. + +1. Specify the runtime through the `RUNTIME` environment variable: + + Set to `"spiritnet"` for production KILT + + ```bash + export RUNTIME="spiritnet" + ``` + + Set to `"peregrine"` for the KILT test net. + + ```bash + export RUNTIME="peregrine" + ``` + +2. Run the `docker.io/kiltprotocol/opendid` docker image. + + ```bash + docker run -d --rm \ + -v $(pwd)/config.yaml:/app/config.yaml \ + -v $(pwd)/checks:/app/checks \ + -e "RUNTIME=${RUNTIME}" \ + -p 3001:3001 \ + docker.io/kiltprotocol/opendid:latest + ``` + +3. Open the login page at _http://localhost:3001_. + +## Next steps + +With configuration in place and a service running, next you need to [integrate OpenDID into an application](./04_integrate_opendid.md) so that a user can use the login page. diff --git a/versioned_docs/version-0.35.0/develop/08_opendid/04_integrate_opendid.md b/versioned_docs/version-0.35.0/develop/08_opendid/04_integrate_opendid.md new file mode 100644 index 000000000..a0518be0b --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/08_opendid/04_integrate_opendid.md @@ -0,0 +1,126 @@ +--- +id: integrate_opendid +title: Integrate OpenDID +--- + +OpenDID follows the [OpenID Connect 1.0 Specification](https://openid.net/specs/openid-connect-core-1_0.html#Introduction) and implements both the [implicit flow](https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowSteps) +and the [authorization code flow](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth). +Read the [demo project guide](05_demo_project.md) for an example of integrating OpenDID. + +## Authorization code flow + +Initiate the flow by redirecting to the **GET** `/api/v1/authorize` endpoint on the OpenDID service and setting the following query URL-encoded parameters: + +- `response_type`: set value to `code` to indicate Authorization Code Flow. +- `client_id`: The client ID set in the `config.yaml` file. +- `redirect_uri`: OpenDID redirects to this URL after authentication. +- `scope`: set value to `openid`. +- `state`: set to a secure random number. +- `nonce`: optional value, set to a secure random number. + +**Example**: + +``` +GET /api/v1/authorize? + response_type=code& + client_id=example-client& + redirect_uri=http://localhost:1606/callback.html& + scope=openid& + state=rkw49cbvd4azu5dsln1xbl& + nonce=vedur4om49ei8w91jt7wt HTTP/1.1 +``` + +After successful authentication, the OpenDID service redirects back to the provided `redirect_uri` with `code` and `state` query parameters. + +**Example**: + +``` +/callback.html? + code=lwDS1ZpQBwR4Vdm53_L8bWpUJ1mx9A0mA_-86dubTqzqzwGazx1RyLX4Z_qf& + state=rkw49cbvd4azu5dsln1xbl +``` + +You can retrieve the `id_token` by calling the **POST** `/api/v1/token` and providing the following values in the form serialization: + +- `code`: code value returned from `authorize`. +- `grant_type`: set value to `authorization_code`. +- `redirect_uri`: the same `redirect_uri` used in `authorize`. +- `client_id`: the client ID set in the `config.yaml` file. +- `client_secret`: the client secret value set in the `config.yaml` file. + +**Example**: + +``` +POST /api/v1/token HTTP/1.1 +Content-Type: application/x-www-form-urlencoded + +code=lwDS1ZpQBwR4Vdm53_L8bWpUJ1mx9A0mA_-86dubTqzqzwGazx1RyLX4Z_qf& +grant_type=authorization_code& +redirect_uri=http%3A%2F%2Flocalhost%3A1606%2Fcallback.html& +client_id=example-client& +client_secret=insecure_client_secret +``` + +The OpenDID service returns the `id_token` in the response body serialized as a JSON object. + +```json +{ + "access_token": "SsFhhSBMWsLeDMxVUVGreKARNwYxMZtGFfBr0-ZiH6iondSmwPRvQDqkG6Fh", + "token_type": "bearer", + "refresh_token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkaWQ6a2lsdDo0b0VkNENVV3RwbkxUVnZENVBFd2lMUmlqMWdzQmprS1JMbVpES2lCOEdqN2I2V0wiLCJ3M24iOiJjdXN0b20iLCJleHAiOjE3MTY4MTYwNjQsImlhdCI6MTcxNjgxNTQ2NCwiaXNzIjoiZGlkOmtpbHQ6NHJzQkE3dEQ1S1E4TDlXSGpGallRdUhrTWtha2NmSGRDNUNhUVVjVXh5VWpEVkhBIiwiYXVkIjoiYXV0aGVudGljYXRpb24iLCJwcm8iOnsiRW1haWwiOiJhYmR1bEBraWx0LmlvIn0sIm5vbmNlIjoidmVkdXI0b200OWVpOHc5MWp0N3d0In0.yOmE_9jWKcAu8LpjVx7IsFyOOvlKbgo2oC4Imf-qrLY", + "id_token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkaWQ6a2lsdDo0b0VkNENVV3RwbkxUVnZENVBFd2lMUmlqMWdzQmprS1JMbVpES2lCOEdqN2I2V0wiLCJ3M24iOiJjdXN0b20iLCJleHAiOjE3MTY4MTU1MjQsImlhdCI6MTcxNjgxNTQ2NCwiaXNzIjoiZGlkOmtpbHQ6NHJzQkE3dEQ1S1E4TDlXSGpGallRdUhrTWtha2NmSGRDNUNhUVVjVXh5VWpEVkhBIiwiYXVkIjoiYXBwbGljYXRpb24iLCJwcm8iOnsiRW1haWwiOiJhYmR1bEBraWx0LmlvIn0sIm5vbmNlIjoidmVkdXI0b200OWVpOHc5MWp0N3d0In0.YlRE9EGnSExQCb5m2iy4__58PZJlZdCZMsSvsuW4oj8" +} +``` + +:::note +In full-stack applications, calling the `token` endpoint is usually done through the back end to improve security. +::: + +The `id_token` is a bearer JSON web token (JWT) signed by the JWT key-pair specified in the `config.yaml` file of the OpenDID service. +You must verify this using the JWT public key, for example, by the back end of the Web app. + +## Implicit flow + +Initiate the flow by redirecting to the **GET** `/api/v1/authorize` endpoint on the OpenDID Service and setting the following query parameters: + +- `response_type`: set value to `id_token` to indicate Implicit Flow. +- `client_id`: The client ID set in the config.yaml file. +- `redirect_uri`: OpenDID redirects to this URL after authentication. +- `scope`: set value to `openid`. +- `state`: set to a secure random number. +- `nonce`: optional value, set to a secure random number. + +**Example**: + +``` +GET /api/v1/authorize? + response_type=id_token& + client_id=example-client& + redirect_uri=http://localhost:1606/callback.html& + scope=openid& + state=o0fl4c9gwylymzw5f4ik& + nonce=ia7sa06ungxdfzaqphk2 HTTP/1.1 +``` + +After successful authentication, OpenDID redirects back to the provided `redirect_uri` with `id_token` and `state` +**fragment components**. + +**Example**: + +``` +/callback.html# + id_token=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkaWQ6a2lsdDo0b0VkNENVV3RwbkxUVnZENVBFd2lMUmlqMWdzQmprS1JMbVpES2lCOEdqN2I2V0wiLCJ3M24iOiJjdXN0b20iLCJleHAiOjE3MTY4ODQ5MDYsImlhdCI6MTcxNjg4NDg0NiwiaXNzIjoiZGlkOmtpbHQ6NHJzQkE3dEQ1S1E4TDlXSGpGallRdUhrTWtha2NmSGRDNUNhUVVjVXh5VWpEVkhBIiwiYXVkIjoiYXBwbGljYXRpb24iLCJwcm8iOnsiRW1haWwiOiJhYmR1bEBraWx0LmlvIn0sIm5vbmNlIjoiOTFzN2ZnZDZvcjR3c2NkdGVtcXQifQ.xTy3Oyc5e-vlP10mGy0f9GqNU4LV97s77s-l7w5EwF0& + refresh_token=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkaWQ6a2lsdDo0b0VkNENVV3RwbkxUVnZENVBFd2lMUmlqMWdzQmprS1JMbVpES2lCOEdqN2I2V0wiLCJ3M24iOiJjdXN0b20iLCJleHAiOjE3MTY4ODU0NDYsImlhdCI6MTcxNjg4NDg0NiwiaXNzIjoiZGlkOmtpbHQ6NHJzQkE3dEQ1S1E4TDlXSGpGallRdUhrTWtha2NmSGRDNUNhUVVjVXh5VWpEVkhBIiwiYXVkIjoiYXV0aGVudGljYXRpb24iLCJwcm8iOnsiRW1haWwiOiJhYmR1bEBraWx0LmlvIn0sIm5vbmNlIjoiOTFzN2ZnZDZvcjR3c2NkdGVtcXQifQ.87UHGid3OotxO8Wpfuw-1sc5fsQJVt5gc2cqp9dVHiw& + state=nitctpl7nmqcpvob7xthrw& + token_type=bearer +``` + +## Self-Issued OpenID Provider v2 (SIOPv2) + +You can configure OpenDID to be compatible with [SIOPv2](https://openid.net/specs/openid-connect-self-issued-v2-1_0.html). +In this case, you only need a DID for the authorization, and no credentials. +To configure the OpenDID service to allow SIOPv2, it must have a `client` key with an empty requirements +value in the `config.yaml` file. + +Initiate the SIOPv2 flow the same way as the [Implicit Flow](#implicit-flow) with the exception that the `nonce` +value is required. diff --git a/versioned_docs/version-0.35.0/develop/08_opendid/05_demo_project.md b/versioned_docs/version-0.35.0/develop/08_opendid/05_demo_project.md new file mode 100644 index 000000000..a4a334d35 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/08_opendid/05_demo_project.md @@ -0,0 +1,30 @@ +--- +id: demo_project +title: Demo Project +--- + +The example code at [demo-project](https://github.com/KILTprotocol/opendid/tree/main/demo-project) contains a minimal application that uses OpenDID. +It's an [express](https://expressjs.com) application that exposes three things: + +- A login page that handles the dispatching of the user to the OpenDID service. +- A callback page for one of the OpenID Connect flows supported to accept the token. +- A protected resource that only authenticated users can access. + +For the demo application to work you need a running OpenDID Service and an identity wallet that follows [the Credential API spec](https://github.com/KILTprotocol/spec-ext-credential-api) (e.g. [Sporran](https://www.sporran.org/)) with a DID and Credential issued by the required attester specified in the `config.yaml` file (Default is SocialKYC). +If you follow the steps in this section in order, you have all the necessary components for the demo application to run. + +Run the pre-configured demo application with the following command: + +```bash +docker run -d -it --rm \ + --name demo-frontend \ + -p 1606:1606 \ + docker.io/kiltprotocol/opendid-demo +``` + +The demo page runs on _http://localhost:1606_. It pre-fills the Client ID value and offers login buttons to follow the implicit or authorization code flow. + +:::note +You can set the JSON web token (JWT) secret can with the `TOKEN_SECRET` environment variable inside the docker container. It must match +the one specified in the `config.yaml` file to correctly verify the `id_token`. The default is `super-secret-jwt-secret`. +::: diff --git a/versioned_docs/version-0.35.0/develop/08_opendid/06_advanced.md b/versioned_docs/version-0.35.0/develop/08_opendid/06_advanced.md new file mode 100644 index 000000000..ec36cb8bb --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/08_opendid/06_advanced.md @@ -0,0 +1,111 @@ +--- +id: advanced +title: Advanced Usage +--- + +## Use dynamic client management with etcd + +To dynamically create or remove OpenID Connect clients, configure the service to get its configuration from an [etcd cluster](https://etcd.io) by adding the connection parameters for the cluster in the `config.yaml` file. + +```yaml +etcd: + endpoints: ['localhost:2379'] + user: etcd-user + password: my-password + tlsDomainName: my.etcd.cluster.example.com + tlsCaCert: | + -----BEGIN CERTIFICATE----- + + -----END CERTIFICATE----- + tlsClientCert: | + -----BEGIN CERTIFICATE----- + + -----END CERTIFICATE----- + tlsClientKey: | + -----BEGIN RSA PRIVATE KEY----- + + -----END RSA PRIVATE KEY----- +``` + +All fields except `endpoints` are optional. +When everything is set up you can start adding client configurations into the etcd cluster. + +```bash +CLIENT_SPEC=$(cat < remote switches. The reverse is assumed to happen via XCM reserve transfer from the configured remote location, for which the pallet crate provides all the XCM components that are dynamically configured based on the switch pair information stored within each instance of this pallet. +* The sovereign account of the source chain at destination owns the remote assets in the amount that is specified when the switch pair is created. The validation of this requirement is delegated to the source chain governance in the act leading to the creation of the switch pair, as the source chain itself has currently no means of doing that. +* To account for failure on the remote destination, the pallet stores unconfirmed operations in a storage map. The remote chain then sends `Report` messages back to either confirm or revert a transfer. In the meanwhile, the source chain (where this pallet is deployed) assumes the transfer will be successful and updates all related counters tracking the destination state, to then revert them in case of failures. + +## Add the pallet to the runtime + +Add the following line to the runtime `Cargo.toml` dependencies section: + +```toml +pallet-asset-switch = {git = "https://github.com/KILTprotocol/kilt-node.git", branch = "release-1.14.0"} +``` + +The asset switch pallet is available in the KILT node release 1.14.0 and later. + +## Configure the pallet + +The pallet can be added one or more times to the runtime. + +For multiple deployments of the same pallet (e.g., to bridge the local currency to different remote assets), pass runtime configuration to the pallet's `Config` trait. + +```rust,ignore +pub type SwitchPool1 = pallet_asset_switch::Instance1; +impl pallet_asset_switch::Config for Runtime { + // Config +} + +pub type SwitchPool2 = pallet_asset_switch::Instance2; +impl pallet_asset_switch::Config for Runtime { + // Config +} +``` + +If a single instance is required, then use the default instance: + +```rust,ignore +impl pallet_asset_switch::Config for Runtime { + // Config +} +``` + +## The `Config` trait + +As the pallet is generic over the runtime specifics, the `Config` trait requires the following configuration parameters passed to it: + +- `type AccountIdConverter: TryConvert`: Because the `AccountId` type can be anything in the runtime, the converter is responsible for converting such a `AccountId` into a `Junction`, which is then used for some XCM processing. +- `type AssetTransactor: TransactAsset`: This component is used when charging the extrinsic submitter with the XCM fees that the chain will pay at the remote chain. For instance, if the transfer on the remote chain will cost 0.1 DOTs, the `AssetTransactor` might deduct 0.1 DOTs from the user's previously topped up balance on the source chain (more details below). +- `type FeeOrigin: EnsureOrigin`: The origin that can update the XCM fee to be paid for the transfer on the remote chain. +- `type LocalCurrency: MutateFungible`: The chain's local currency. +- `type PauseOrigin: EnsureOrigin`: The origin that can pause a switch pair, e.g., if a vulnerability is found. +- `type RuntimeEvent: From> + IsType<::RuntimeEvent>`: The aggregate `Event` type. +- `type SubmitterOrigin: EnsureOrigin`: The origin that can call the `switch` extrinsic and perform the switch. +- `type SwitchHooks: SwitchHooks`: Any additional runtime-specific logic that can be injected both before and after local tokens are exchanged for the remote assets, and before and after the remote assets are converted into local tokens. +- `type SwitchOrigin: EnsureOrigin`: The origin that can set, resume, and delete a switch pair. +- `type UniversalLocation: Get`: The location of the parachain relative to the global consensus space. +- `type WeightInfo: WeightInfo`: The computed weights of the pallet after benchmarking it. +- `type XcmRouter: SendXcm`: The component responsible for routing XCM messages to the switch pair remote location to perform the remote asset transfer from the chain's sovereign account to the specified beneficiary. + +### Benchmark-only `Config` components + +- `type BenchmarkHelper: BenchmarkHelper`: Helper trait to allow the runtime to set the ground before the benchmark logic is executed. It allows the runtime to return any of the parameters that are used in the extrinsic benchmarks, or `None` if the runtime has no special conditions to fulfil. + +## Storage + +The pallet has a single `SwitchPair` storage value that contains a `Option`. +If unset, no switch pair is configured hence no switch can happen. +When set and its status is `Running`, switches are enabled in both directions. + +Two more storage components, `PendingSwitchConfirmations` and `NextQueryId`, are used for error recovery. +Specifically, the former stores information about transfers executed locally but that have not been confirmed on the remote destination. +Once a transfer either succeeds or fails, the entry is removed from the storage and additional actions are taken as needed, e.g., reverting the transfer locally as well.Th +The latter stores an ever-increasing counter, which wraps around itself when it would overflow, and provides the value the `PendingSwitchConfirmations` storage map uses to keep track of pending confirmations. + +## Events + +The pallet generates the following events: + +- `SwitchPairCreated`: when a new switch pair is created by the required origin, e.g., governance. +- `SwitchPairRemoved`: when a switch pair is removed by the root origin. +- `SwitchPairResumed`: when a switch pair has (re-)enabled local to remote asset switches. +- `SwitchPairPaused`: when a switch pair has been paused. +- `SwitchPairFeeUpdated`: when the XCM fee for the switch transfer has been updated. +- `LocalToRemoteSwitchExecuted`: when a switch of some local tokens for the remote asset has taken place. +- `RemoteToLocalSwitchExecuted`: when a switch of some remote assets for the local tokens has taken place. +- `LocalToRemoteSwitchReverted`: when a switch fails on the remote destination and is reverted on the source chain as well. +- `LocalToRemoteSwitchFinalized`: when a switch is confirmed to have successfully taken place at the remote destination. + +## Calls + +1. `pub fn set_switch_pair(origin: OriginFor, remote_asset_total_supply: u128, remote_asset_id: Box, remote_asset_circulating_supply: u128, remote_reserve_location: Box, remote_asset_ed: u128, remote_xcm_fee: Box) -> DispatchResult`: Set a new switch pair between the local currency and the specified `remote_asset_id` on the `reserve_location`. The specified `total_issuance` includes both the `circulating_supply` (i.e., the remote asset amount that the chain does not control on the `reserve_location`) and the locked supply under the control of the chain's sovereign account on the `reserve_location`. For this reason, the value of `total_issuance` must be at least as large as `circulating_supply`. It is possible for `circulating_supply` to be `0`, in which case it means this chain controls all the `total_issuance` of the remote asset, which can be obtained by locking a corresponding amount of local tokens via the `switch` call below. + + Furthermore, the pallet calculates the account that will hold the local tokens locked in exchange for remote tokens. This account is based on the pallet runtime name as returned by the `PalletInfoAccess` trait and the value of `remote_asset_id`. The generated account must already have a balance of at least `circulating_supply`, ensuring enough local tokens are locked to satisfy all requests to exchange the remote asset for local tokens. The balance of such an account can be increased with a simple transfer after obtaining the to-be-created switch pair pool account by interacting with the [asset-switch runtime API][asset-switch-runtime-api]. + + This requirement can be bypassed with the `force_set_switch_pair` call. Only `SwitchOrigin` can call this, and in most cases it will most likely be a governance-based origin such as the one provided by referenda or collectives with high privileges. +2. `pub fn force_set_switch_pair(origin: OriginFor, remote_asset_total_supply: u128, remote_asset_id: Box, remote_asset_circulating_supply: u128, remote_reserve_location: Box, remote_asset_ed: u128, remote_xcm_fee: Box) -> DispatchResult`: The same as the `set_switch_pair`, but skips the check over the switch pair pool account balance, and requires the `root` origin for the call to be dispatched. +3. `pub fn force_unset_switch_pair(origin: OriginFor) -> DispatchResult`: Forcibly remove a previously-stored switch pair. This operation can only be called by the `root` origin. + + **Any intermediate state, such as local tokens locked in the switch pair pool or remote assets that are not switchable anymore for local tokens, must be taken care of with subsequent governance operations.** +4. `pub fn pause_switch_pair(origin: OriginFor) -> DispatchResult`: Allows the `PauseOrigin` to immediately pause switches in both directions. +5. `pub fn resume_switch_pair(origin: OriginFor) -> DispatchResult`: Allows the `SwitchOrigin` to resume switches in both directions. +6. `pub fn remote_xcm_fee(origin: OriginFor, new: Box) -> DispatchResult`: Allows the `FeeOrigin` to update the required XCM fee to execute the transfer of remote asset on the reserve location from the chain's sovereign account to the beneficiary specified in the `switch` operation. + + For example, if the cost of sending an XCM message containing a `TransferAsset` instruction from the source chain to AssetHub (reserve location) changes from 0.1 DOTs to 0.2 DOTs, the fee will need to be updated accordingly to avoid transfers failing on AssetHub, leaving the whole system in an inconsistent state. Since the pallet refunds any unused assets on the reserve location to the account initiating the switch on the source chain, it is not a big issue to overestimate this value here since no funds will be burnt or unfairly taken from the user during the switch process. +7. `pub fn switch(origin: OriginFor, local_asset_amount: LocalCurrencyBalanceOf, beneficiary: Box) -> DispatchResult`: Allows the `SubmitterOrigin` to perform a switch of some local tokens for the corresponding amount of remote assets on the configured `reserve_location`. The switch will fail on the source chain if any of the following preconditions are not met: + 1. The submitter does not have enough balance to pay for the tx fees on the source chain or to cover the amount of local tokens requested. Hence, the user's local balance must be greater than or equal to the amount of tokens requested in the switch + the cost of executing the extrinsic on the source chain. + 2. No switch pair is set or the switch pair is currently not allowing switches. + 3. There are not enough locked remote assets on the `reserve_location` to cover the switch request. e.g., if the chain sovereign account on the `reserve_location` only controls `10` remote assets, users can only switch up to `10` local tokens. Once the limit is reached, someone needs to perform the reverse operation (remote -> local switch) to free up some remote tokens. + 4. The switch pair `reserve_location` is not reachable from the source chain, because the configured `XcmRouter` returns an error (e.g., there is no XCM channel between the two chains). + 5. The configured `SwitchHooks` returns an error in either the `pre-` or the `post-` switch checks. + 6. The user does not have enough assets to pay for the required remote XCM fees as specified in the switch pair info and as returned by the configured `AssetTransactor`. + +## XCM components + +Because the switch functionality relies on XCM, the pallet provides a few XCM components that should be included in a runtime to enable the whole set of interactions between the source chain and the configured remote reserve location. + +* `AccountId32ToAccountId32JunctionConverter` in [xcm::convert][xcm-convert]: provides an implementation for the pallet's `AccountIdConverter` config component, that converts local `AccountId32`s into a `AccountId32` XCM `Junction`. This works only for chains that use `AccountId32` as their overarching `AccountId` type. +* `MatchesSwitchPairXcmFeeFungibleAsset` in [xcm::match][xcm-match]: provides an implementation of the `MatchesFungibles` that returns the input `Asset` if its ID matches the XCM fee asset ID as configured in the switch pair, if present. If no switch pair is present or if the ID does not match, it returns a [XcmExecutorError::AssetNotHandled][XcmExecutorError::AssetNotHandled], which does not prevent other matchers after it to apply their matching logic. It can be used for the `AssetTransactor` property of the [XcmExecutor::Config][XcmExecutor::Config] and as the `AssetTransactor` component of this pallet in the runtime. +* `UsingComponentsForXcmFeeAsset` in [xcm::trade][xcm-trade]: provides an implementation of `WeightTrader` that allows buying weight using the XCM fee asset configured in the switch pair. That is, if the XCM fee asset is DOT, and users need to send DOTs to this chain in order to pay for XCM fees, this component lets them use those very same DOTs that are being sent to pay for the XCM fees on this chain. Any unused weight is burnt, since this chain's sovereign account already controls the whole amount on the reserve location due to the nature of reserve-based transfers. It can be used for the `Trader` property of the [XcmExecutor::Config][XcmExecutor::Config]. +* `UsingComponentsForSwitchPairRemoteAsset` in [xcm::trade][xcm-trade]: provides an implementation of `WeightTrader` that allows buying weight using the remote asset configured in the switch pair when sending it to this chain to be switched for local tokens. Any unused weight is transferred from the switch pair account to the configured `FeeDestinationAccount`, as those local tokens do not need to back any remote assets because they have been used to pay for XCM fees. It can be used for the `Trader` property of the [XcmExecutor::Config][XcmExecutor::Config]. +* `SwitchPairRemoteAssetTransactor` in [xcm::transact][xcm-transact]: provides an implementation of `TransactAsset::deposit_asset` that matches the asset to be deposited with the remote asset configured in the switch pair '(else it returns [Error::AssetNotFound][Error::AssetNotFound]) and moves as many local tokens from the switch pair account to the specified `who` destination. It also calls into the `SwitchHooks` pre- and post- checks, and generates a `RemoteToLocalSwitchExecuted` if everything is completed successfully. It can be used for the `AssetTransactor` property of the [XcmExecutor::Config][XcmExecutor::Config]. +* `IsSwitchPairXcmFeeAsset` in [xcm::transfer][xcm-transfer]: provides an implementation of `ContainsPair` that returns `true` if the given asset and sender match the stored switch pair XCM fee asset and reserve location respectively. It can be used for the `IsReserve` property of the [XcmExecutor::Config][XcmExecutor::Config]. +* `IsSwitchPairRemoteAsset` in [xcm::transfer][xcm-transfer]: provides an implementation of `ContainsPair` that returns `true` if the given asset and sender match the stored switch pair remote asset and reserve location respectively. It can be used for the `IsReserve` property of the [XcmExecutor::Config][XcmExecutor::Config]. + +The pallet itself implements the [OnResponse trait][on-response-trait], that must be added to runtimes that deploy this pallet to allow for the error-recovery process to take place. +The trait implementation validates the received query response message based on the state of the switch pair, and then performs the required action on the pending transfer info accordingly. + +[asset-switch-runtime-api]: https://github.com/KILTprotocol/kilt-node/tree/master/runtime-api/asset-switch +[xcm-convert]: https://raw.githubusercontent.com/KILTprotocol/kilt-node/master/pallets/pallet-asset-switch/src/xcm/convert/mod.rs +[xcm-match]: https://raw.githubusercontent.com/KILTprotocol/kilt-node/master/pallets/pallet-asset-switch/src/xcm/match/mod.rs +[XcmExecutorError::AssetNotHandled]: https://github.com/paritytech/polkadot-sdk/blob/33324fe01c5b1f341687cef2aa6e767f6acf40f3/polkadot/xcm/xcm-executor/src/traits/token_matching.rs#L54 +[XcmExecutor::Config]: https://github.com/paritytech/polkadot-sdk/blob/33324fe01c5b1f341687cef2aa6e767f6acf40f3/polkadot/xcm/xcm-executor/src/config.rs#L31 +[xcm-trade]: https://raw.githubusercontent.com/KILTprotocol/kilt-node/master/pallets/pallet-asset-switch/src/xcm/trade/mod.rs +[Error::AssetNotFound]: https://github.com/paritytech/polkadot-sdk/blob/e5791a56dcc35e308a80985cc3b6b7f2ed1eb6ec/polkadot/xcm/src/v3/traits.rs#L68 +[xcm-transact]: https://raw.githubusercontent.com/KILTprotocol/kilt-node/master/pallets/pallet-asset-switch/src/xcm/transact/mod.rs +[xcm-transfer]: https://raw.githubusercontent.com/KILTprotocol/kilt-node/master/pallets/pallet-asset-switch/src/xcm/transfer/mod.rs +[on-response-trait]: https://github.com/paritytech/polkadot-sdk/blob/33324fe01c5b1f341687cef2aa6e767f6acf40f3/polkadot/xcm/xcm-executor/src/traits/on_response.rs#L29 diff --git a/versioned_docs/version-0.35.0/develop/09_polarpath/_category_.json b/versioned_docs/version-0.35.0/develop/09_polarpath/_category_.json new file mode 100644 index 000000000..e617cba37 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/09_polarpath/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Polar path", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/develop/_category_.json b/versioned_docs/version-0.35.0/develop/_category_.json new file mode 100644 index 000000000..84922e6c0 --- /dev/null +++ b/versioned_docs/version-0.35.0/develop/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Develop", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/01_overview.md b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/01_overview.md new file mode 100644 index 000000000..319e47579 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/01_overview.md @@ -0,0 +1,46 @@ +--- +id: overview +title: Overview +--- + +Collators are the most important members of the network as they not only maintain the state by running a KILT full node, but are also allowed to change it by building state transition proofs and sharing them with the Relay Chain validators. +Generally speaking, the latter finalize the proposed block if and only if it represents a valid state transition. + +It is important to note that elusive collators can never get invalid blocks finalized thanks to the design security umbrella provided by the Relay Chain. +Thus, the most harm dishonest collators can do is to slow down or halt the network. +As long as at least one honest collator exists, the parachain is secured and fully operative. +However, the block time would be slower than with a full set of honest and functioning collator nodes. + +If you want to join the KILT network as a collator, you have to run a full node of the blockchain and set up your session keys. +You are also required to hold a minimum amount of self-staked tokens to qualify for a collator seat. +Once you have finished the mandatory steps described throughout the following sections, you can be added to the candidate pool. +The candidate pool is sorted first by the total staking amount including delegations. +If the pool is full and the new candidate has the exact same stake amount as the last member of the pool (by total stake), the blockchain favors the candidate that has been in the pool longest. +Thus, only the collators with the highest total stake are periodically selected to be eligible block authors. + +:::info +You can find more information about collators and the Relay Chain-parachain-interaction in the [**official Polkadot Wiki**](https://wiki.polkadot.network/docs/learn-collator). +::: + +## Roadmap + +We will guide you through the steps to become a collator. +First, we will discuss the hardware requirements and how you could test the performance of your node. +Then, we go over a few configuration options and show you how to set up and start a KILT collator, including how to generate your sessions keys and join the pool of collator candidates. + +:::info +In case you are already collating, you could check out the advanced section. +There you will learn how to [**monitor**](../02_advanced_collator_section/04_monitoring.md) or [**benchmark**](../02_advanced_collator_section/06_benchmarking.md) your node, [**adjust your stake**](../02_advanced_collator_section/01_adjust_stake.md), [**fix problems**](../06_troubleshooting.md) or [**leave the network**](../02_advanced_collator_section/02_exit.md). +::: + +## Join the Community + +As a collator you are required to keep track of updates and changes to configuration. +You should also be accessible in case there is an issue with your node, as this affects not only your and your delegator's rewards, but also the entire network negatively. +We recommend joining the [KILT Community Discord server](https://discord.gg/hX4pc8rdHS) and following (at least) the **collators** and **staking** channels. +There, you will receive announcements about future updates and potential mandatory client upgrades. +Moreover, the channels serve as a discussion hub for collators and delegators. + +After joining Discord, feel free to send a DM to [`Dudley | KILT protocol#6222`](https://discordapp.com/users/687952993156726784) or [`William | KILT Protocol#4433`](https://discordapp.com/users/w3n;williamfreude#4433) to introduce yourself. +Of course, you can also directly announce yourself in one of the two channels mentioned above. +This way, the community knows who to contact in case there are any issues with your node. diff --git a/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/02_hardware_requirements.md b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/02_hardware_requirements.md new file mode 100644 index 000000000..c590b8349 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/02_hardware_requirements.md @@ -0,0 +1,16 @@ +--- +id: hardware-requirements +title: Minimum Hardware Requirements +--- + +The KILT blockchain extrinsic weights were calculated using the following hardware: + +- **OS** - Ubuntu 20.04.2 +- **CPU** - AMD Ryzen 7 1700X +- **Storage** - A NVMe solid-state drive. Should be reasonably-sized to deal with blockchain growth. Starting around 250GB will be okay for the next year of the KILT parachain and Polkadot Relay Chain, but it will mostly likely grow after that and will have to be re-evaluated on a regular basis. +- **Memory** - 16GB + +Although the aforementioned hardware is by no means the minimum spec required, the new node *is recommended* to be as close as possible to these capabilities in all the categories. +Having more performant hardware reduces the probability that the node will not be able to produce and propose a valid block on time during the allocated block production slot, missing out on the collating rewards. + +You can measure the performance of the new hardware by benchmarking it using [the steps described in the benchmarking section](../02_advanced_collator_section/06_benchmarking.md). diff --git a/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/03_setup_node.md b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/03_setup_node.md new file mode 100644 index 000000000..f029d5870 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/03_setup_node.md @@ -0,0 +1,183 @@ +--- +id: setup-node +title: Set Up a Node +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import StartNodeDocker from './_03_start_node_docker.mdx'; +import StartNodeBinary from './_03_start_node_binary.mdx'; + +There are several ways to build and run a collator node. +Here, we show both how to use a Docker image and how to compile the source code directly from [our chain repository](https://github.com/KILTprotocol/kilt-node). + +There are currently two different runtimes (i.e., two different parachain environments) that a KILT collator can be part of: + +- **Spiritnet**: the official public network, which contains only stable and thoroughly-tested features. +- **Peregrine**: the public test network whose runtime is as close to that of Spiritnet as possible. It can be used to try things out before executing them on the production Spiritnet chain, which involves spending tokens that have real monetary value. + +Each runtime has its own benchmark measurements. + +:::info +The remainder of this guide explaining how to set up and run a collator is mainly for the official **Spiritnet** parachain. +However, we recommend trying out the setup on our Peregrine testnet first. +Hence, at each step where it is applicable, we indicate what differs between the Peregrine and Spiritnet configuration for the collator node to join either network. +::: + +## Configuration + +Running a collator requires a few configuration parameters. +Some of the parameters might appear twice in the command to start the collator, because a parachain collator actually runs two blockchains. +The parameters that are listed before the `--` are related to the parachain node itself (the KILT blockchain), whereas the parameters following the `--` are related to the Relay Chain, e.g., Kusama or Polkadot. + +The following is a description of some of the parameters that can be set when spinning up a parachain collator node. + +### RPC and WS Endpoints + +As a collator, you need to link your session keys to your collator account. +These session keys can be generated by calling an RPC endpoint that the collator optionally exposes. +Exposing the RPC endpoint can be done using the following parameters: + +``` +--rpc-port=9944 +--rpc-cors=all +--rpc-methods=unsafe +--unsafe-rpc-external // ONLY for Docker-based setups +``` + +Exposing the RPC endpoint of a collator does not imply that it becomes accessible via the PolkadotJS Apps interface, because this requires a WebSocket to connect to the node. + +By default, the WebSocket port used by the node is configured to be `9944`, but it can be changed by specifying a different value with `--rpc-port=`. + +Connecting from a remote host to either the collator RPC endpoint or WS endpoint requires explicitly exposing the endpoint to the public with the `--rpc-external` option. + +:::danger + +Be aware that it is highly discouraged to publicly expose an RPC endpoint, especially if it allows the execution of unsafe RPC calls! +You should be the only one able to call the RPC endpoint. +For a secure setup, follow the instructions in the previous section about [generating the session keys](./04_session_keys.md). +::: + +### WASM Runtime Execution + +A KILT collator node should use the `--execution=wasm` parameter for both the Relay Chain and parachain collation. +The alternative to WASM runtime execution is native runtime execution, which might be faster but can, in some cases, deviate from the WASM execution logic and result in a different state. +When this happens, the collator node will crash and will stop synchronizing with the network and stop producing blocks. +Since the WASM runtime logic is part of the blockchain state itself and hence represents the single source of truth, all nodes should execute the WASM version of the runtime logic. + +### Specify the Right Chainspec + +The `--chain` parameter indicates which blockchain the KILT collator node will join. +This parameter must be specified for both the parachain **and** the Relay Chain, since both chains are, as a matter of fact, separate blockchains. +The KILT parachain accepts an additional parameter to select the environment to use for the WASM runtime execution. +This can either be `peregrine` or `spiritnet`. + +Hence, to start a collator node for the Spiritnet network, the parameter would be `--chain=spiritnet`. +Unfortunately, there is no hardcoded chain spec for the Peregrine network, so the full path of the chainspec file must be provided `--chain=/node/dev-specs/kilt-parachain/peregrine-kilt.json`. +Please refer to the [KILT node repository](https://github.com/KILTprotocol/kilt-node/blob/master/chainspecs/peregrine/peregrine-paseo.json) or the [Docker image](https://hub.docker.com/r/kiltprotocol/kilt-node/tags) for more information. + +### Specify the Blockchain Storage Path + +The `--base-path` parameter specifies where all the persistent files must be stored. +By default, the session keys will also be stored in the *base path*, but we recommend separating them from the other files. +This makes sure that the keyfiles are not accidentally lost or published when the blockchain database is either backed up or restored. +You can configure where to store the session keys using the `--keystore-path` option. +Since the collator will collate only for the parachain, there is no need to add this to the relaychain part of the command. + +## Obtain the Node Executable + + + + +In order to build the KILT full node executable, you need to have [rustup and Rust installed](https://www.rust-lang.org/tools/install). + +After cloning the repository, you can build the executable by running the `cargo build` command below from the root directory. + +```bash +# Clone the repository +git clone https://github.com/KILTprotocol/kilt-node.git +# Check out master branch +git checkout master +# Build the executable from source enabling all the optimizations with --release. +cargo build --release -p kilt-parachain +``` + +:::info +You must not use the default `develop` branch to build the executable. +Instead, the [latest release](https://github.com/KILTprotocol/kilt-node/releases) from `master` should be used. +::: + +The compiled executable can be found in `./target/release/kilt-parachain` after the build process completes successfully. + + + + +Simply pull the [latest Docker image](https://hub.docker.com/r/kiltprotocol/kilt-node/tags): + +```bash +docker pull kiltprotocol/kilt-node:latest +``` + + + + +## Start the Node + + + + + +In either case, if the node needs to be reachable via PolkadotJS Apps, the `--rpc-external` flag must be added to the collator options, before the `--` divider. + + + + + +In either case, if the node needs to be reachable via PolkadotJS Apps, the `--rpc-external` flag must be added to the collator options, before the `--` divider, and the WS port must be exposed from the container with an additional `-p 9944:9944` parameter. +Make sure that you only expose the websocket port publicly if you are not running a collator. + +In addition to the websocket, you need to expose the ports for p2p connections. +In the the command above these are `30333` for the parachain and `30334` for the relaychain. +Make sure you configure your firewall in a way that allows incoming and outgoing connections to these ports. + +The Docker command will map the database files for the Relay Chain and parachain as well as the keystore directory to `~/data` on the host system using the flag `-v $HOME/data:/data`. +That way the blockchain database files are not lost when and if the Docker container is removed and can be mounted back on the next containers. + +The Docker container runs as an user with id 1000 and will try to access the mapped volume and the files it contains. +If the files are not owned by a user with id 1000, this will result in an error. +If that is the case, run `sudo chown -R 1000:1000 $HOME/data` to give the container access. + + + + +## Sync the Blockchain State + +Before a collator can author blocks, the node needs to fully sync up with both the parachain and the Relay Chain. +Depending on the size of the blockchain states, it may take a number of hours to few days for the node to catch up. +More details can be found on the [Polkadot network docs](https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#synchronize-chain-data). + +:::note Example of node sync: + +```Example of node sync +2021-06-17 02:34:34 ๐Ÿ” Discovered new external address for our node: /ip4/100.102.231.64/tcp/30333/ws/p2p/12D3KooWLE7ivpuXJQpFVP4fuuutAqEsk8nrNEpuR3tddqnXgLPB +2021-06-17 02:34:36 โš™๏ธ Syncing 409.2 bps, target=#8062689 (5 peers), best: #3477 (0x63adโ€ฆe046), finalized #3072 (0x0e4cโ€ฆf587), โฌ‡ 153.2kiB/s โฌ† 12.9kiB/s +2021-06-17 02:34:37 ๐Ÿ” Discovered new external address for our node: /ip4/100.111.175.0/tcp/30333/ws/p2p/12D3KooWLE7ivpuXJQpFVP4fuuutAqEsk8nrNEpuR3tddqnXgLPB +2021-06-17 02:34:38 ๐Ÿ” Discovered new external address for our node: /ip4/100.100.176.0/tcp/30333/ws/p2p/12D3KooWLE7ivpuXJQpFVP4fuuutAqEsk8nrNEpuR3tddqnXgLPB +2021-06-17 02:34:41 โš™๏ธ Syncing 386.2 bps, target=#8062690 (7 peers), best: #5409 (0x1d76โ€ฆ8c3d), finalized #5121 (0x8ad1โ€ฆb6dc), โฌ‡ 96.1kiB/s โฌ† 10.9kiB/s +2021-06-17 02:34:46 โš™๏ธ Syncing 394.8 bps, target=#8062691 (11 peers), best: #7383 (0x0689โ€ฆ6f1e), finalized #7168 (0x72a9โ€ฆ8d8c), โฌ‡ 352.9kiB/s โฌ† 5.1kiB/s +2021-06-17 02:34:51 โš™๏ธ Syncing 347.0 bps, target=#8062692 (12 peers), best: #9118 (0x66fcโ€ฆcce3), finalized #8704 (0x14c9โ€ฆ705e), โฌ‡ 62.7kiB/s โฌ† 1.7kiB/s +``` + +::: diff --git a/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/04_session_keys.md b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/04_session_keys.md new file mode 100644 index 000000000..b061db105 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/04_session_keys.md @@ -0,0 +1,124 @@ +--- +id: session-keys +title: Set and Rotate Session Keys +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +As a collator, you need to link your session keys to your collator account. +Once linked, the keys are used to identify your collator node. +Your collator address will receive the permit to build blocks, but the session keys pass this permit to your node. +To check whether the account has already some session keys set, the RPC functions `author > hasKey(publicKey, keyType)` and `author > hasSessionKeys(sessionKeys)` can be called. + +![](/img/chain/author-hasKey.png) + +:::info +The session keys associate a collator node with an account on the blockchain. +They are hot keys that must be kept online. +It is recommended to change them throughout sessions. +::: + +## Generate New Session Keys {#generating-session-keys} + +:::warning + +Make sure that no unauthorized party is able to access the RPC endpoint of the collator. +Use SSH forwarding for the RPC port when needing to perform some RPC operations on the node with + +``` +ssh -L 127.0.0.1:9944:127.0.0.1:9944 @ +``` +::: + +There are three ways to create the session keys. +We recommend using the curl command on the same host that the node is running or from a host that has an active SSH tunnel with it. +This way there is no need to add the `--unsafe-rpc-external` argument to the node. +Nevertheless, the session keys can also be rotated using the PolkadotJS Apps interface or by directly storing the new key in the node's keystore. + + + + + +A collator can use the following command to rotate the session key. + +```bash +curl -H "Content-Type: application/json" -d '{"id":1, "jsonrpc":"2.0", "method": "author_rotateKeys", "params":[]}' http://localhost:9944 +``` + +The answer should look like the JSON object below. +The `result` key is the HEX-encoded public part of the newly created session key. + +``` +{"jsonrpc":"2.0","result":"0xda3861a45e0197f3ca145c2c209f9126e5053fas503e459af4255cf8011d51010","id":1} +``` + + + + +In order to use the PolkadotJS Apps UI, the node WebSocket endpoint must be reachable. +This can be done either by publicly exposing it with the `--rpc-external` flag, which is discouraged, or by setting up an SSH tunnel for the WebSocket endpoint with `ssh -L 127.0.0.1:9944:127.0.0.1:9944 @`. +If the latter option is chosen, there is no need to have a separate SSH tunnel for RPC traffic as all the RPC operations can be performed directly from the now-accessible PolkadotJS Apps interface. + +![](/img/chain/chain-menu.png) + +![](/img/chain/chain-selection.png) + +After connecting to the node, select `Developer -> RPC calls -> author -> rotateKeys()` from the menu. +This will generate a new session key which replaces the existing one. + +![](/img/chain/author-rotateKeys.png) + + + + +A keypair can be created using the [subkey tool](https://substrate.dev/docs/en/knowledgebase/integrate/subkey) by following the steps in the tool's official documentation. +The generated private and public keys can then be saved within the keystore folder of the collator node to be used as session keys. + +``` +โฏ subkey generate -n kilt +Secret phrase `very secure private key you should not use the example private key` is account: + Secret seed: 0xcafe97b4b8f0adc1adeb3feef30bf2e5b9d49ddd897f268c8027c850DeadBEEF + Public key (hex): 0xda3861a45e0197f3ca145c2c209f9126e5053fas503e459af4255cf8011d51010 + Account ID: 0xda3861a45e0197f3ca145c2c209f9126e5053asdg03e459af4255cf8011d51010 + SS58 Address: 4srC1aowD94H9UH9xsnfv7XV6oHU6dhCymKYZHWKsdddaP29 +``` + +The name of the file must be the *public* key prepended with `61757261` (HEX representation of `aura`) and without the `0x` prefix, while the content of the file has to be the secret phrase. + +![](/img/chain/session-key-file.png) + +For instance, with the keypair generated in the example, the session key file would be stored at the path `./keystores/61757261da3861a45e0197f3ca145c2c209f9126e5053fas503e459af4255cf8011d51010`. + + + + + +:::info +The rotation of the session key should be done periodically to ensure that your collator can remain secure and safe from attacks. +You can find more information about session keys in the [Substrate Documentation](https://docs.substrate.io/v3/concepts/session-keys/#generation-and-use). +::: + +Once a new session key is generated, you must then link that key to your collator account in order to receive rewards for producing new blocks.. +This operation is performed by submitting a signed extrinsic to the blockchain. + +For Spiritnet, the endpoint is [wss://spiritnet.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkilt-rpc.dwellir.com#/explorer), while for Peregrine it is [wss://peregrine.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine-stg.kilt.io#/explorer). + +`Developer -> Extrinsics -> Submission` + +1. Select your collator KILT address as the extrinsic submitter (the *using the selected account* field) +2. Set up the following extrinsic: `session -> setKeys(keys, proof)` + - `keys` -> the public session key (`0xda3861a45e0197f3ca145c2c209f9126e5053fas503e459af4255cf8011d51010` in the example above) + - `proof` -> the proof of ownership. It can be set to `0x00` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/session-setKeys.png) + +Once the extrinsic is executed, you will have linked the new session key to your account and can start receiving rewards for producing new blocks. +However, the new session key does not become effective immediately but with the start of the next session. diff --git a/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/05_join_collators.md b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/05_join_collators.md new file mode 100644 index 000000000..a47b46e64 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/05_join_collators.md @@ -0,0 +1,62 @@ +--- +id: join +title: Join the Collator Candidate Pool +--- + +import StakingTxDisclaimer from '../_disclaimer_staking_tx.md'; + +Before a collator can author blocks, the node needs to fully sync up with both the KILT parachain and the Polkadot Relay Chain. +Depending on the size of the blockchain states, it may take from a number of hours to few days for the node to fully synchronize. +More details can be found on the [Polkadot network docs](https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#synchronize-chain-data). + +After you have finished with the setup, you can finally tell the chain that you are ready to collate and join the pool of candidates. + +:::warning +These steps should be followed only once your collator node has successfully [**linked a session key to its address**](./04_session_keys.md) and synced the parachain and relaychain states by following the previous steps. +::: + +## Minimum Token Requirement + +The maximum number of **active** collators is currently (2022-05-05) 16 on Peregrine and 30 on Spiritnet. + +In order to become a collator, you must stake +- at least *10,000 KILT* tokens and +- at most *200,000 KILT* tokens. + +## Execute the Joining Transaction + +The collator must call an extrinsic `parachainStaking -> joinCandidates(stake)` with the desired stake to join the candidate pool. + + + +![](/img/chain/parachainStaking-joinCandidates.png) + +1. Select your collator KILT address as the extrinsic submitter (the *using the selected account* field) +2. Select the following extrinsic: `parachainStaking -> joinCandidates(stake)` +3. Insert the staked KILT amount for your collator (any value between `10,000,000,000,000,000,000` and `20,000,000,000,000,000,0000`) +4. Sign and submit the extrinsic (the *Submit Transaction* button) + +:::info +A recent change in the blockchain metadata resulted in a change in the UI regarding how balances are shown. +In the current version of PolkadotJS Apps, specifying 1 KILT requires adding 15 trailing `0`s. +So, for instance, 1 KILT needs to be written as `1,000,000,000,000,000`, while 10,000 KILT would be written as `10,000,000,000,000,000,000`. +::: + +## Check Your Position in the Collators Queue + +As a collator candidate you can check the current top candidates to see their position and the required staked amount to become an active collator, i.e., to start authoring new blocks. + +![](/img/chain/parachainStaking-topCandidates1.png) + +In Polkadot JS ([wss://spiritnet.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkilt-rpc.dwellir.com#/explorer), or [wss://peregrine.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine-stg.kilt.io#/explorer)) go to `Developer -> Chain state -> Storage` + +1. Selected state query: `parachainStaking -> topCandidates(): ParachainStakingSetOrderedSet` +2. Execute the query by pressing the "+" button on the right side + +Now, you should see a window which lists collators (the *owner* field) ordered by their total stake (the *amount* field) from greatest to lowest. + +![](/img/chain/parachainStaking-topCandidates2.png) + +If a collator has enough self-stake and delegator stake it will be selected to collate. +The last address in the list will be the least staked candidate. +A time period of two sessions must pass before the selected collator will be authoring blocks, e.g., after the remainder of the current session and the entire next one. diff --git a/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/_03_start_node_binary.mdx b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/_03_start_node_binary.mdx new file mode 100644 index 000000000..58dde2037 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/_03_start_node_binary.mdx @@ -0,0 +1,61 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import styles from '@site/src/pages/styles.module.css'; + +Please select your target network: + +
+ + + To join the Spiritnet network, run: + + ```bash= + ./target/release/kilt-parachain \ + --chain=spiritnet \ + --runtime=spiritnet \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-methods=unsafe \ + --name="name of collator" \ + --execution=wasm \ + --listen-addr=/ip4/0.0.0.0/tcp/30333 \ + --base-path=$HOME/data/parachain \ + --keystore-path=$HOME/data/keystore \ + --collator \ + -- \ + --chain=polkadot \ + --listen-addr=/ip4/0.0.0.0/tcp/30334 \ + --base-path=$HOME/data/relay \ + --execution=wasm + ``` + + + + To join the Peregrinenetwork, run: + + ```bash= + ./target/release/kilt-parachain \ + --chain=./dev-specs/kilt-parachain/peregrine-kilt.json \ + --runtime=peregrine \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-methods=unsafe \ + --name="name of collator" \ + --execution=wasm \ + --listen-addr=/ip4/0.0.0.0/tcp/30333 \ + --base-path=$HOME/data/parachain \ + --keystore-path=$HOME/data/keystore \ + --collator \ + -- \ + --chain=./dev-specs/kilt-parachain/peregrine-relay.json \ + --listen-addr=/ip4/0.0.0.0/tcp/30334 \ + --base-path=$HOME/data/relay \ + --execution=wasm + ``` + + + +
diff --git a/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/_03_start_node_docker.mdx b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/_03_start_node_docker.mdx new file mode 100644 index 000000000..ec0966252 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/_03_start_node_docker.mdx @@ -0,0 +1,65 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import styles from '@site/src/pages/styles.module.css'; + +Please select your target network: + +
+ + + + To start the **Spiritnet** collator container, run: + ```bash= + docker run -p 127.0.0.1:9944:9944 -p 30333:30333 -p 30334:30334 \ + -v ~/data:/data kiltprotocol/kilt-node:latest \ + --chain=spiritnet \ + --runtime=spiritnet \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-methods=unsafe \ + --unsafe-rpc-external \ + --name="name of collator" \ + --execution=wasm \ + --listen-addr=/ip4/0.0.0.0/tcp/30333 \ + --base-path=/data/parachain \ + --keystore-path=/data/keystore \ + --collator \ + -- \ + --chain=polkadot \ + --listen-addr=/ip4/0.0.0.0/tcp/30334 \ + --base-path=/data/relay \ + --execution=wasm + ``` + + + + + To start the **Peregrine** Collator container, run: + ```bash= + docker run -p 127.0.0.1:9944:9944 -p 30333:30333 -p 30334:30334 \ + -v ~/data:/data kiltprotocol/kilt-node:latest \ + --chain=/node/dev-specs/kilt-parachain/peregrine-kilt.json \ + --runtime=peregrine \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-methods=unsafe \ + --unsafe-rpc-external \ + --name="name of collator" \ + --execution=wasm \ + --listen-addr=/ip4/0.0.0.0/tcp/30333 \ + --base-path=/data/parachain \ + --keystore-path=/data/keystore \ + --collator \ + -- \ + --chain=/node/dev-specs/kilt-parachain/peregrine-relay.json \ + --listen-addr=/ip4/0.0.0.0/tcp/30334 \ + --base-path=/data/relay \ + --execution=wasm + ``` + + + +
diff --git a/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/_category_.json b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/_category_.json new file mode 100644 index 000000000..c35bfb041 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/01_become_a_collator/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Become a Collator", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/01_adjust_stake.md b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/01_adjust_stake.md new file mode 100644 index 000000000..c9bf1cc63 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/01_adjust_stake.md @@ -0,0 +1,41 @@ +--- +id: adjust-stake +title: Adjust Your Own Stake +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import StakingTxDisclaimer from '../_disclaimer_staking_tx.md'; + +A collator can increase or decrease their stake, always within the limits of the minimum and maximum allowed stake amounts. +The corresponding extrinsics for these operations are `parachainStaking -> candidateStakeMore(more)` and `parachainStaking -> candidateStakeLess(less)`. + + + + + + +![](/img/chain/parachainStaking-candidateStakeMore.png) + +1. Select your collator KILT address as the extrinsic submitter (the *using the selected account* field) +2. Select the extrinsic: `parachainStaking -> collatorStakeMore` +3. Choose the stake amount that you want to add or remove from your current stake (the *more* field). +You can add up to the maximum of 200,000 KILT and your maximum available balance. +4. Sign and submit the extrinsic (the *Submit Transaction* button) + + + + +![](/img/chain/parachainStaking-candidateStakeLess.png) + +1. Select the collators's KILT address as the extrinsic submitter (the *using the selected account* field) +2. Select the extrinsic: `parachainStaking -> collatorStakeLess` +3. Choose the desired stake amount which you want to remove from your current stake (the *less* field). +You can reduce down to minimum collator amount (10,000 KILT), e.g., any value up to the difference of your current stake and the minimum will be accepted. +4. Sign and submit the extrinsic (the *Submit Transaction* button) + + + \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/02_exit.md b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/02_exit.md new file mode 100644 index 000000000..8d2e6c6c0 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/02_exit.md @@ -0,0 +1,65 @@ +--- +id: exit +title: Leave the Collator Candidate Pool +--- + +import StakingTxDisclaimer from '../_disclaimer_staking_tx.md'; + +If you intend to stop collating or stop being a collator candidate, you have to go through three stages until your staked tokens are unlocked and your collator state is purged from the chain. + +:::info +Unfortunately, exiting is not a simple process for security reasons. +Since a picture paints a thousand words, you can find a visualization of this process in the following [**lifecycle section**](./03_collator_lifecycle.md). +::: + +## Initiate the Exit Request + +First, signal your intent by calling `parachainStaking -> initLeaveCandidates`. +You will then be removed from the `CandidatePool` and your state switches from `Active` to `Leaving(leaveRound)`, where `leaveRound` reflects the number of sessions that have to elapse before you can definitely leave the set of collators. +You still need to stay online and build blocks for the current and next sessions. +Since each session lasts 2 hours, **the maximum amount of time you will need to wait is 4 hours**. +Of course, you will continue to receive rewards for the blocks your collating node will author. +A leaving candidate cannot be selected as an active collator for the sessions from this point on. +Moreover, you cannot receive new delegations and existing delegations cannot be adjusted. +However, delegations can still be revoked. + + + +![](/img/chain/parachainStaking-initLeaveCandidates.png) + +1. Select your collator KILT address as the extrinsic submitter (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> initLeaveCandidates` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +## Execute the Exit Request + +Once the current and next sessions have elapsed (which can take at most 4 hours), you can call `executeLeaveCandidate` to remove all of your `Candidate` associated storage. +You should be certain that you wish to leave as there is no turning back afterwards. +If you wish to become a candidate at a later stage, you will have to apply again and will not have your former delegations. + +![](/img/chain/parachainStaking-executeLeaveCandidates.png) + +1. Select one of your KILT addresses with sufficient funds to pay for the transaction fee (~5 milli KILT) as the extrinsic submitter (the *using the selected account* field) +_NOTE: Of course, you can chose your collator account._ +2. Select the appropriate extrinsic: `parachainStaking -> executeLeaveCandidates` +3. Select the `Id` option (the *MultiAddress (LookupSource) field*) +4. Select the collator account (the *Id: AccountId* field) +5. Sign and submit the extrinsic (the *Submit Transaction* button) + +## Cancel the Exit Request + +You still have not completed your exit request, you can still cancel it by calling `cancelLeaveCandidates`, which will succeed if the `CandidatePool` is not already full. +Upon interruption of your exit procedure, your state switches back to `Active` and you maintain all the previous delegations, since everything has remained untouched in the meantime. +Moreover, if you are one of the top staked candidates, you will automatically become a collator again at the end of the second round from this point, which can take as long as 4 hours in the worst case. + +![](/img/chain/parachainStaking-cancelLeaveCandidates.png) + +1. Select your collator KILT address as the extrinsic submitter (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> cancelLeaveCandidates` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +## Unlock Your Stake + +If you have executed the exit request you cannot immediately unlock your previously staked tokens. +There is a delay of 7 days in block time before you can free them by calling `unlockUnstaked`. +See [here](../05_unlock_unstaked.md) for a step-by-step tutorial. diff --git a/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/03_collator_lifecycle.md b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/03_collator_lifecycle.md new file mode 100644 index 000000000..e9f1911d9 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/03_collator_lifecycle.md @@ -0,0 +1,44 @@ +--- +id: lifecycle +title: Lifecycle of a Collator +--- + +The following diagram visualizes the full lifecycle of a collator from owning free KILT to joining the collator candidate pool, initiating the exit, waiting for the stake to be unlockable and eventually unlocking their bond. +It summarizes the previous [exit](./02_exit.md) section. + +
+ +```mermaid +flowchart TD + A["Hold (at least) 10K KILT"] -->|join_candidates| B(Candidate) + B --->|init_leave_candidates|I("Leaving Candidate\n(locked)") + I ---> G{"2 Sessions (4h)\n passed?"} + I -->|cancel_leave_candidates|B + G -->|no|I + G -->|yes|H("Leaving Candidate\n(unlocked)") + H -->|execute_leave_candidates|J("Locked Balance") + H -->|cancel_leave_candidates|B + J --->K{"At least 7 days\npassed?"} + K -->|yes|L("Balance with expired lock") + K -->|no|J + L -->|unlock_unstaked|A + + %% style assignment + A:::unstakedFreeKilt + B:::activeCollator + I:::leavingLocked + G:::leavingLocked + H:::leavingUnlocked + J:::leavingUnlocked + K:::leavingUnlocked + L:::stakedReleasableKilt + + %% style definition + classDef leavingLocked fill:#FFF4BD, stroke:none, color:black; + classDef leavingUnlocked fill:#F1C0B9, stroke:black, stroke-width:1px, color:black; + classDef unstakedFreeKilt fill:#85D2D0, stroke:black, stroke-width:1px, color:black; + classDef activeCollator fill:#94C973, stroke:#333, stroke-width:2px, color:black; + classDef stakedReleasableKilt fill:#F37970, stroke:black, color:black; +``` + +
diff --git a/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/04_monitoring.md b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/04_monitoring.md new file mode 100644 index 000000000..89052ec0b --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/04_monitoring.md @@ -0,0 +1,59 @@ +--- +id: monitoring +title: Set Up Node Monitoring +--- + +It would be ideal if the host being monitored is not the host monitoring, i.e., if the monitoring process does not run on the same host as the collator process. +However, in cases of limited resources, the two can also co-exist on the same host. + +The monitoring process collects two types of metrics: **Node Exporter metrics** and **blockchain metrics**. +The monitoring infrastructure can either be run as a local grafana cluster or as a [cloud-based solution](https://grafana.com/products/cloud/). + +:::info +For cloud-based solutions, the prometheus process must be publicly accessible, e.g., via a reverse proxy. +::: + +## What Will Be Installed + +The Docker compose setup creates and deploys up to four containers, all of which are optional: + +- **Node Exporter**: collects metrics from the host machine including CPU, memory, and storage usage, and network traffic statistics +- **Prometheus**: stores the metrics collected by Node Exporter and collects additional metrics from the blockchain node +- **Grafana**: shows the collected metrics in a customizable dashboard and can be configured to send alerts when certain conditions are met +- **Collator**: the collator node itself, which runs one of the available KILT runtimes + +## Installation +Install the latest version of docker-compose from the [official docker-compose installation guide](https://docs.docker.com/compose/install/), then: + +1. Clone the [entire KILT chain repo](https://github.com/KILTprotocol/docs) or download only the [monitoring template](https://github.com/KILTprotocol/docs/tree/master/collator). +2. Change directory to the above with ```cd docs/collator``` +3. Edit the `.env` file and insert your desired grafana admin user and password +4. Depending on the installation type either: + - run `docker-compose up -d` to install only Node Exporter and prometheus or + - run `docker-compose up --profile grafana -d` to install Node Exporter, prometheus and grafana or + - run `docker-compose --profile collator --profile grafana up -d` to install Node Exporter, prometheus, grafana **and** a Collator node + +5. Secure the endpoints: + 1. Install nginx with certbot ```sudo apt install nginx certbot python3-certbot-nginx``` + 2. If ufw is enabled, allow Nginx Full: ```sudo ufw allow 'Nginx Full'``` + 3. Generate an SSL certificate: ```sudo certbot --nginx -d ${DOMAIN_OF_SERVER_NAME}``` + 4. Enable certificate renewal by editing the crontab list ```crontab -e``` and appending ```0 5 * * * /usr/bin/certbot renew --quiet``` + 5. Reload nginx after replacing the default nginx file with prometheus endpoint (if grafana cloud is chosen) or grafana endpoint (if grafana installed) by adding the following config snippet to `/etc/nginx/sites-enabled/default` + ``` + location / { + proxy_pass http://localhost:9090/; #proxy_pass http://localhost:3000/; + } + ``` + 6. Enable basic authentication by replacing the default password in `prometheus.yml` using ``` htpasswd -nBC 10 "" | tr -d ':\n' ``` + +## Testing the Configuration +The configuration can be checked by visiting `https://localhost:3000` and authenticating with the username and password set in `.env` at step 3. + +## Configuring Alert Notification Channel +Choose any of the supported notification channels and follow the [grafana documentation](https://grafana.com/docs/grafana/latest/alerting/) to receive alerts and notifications. + +Overall, for monitoring we recommend the following stack: +- Prometheus +- Grafana +- Node exporter +- Nginx \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/05_bootnodes.md b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/05_bootnodes.md new file mode 100644 index 000000000..2790860d7 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/05_bootnodes.md @@ -0,0 +1,40 @@ +--- +id: bootnodes +title: Bootnodes +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +The bootnodes are required to connect to the peer-to-peer network and discover additional peers. +The addresses are included in the chain spec, so there is no need to add them as a parameter to the start command. +For the sake of completeness, the bootnodes are listed below: + + + + + For **Spiritnet**, the parachain bootnodes are: + +``` +--bootnodes=/dns4/hetzner-1.kilt.io/tcp/30333/p2p/12D3KooWKU8ehzuKAzHEMCy4i4kpJtgCFBCYYhqcub4Y1HR8FRoT \ +--bootnodes=/dns4/hetzner-2.kilt.io/tcp/30333/p2p/12D3KooWDJzJ7TRNKvE2DWXMSSsoKR5TgxsnNy3W1eCBPveX6g9i \ +--bootnodes=/dns4/node-6840569230186737664-0.p2p.onfinality.io/tcp/11578/ws/p2p/12D3KooWQapPfoSDxLBnsVZmpRA1yNApXEAEuhexPcFa7fECqpHa \ +--bootnodes=/dns4/node-6840781141641752576-0.p2p.onfinality.io/tcp/28779/ws/p2p/12D3KooWKMCaxjsvaNkYkdQGnPQnkYFouHFdJ3S36aBhV6QTXzaE \ +--bootnodes=/dns4/node-6840781099853901824-0.p2p.onfinality.io/tcp/15360/ws/p2p/12D3KooWLWSE85c5PSsgo62Dy5UM68Sx8p3vnJvtvDVC8QHXFpR +``` + + + + +For **Peregrine**, the parachain bootnodes are: + +``` +--bootnodes=/dns4/eyrie-4.kilt.io/tcp/30371/p2p/12D3KooWALJtiCZzcUPVsCa5f5egGfQyFhPY67kKosDw95bJqK7M +--bootnodes=/dns4/eyrie-5.kilt.io/tcp/30372/p2p/12D3KooWCRgcGtFRsvqxqgysiR6Ah9SAzUNkM12Ef9sy59ZEspSQ +``` + + + diff --git a/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/06_benchmarking.md b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/06_benchmarking.md new file mode 100644 index 000000000..712fbd99f --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/06_benchmarking.md @@ -0,0 +1,40 @@ +--- +id: benchmarking +title: Benchmark Your Collator +--- + +To enable benchmarking, the collator must enable the benchmarking feature from a new build of the `kilt-parachain`. + + + +:::caution Don't use this binary for running the Collator! +```bash= +cargo build --release -p kilt-parachain --features=runtime-benchmarks +``` +::: + +The benchmarks can be run to compare the server's hardware capabilities against the referenced hardware. +At the moment, we have benchmarked the Spiritnet and Peregrine runtimes on an AMD Ryzen 7 1700X with 64GB RAM and an NVMe SSD. +After executing the benchmarks on a server compare the weights to the official KILT weights. +Your weight results should at least be similar to the official ones and the lower yours are, the better. + +The commands executed to benchmark the KILT runtimes can be found in the official benchmark files for both [Spiritnet](https://github.com/KILTprotocol/kilt-node/tree/master/runtimes/spiritnet/src/weights) and [Peregrine](https://github.com/KILTprotocol/kilt-node/tree/master/runtimes/peregrine/src/weights). + +Below is an example of benchmarking for the the `balances` pallet. + +```bash= +./target/release/kilt-parachain \ + benchmark \ + --chain=spiritnet-dev \ + --execution=wasm \ + --wasm-execution=Compiled \ + --heap-pages=4096 \ + --extrinsic=* \ + --pallet=pallet-balances \ + --steps=50 \ + --repeat=20 \ + --output \ + ./runtimes/spiritnet/src/weights/pallet_balances.rs \ + --template \ + ./.maintain/weight-template.hbs +``` \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/_category_.json b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/_category_.json new file mode 100644 index 000000000..c6cc858f8 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/02_advanced_collator_section/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Advanced Collator Section", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/01_overview.md b/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/01_overview.md new file mode 100644 index 000000000..f5b4fed05 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/01_overview.md @@ -0,0 +1,17 @@ +--- +id: overview +title: Overview +--- + +In the [KILT **L**imited **D**elegated **P**roof **o**f **S**take (LDPoS)](https://medium.com/kilt-protocol/the-continuing-evolution-of-kilt-protocol-limited-delegated-proof-of-stake-640403427c48) consensus, delegators play an important role (at least in the infancy of the network) to filter the pool of candidates for honest, trusted and well-performing collators. + +The requirements to become a delegator are much less than [those for collators](../01_become_a_collator/01_overview.md). +You only need to stake a relatively low number of tokens and decide on a collator candidate. +Once the collator you have backed with your stake authors a block and thus receives a reward, you and all the other delegators of this collator also receive a reward. + +The following sections will guide you through the process of becoming a delegator, adjusting your stake, revoking a delegation and unstaking your tokens. + +:::info +The amount of delegators per collator is limited. +Currently, each delegator can only stake to one collator per account; this may change if the community decides to enable multiple delegations per account. +::: diff --git a/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/02_become.md b/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/02_become.md new file mode 100644 index 000000000..4fbd67484 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/02_become.md @@ -0,0 +1,102 @@ +--- +id: join +title: Become a Delegator +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import StakingTxDisclaimer from '../_disclaimer_staking_tx.md'; + +In contrast to the rather difficult [path to become a collator candidate](../01_become_a_collator/01_overview.md), joining the delegator pool is rather simple. +Anyone can delegate to a collator candidate by staking a minimum of 20 KILT and calling `parachainStaking -> joinDelegators`. + + + +![](/img/chain/parachainStaking-joinDelegators.png) + +1. Select the KILT address you want to delegate from as the extrinsic submitter (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> joinDelegators` +3. Select the `Id` option (the *MultiAddress (LookupSource) field*) +4. Select the collator account (the *Id: AccountId* field) +5. Choose the desired stake amount. +6. Sign and submit the extrinsic (the *Submit Transaction* button) + +:::info +A recent change in the blockchain metadata resulted in a change in the UI regarding how balances are shown. +In the current version of PolkadotJS Apps, specifying 1 KILT requires adding 15 trailing `0`s. +So, for instance, 1 KILT needs to be written as `1,000,000,000,000,000`, while 10,000 KILT would be written as `10,000,000,000,000,000,000`. +::: + + +## Happy Path + +If your chosen collator candidate has at least one empty slot in their delegation pool (out of 35 maximum slots at the time of writing), your delegation will be successful and you immediately start receiving rewards each time the collator you delegated produces a block. + +
+ +```mermaid +flowchart TD + A["Hold at least 20 KILT"] --> |"decide on candidate"| B("Collator Candidate chosen"); + B --> |"call extrinsic joinDelegators"| C{"Can delegate to target? \n Either \n 1. There are empty \n delegations or \n 2. You delegate more \n than another Delegator"}; + C --> |yes| D("Delegating to a Collator Candidate") + D --> |"Collator produces block"| E("Account rewards") + E --> |"claim"| F("Have rewards in wallet") + %% Styles + A:::unstakedFreeKilt + B:::preDelegationCheck + C:::preDelegationCheck + D:::activelyDelegating + E:::activelyDelegating + F:::activelyDelegating + + %% StyleDef + classDef preDelegationCheck fill:#FFF4BD, stroke:none, color:black; + classDef notDelegating fill:#F1C0B9, stroke:black, color:black, stroke-width:1px;; + classDef unstakedFreeKilt fill:#85D2D0, stroke:black, color:black, stroke-width:1px; + classDef activelyDelegating fill:#94C973, stroke:#333, color:black, stroke-width:2px; + classDef preUnlockStaked fill:#F37970, stroke:black, color:black; +``` +
+ +:::info +If your chosen collator fails to produce blocks, neither the collator itself nor their delegators receive rewards. +This can happen if the collator has connectivity issues or are not building blocks fast enough. +::: + +## Unhappy Path + +If the delegation pool of your chosen collator candidate is full, you may still delegate to them if you stake more than the current lowest delegator stake of that pool. +When that happens, + +- The kicked delegator will be replaced by the delegator with a higher delegation (you) immediately +- The kicked delegator's stake is prepared for unstaking as if they revoked the delegation +- A delegator needs to wait 7 days (in block time) to be able to unlock the stake. +Please note that it can take longer in real time as the block times assumes a constant block time of 12s, which is not guaranteed. + +
+ +```mermaid +flowchart TD + A["Hold at least 20 KILT"] --> |"Decide on candidate"| B("Collator candidate chosen"); + B --> |"Call extrinsic joinDelegators"| C{"Can delegate to target? \n Either \n 1. There are empty \n delegations or \n 2. You delegate more \n than another delegator"}; + C --> |no| C2{"Balance locked?\n e.g., previously delegated \n without unlocking?"} + C2 --> |no| A + + %% Styles + A:::unstakedFreeKilt + B:::preDelegationCheck + C:::preDelegationCheck + C2:::notDelegating + + %% StyleDef + classDef preDelegationCheck fill:#FFF4BD, stroke:none, color:black; + classDef notDelegating fill:#F1C0B9, stroke:black, color:black, stroke-width:1px; + classDef unstakedFreeKilt fill:#85D2D0, stroke:black, color:black, stroke-width:1px; +``` +
+ + +:::info +For now, an account can only delegate to one collator at any time! +Moreover, you can only (re-) delegate, e.g., call `parachainStaking -> {joinDelegators, delegateAnotherCandidate}`, once per staking round. +::: diff --git a/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/03_adjust_stake.md b/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/03_adjust_stake.md new file mode 100644 index 000000000..9f67b4a94 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/03_adjust_stake.md @@ -0,0 +1,52 @@ +--- +id: adjust-stake +title: Adjust Your Delegation Stake +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import StakingTxDisclaimer from '../_disclaimer_staking_tx.md'; + +A delegator can increase and decrease their stake by calling either `parachainStaking -> delegatorStakeMore(more)` or `parachainStaking -> delegatorStakeLess(less)`. +Your adjustment becomes effective immediately! +If you increase your stake, you will instantly receive higher rewards for any blocks produced by your collator; if you decreased your delegation amount, the reverse applies and you receive less rewards. + + + + + + +![](/img/chain/parachainStaking-delegatorStakeMore.png) + +1. Select the KILT address you want to delegate from as the extrinsic submitter (the *using the selected account* field) +2. Select the extrinsic: `parachainStaking -> delegatorStakeMore` +3. Select the `Id` option (the *MultiAddress (LookupSource) field*) +4. Select the collator account (the *Id: AccountId* field) +5. Choose the desired amount of stake that you want to add to your current stake. +You can add up to your maximum available balance. +6. Sign and submit the extrinsic (the *Submit Transaction* button) + + + + +![](/img/chain/parachainStaking-delegatorStakeLess.png) + +1. Select the KILT address you want to delegate from as the extrinsic submitter (the *using the selected account* field) +2. Select the extrinsic: `parachainStaking -> delegatorStakeLess` +3. Select the `Id` option (the *MultiAddress (LookupSource) field*) +4. Select the collator account (the *Id: AccountId* field) +5. Choose the desired amount of stake that you want to remove from your current stake. +You can reduce down to the minimum delegation amount (20 KILT), e.g., any value up to the difference of your current stake and the minimum will be accepted. +6. Sign and submit the extrinsic (the *Submit Transaction* button) + + + + +:::caution +You cannot adjust your stake if your Collator candidate is in the leaving state, e.g., they want to stop collating. +However, you can still [**remove**](./04_exit.md) your delegation. +::: + diff --git a/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/04_exit.md b/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/04_exit.md new file mode 100644 index 000000000..f2146c8c0 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/04_exit.md @@ -0,0 +1,21 @@ +--- +id: exit +title: Leave the Set of Delegators +--- + +import StakingTxDisclaimer from '../_disclaimer_staking_tx.md'; + +A Delegator can revoke their delegation by calling `parachainStaking -> leaveDelegators`. +As a result, you won't receive any rewards immediately after the transaction is successfully executed. + +- Your previously delegated amount will be prepared for unstaking. +- You need to wait 7 days (in block time) before you can unlock your unstaked tokens, see the section [Unlock Unstaked](../05_unlock_unstaked.md) for more information. +- Exiting does not count towards the limit of โ€œ1 delegation per roundโ€. + + + +![](/img/chain/parachainStaking-leaveDelegators.png) + +1. Select the KILT address you delegated from as the extrinsic submitter (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> leaveDelegators`. +3. Sign and submit the extrinsic (the *Submit Transaction* button) diff --git a/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/05_delegator_lifecycle.md b/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/05_delegator_lifecycle.md new file mode 100644 index 000000000..05daa00d4 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/05_delegator_lifecycle.md @@ -0,0 +1,55 @@ +--- +id: lifecycle +title: Lifecycle of a Delegator +--- + +The following diagram depicts the full lifecycle of a delegator from owning free KILT to delegating, losing a delegation seat, re-delegating and finally unlocking their stake. + +It provides a summary of the detailed information provided in the preceding sections. + +
+ +```mermaid +flowchart TD + A["Hold at least 20 KILT"] --> |Choose candidate| B("Collator candidate chosen"); + B --> |"Call \n joinDelegators"| C{"Can delegate to target? \n Either \n 1. There are empty \n delegations or \n 2. You delegate more \n than another Delegator"}; + C --> |yes| D("Delegating to a collator candidate") + C --> |no| C2{"Balance locked?\n e.g., previously delegated \n without unlocking?"} + C2 --> |no| A + C2 --> |yes| G + D --> D2("Accumulating rewards \non each block built by \n delegated collator") + D --> |"leave \n Delegators"| E("Not delegating") + D --> |"your Collator \n candidate leaves"| E + E --> E2("Not accumulating \n rewards") + E --> F{"Delegate to \n another candidate?"} + F --> |Yes| B + F --> |No| G("Locked tokens") + G --> |Want to unlock| H{"Waited 7 days?"} + H --> |yes| I("Balance with expired lock") + H --> |no| F + I --> |"Call \n unlockUnstaked"| A + + %% Styles + A:::unstakedFreeKilt + B:::preDelegationCheck + C:::preDelegationCheck + C2:::notDelegating + D:::activelyDelegating + D2:::activelyDelegating + E:::notDelegating + E2:::preUnlockStaked + F:::notDelegating + G:::preUnlockStaked + H:::preUnlockStaked + I:::preUnlockStaked + + %% StyleDef + classDef preDelegationCheck fill:#FFF4BD, color:black, stroke:none; + classDef notDelegating fill:#F1C0B9, color:black, stroke:black, stroke-width:1px;; + classDef unstakedFreeKilt fill:#85D2D0, color:black, stroke:black, stroke-width:1px; + classDef activelyDelegating fill:#94C973, color:black, stroke:#333, stroke-width:2px; + classDef preUnlockStaked fill:#F37970, color:black, stroke:black; +``` + +
+ diff --git a/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/_category_.json b/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/_category_.json new file mode 100644 index 000000000..78f66302c --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/03_delegate/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Delegate", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/participate/01_staking/04_claim_rewards.md b/versioned_docs/version-0.35.0/participate/01_staking/04_claim_rewards.md new file mode 100644 index 000000000..debc20b1b --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/04_claim_rewards.md @@ -0,0 +1,93 @@ +--- +id: claim-rewards +title: Claim Staking Rewards +--- + +import CodeBlock from '@theme/CodeBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import StakingTxDisclaimer from './_disclaimer_staking_tx.md'; +import GetUnclaimedStakingRewards from '!!raw-loader!@site/code_examples/sdk_examples/src/staking/rewards/01_query_staking_rewards.ts'; +import ClaimRewardsCollator from './_04_claim_rewards_collator.mdx'; +import ClaimRewardsDelegator from './_04_claim_rewards_delegator.mdx'; + +Until runtime version 1.7.5 (`spiritnet-10750`), staking rewards were automatically minted. +In 1.8.0 (`spiritnet-10801`) this will change: +Hereafter, the rewards are still accounted to the collators and their delegators in each block. +However, they need to be actively claimed by calling an extrinsic, similar to the pull-based approach on Polkadot. +Since the rewards never expire, one does not need to rush to do so. + +This change improves the scalability of our LDPoS by orders of magnitude because it removes the `Rewarded` events for a collator and all their delegators in each block. +This reduces the number of taxable events from many thousands per year to any number a user might find suitable. +Please check our blogpost for more details. + +## How to check the reward amount + +Unfortunately, the amount of accumulated rewards are not directly stored on the chain but divided into multiple storage entries. +Luckily, you can easily query your current reward status by performing a runtime API call which we created for that specific purpose. +Since this is just a simple query, it does not cost any transaction fees. + + + + +In the Polkadot JS Apps ([wss://spiritnet.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkilt-rpc.dwellir.com#/explorer), or [wss://peregrine.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine-stg.kilt.io#/explorer)) go to `Developer -> Runtime calls`. + +1. Select the `parachainStaking` endpoint. +2. Select the `getUnclaimedStakingRewards(account)` call. +3. Select your KILT address (the *account: AccountId32* field) +4. Submit the runtime call (the *Submit Runtime call* button). You do not need to sign or pay any fees. + +![](/img/chain/parachainStaking-getUnclaimedStakingRewards.png) + + + + + + {GetUnclaimedStakingRewards} + + + + +## How to claim + +In order to move the staking rewards into your wallet, you need to call two different extrinsics: `increment{Collator, Delegator}Rewards` and `claimRewards`. +This can be done sequentially or in a batch. +To save transaction fees, we recommend the latter [batched call](#recommendation-batched-call). + +
+ +```mermaid + +graph TD +Alice("Alice holds free KILT") ---> |"call joinCandidates"| C("Active Collator") +Alice ---> |"call joinDelegators"| D("Active Delegator") +C ---> |"build block"| R +D ---> |"delegated collator \n builds block"| R("Reward counter is \n internally increased") +R ---> |"call increment...Rewards"| R2("Rewards are \n converted into Balance") +R2 ---> |"call claimRewards"| R3("Rewards are moved \n into Alice's wallet") + +``` + +
+ + + + + + + + + + + + + + + + diff --git a/versioned_docs/version-0.35.0/participate/01_staking/05_unlock_unstaked.md b/versioned_docs/version-0.35.0/participate/01_staking/05_unlock_unstaked.md new file mode 100644 index 000000000..5c13ae86a --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/05_unlock_unstaked.md @@ -0,0 +1,48 @@ +--- +id: unlock-unstaked +title: Unlock Unstaked Tokens +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import StakingTxDisclaimer from './_disclaimer_staking_tx.md'; + +Before you can unlock your previously staked tokens, you have to wait 7 days (in block time). + + + +![](/img/chain/parachainStaking-unlockUnstaked.png) + + + + +1. Select any account with enough balance to cover the transaction fee, which is around 0.005 KILT (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> unlockUnstaked(target)` +3. Select the `Id` option (the *MultiAddress (LookupSource) field*) +4. Select your collator's KILT address (the *Id: AccountId* field) +5. Sign and submit the extrinsic (the *Submit Transaction* button) + +:::info +You have unstaked tokens if you have either reduced your stake without increasing it for (at least) same amount afterwards or executing your exit request. +::: + + + + +1. Select any account with enough balance to cover the transaction fee, which is around 0.005 KILT (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> unlockUnstaked(target)` +3. Select the `Id` option (the *MultiAddress (LookupSource) field*) +4. Select the KILT address you delegated from (the *Id: AccountId* field) +5. Sign and submit the extrinsic (the *Submit Transaction* button) + +:::info +Even if you have not exited, reduced or removed your delegation, you can still have unstaked tokens. +This can happen if either of the following events occurred +* You were kicked out of your collator candidate's delegation pool because all current delegators have a higher stake +* Your collator candidate intentionally left the collator pool. +::: + + \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/participate/01_staking/06_troubleshooting.md b/versioned_docs/version-0.35.0/participate/01_staking/06_troubleshooting.md new file mode 100644 index 000000000..02bcd8da6 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/06_troubleshooting.md @@ -0,0 +1,65 @@ +--- +id: troubleshooting +title: Troubleshooting +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + +There are a few things that can be checked to make sure everything is set up correctly. + +If the collator's account is shown next to some of the blocks on any network explorer, e.g., the one offered by PolkadotJS Apps, then the collator is correctly producing blocks and getting rewarded for it. +If the logs print the message that starts with a :gift: emoji, it indicates that the collator setup is correct but that the blocks produced are not included by the Relay Chain. +This typically signals some issues about the node hardware or connectivity. +If not, it might be that the node does not produce and send blocks fast enough. +This can be caused by slow hardware or a slow internet connection. +Also, note that a high bandwidth connection can still be slow if it has a high ping! +Bandwidth and latency do not necessarily come hand in hand. +In this case, it is better to rule out other options before thinking about upgrading the collator's hardware. + +1. Check that the session keys are associated with the validatorId (aka AccountId). +There should be a 32 Byte long public key stored in `session > nextKeys(your AccountId)`. +2. Check that the node has the corresponding private key for the public session key. +Connect to the node and query `author > hasKey(, aura)` to see if it returns `true`. +3. Check that the node is fully synced with the Relay Chain & parachain (best and finalized block number is equal to the one shown in the PolkadotJS Apps ([wss://spiritnet.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkilt-rpc.dwellir.com#/explorer), [wss://peregrine.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine-stg.kilt.io#/explorer)) and on Subscan (only for [Spiritnet](https://spiritnet.subscan.io/)). +4. Check that the collator is among the selected candidates. +Its address should included in the list returned by querying `parachainStaking > topCandidates()`. +5. Check that the `parachainStaking` pallet has registered the collator's address among the authorized authors in the `session`. +Its address should be listed when querying `session > validators()`. + +## Collator Rewards Have Stopped + +If you have stopped receiving rewards, either of the following is true: +1. You were kicked out of the top collator candidate list because your total stake is too low. + See the [section about joining](./01_become_a_collator/05_join_collators.md#check-your-position-in-the-collators-queue) for the necessary steps to retrieve the least staked candidate address in that list. + You can query their stake by going to `Developer -> Chain State` calling `parachainStaking -> candidatePool(address) -> +`. +2. You have connectivity issues, see above for resolution tips. + + + + +## Delegator Rewards Have Stopped + +If you have stopped receiving rewards, either +1. You were kicked out of your collator candidate's delegation pool because all current delegators have a higher stake or +2. Your collator candidate stopped producing blocks, because: + 1. They left the collator candidate pool intentionally so they don't have an associated collator state on-chain henceforth; or + 2. They are not among the top staked candidates (of which there are 30 at the time of writing 2022-05-05); or + 3. They are offline. + +In case of 1. or 2i., your stake will automatically be unstaked and prepared for [unlocking](./05_unlock_unstaked.md). +Otherwise, in case of 2ii. and 2iii., you need to [manually initiate the unlocking period](./03_delegate/04_exit.md) if you don't want to or cannot delegate to another Collator candidate. + + + +### Why Can't I Transfer Unstaked Tokens? + +Staking puts a lock on your tokens which blocks them from being transferred. +You can still use them for participating in Governance. +If your funds are unstaked, you still need to wait 7 days (in block time) to [unlock tokens after unstaking them](./05_unlock_unstaked.md). diff --git a/versioned_docs/version-0.35.0/participate/01_staking/_04_claim_rewards_collator.mdx b/versioned_docs/version-0.35.0/participate/01_staking/_04_claim_rewards_collator.mdx new file mode 100644 index 000000000..e53bbbb1c --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/_04_claim_rewards_collator.mdx @@ -0,0 +1,57 @@ +import CodeBlock from '@theme/CodeBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import ClaimCollatorStakingRewards from '!!raw-loader!@site/code_examples/sdk_examples/src/staking/rewards/02_claim_collator_staking_rewards.ts'; + +
+ + + +### Prepare claiming + +First, you need to convert your _reward points_ into balance. + +1. Select the collator account for which you want to claim the rewards. +It should have enough balance to cover the transaction fee which is around 0.0001 KILT (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> incrementCollatorRewards()` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/parachainStaking-incrementCollatorRewards.png) + +### Claim + +Finally, you can claim your well deserved staking rewards. + +1. Select the collator account for which you want to claim the rewards. +It should have enough balance to cover the transaction fee which is around 0.0001 KILT (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> claimRewards()` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/parachainStaking-claimRewards.png) + +### Recommendation: Batched call + +We recommend to execute both extrinsics in a single batch to save on transaction fees: + +1. Select the collator account for which you want to claim the rewards. +It should have enough balance to cover the transaction fee which is around 0.000112 KILT (the *using the selected account* field) +2. Select the batch extrinsic: `utility -> batch()` +3. Select the reward increment extrinsic: `parachainStaking -> incrementCollatorRewards()` +4. Press the `+` button and add the reward claiming extrinsic: `parachainStaking -> claimRewards()` +5. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/parachainStaking-batch-incrementCollatorRewards-claimRewards.png) + + + + + + {ClaimCollatorStakingRewards} + + + + +
diff --git a/versioned_docs/version-0.35.0/participate/01_staking/_04_claim_rewards_delegator.mdx b/versioned_docs/version-0.35.0/participate/01_staking/_04_claim_rewards_delegator.mdx new file mode 100644 index 000000000..6eea0b592 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/_04_claim_rewards_delegator.mdx @@ -0,0 +1,55 @@ +import CodeBlock from '@theme/CodeBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import ClaimDelegatorStakingRewards from '!!raw-loader!@site/code_examples/sdk_examples/src/staking/rewards/03_claim_delegator_staking_rewards.ts'; + +
+ + + +### Prepare claiming + +First, you need to convert your _reward points_ into balance. + +1. Select the delegator account for which you want to claim the rewards. It should have enough balance to cover the transaction fee which is around 0.0001 KILT (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> incrementDelegatorRewards()` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/parachainStaking-incrementDelegatorRewards.png) + +### Claim + +Finally, you can claim your well deserved staking rewards. + +1. Select the delegator account for which you want to claim the rewards. It should have enough balance to cover the transaction fee which is around 0.0001 KILT (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> claimRewards()` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/parachainStaking-claimRewards.png) + +### Recommendation: Batched call + +We recommend to execute both extrinsics in a single batch to save on transaction fees: + +1. Select the delegator account for which you want to claim the rewards. +It should have enough balance to cover the transaction fee which is around 0.000112 KILT (the *using the selected account* field) +2. Select the batch extrinsic: `utility -> batch()` +3. Select the reward increment extrinsic: `parachainStaking -> incrementDelegatorRewards()` +4. Press the `+` button and add the reward claiming extrinsic: `parachainStaking -> claimRewards()` +5. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/parachainStaking-batch-incrementDelegatorRewards-claimRewards.png) + + + + + + {ClaimDelegatorStakingRewards} + + + + +
diff --git a/versioned_docs/version-0.35.0/participate/01_staking/_category_.json b/versioned_docs/version-0.35.0/participate/01_staking/_category_.json new file mode 100644 index 000000000..0e13eb399 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Staking", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/participate/01_staking/_disclaimer_staking_tx.md b/versioned_docs/version-0.35.0/participate/01_staking/_disclaimer_staking_tx.md new file mode 100644 index 000000000..c8cc3a9ef --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/01_staking/_disclaimer_staking_tx.md @@ -0,0 +1,6 @@ +:::info +You can either execute this transaction in Polkadot JS Apps or the [**KILT Stakeboard**](../../develop/05_builtonkilt.md#web-apps), which serves as an in-house developed Frontend for all KILT staking activity. +Below, we outline the steps for Polkadot JS Apps. +::: + +In the Polkadot JS Apps ([wss://spiritnet.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkilt-rpc.dwellir.com#/explorer), or [wss://peregrine.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine-stg.kilt.io#/explorer)) go to `Developer -> Extrinsics -> Submission`. diff --git a/versioned_docs/version-0.35.0/participate/02_governance/01_vote.md b/versioned_docs/version-0.35.0/participate/02_governance/01_vote.md new file mode 100644 index 000000000..87e302201 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/02_governance/01_vote.md @@ -0,0 +1,83 @@ +--- +id: vote +title: Cast a Vote +--- + +1. Go to KILT Spiritnet on [Polkadot.JS](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fspiritnet.api.onfinality.io%2Fpublic-ws#/democracy) + +2. Under the โ€œGovernanceโ€ โ†’ โ€œDemocracyโ€ section you will see active referenda and proposals + +3. Scroll to the referendum you wish to vote on + +4. Click โ€œVoteโ€ + +5. This opens a separate pop-up. + Enter the amount of coins you want to lock (1). + The minimum required to vote is 1 KILT.
+ You can vote with multiplier 0.1 (10% of your voting tokens) and your coins will only get locked for the duration of the vote. + ![](/img/chain/cast-vote.png) + +6. If you wish to increase your voting power by selecting a period of time to lock your coins, click the arrow next to conviction (2). + Choose your conviction in the drop-down menu.
+ :::note + if the referendum is successful, your coins will remain locked for this period; if unsuccessful, your tokens will be unlocked when the referendum has finished. + Also because voting happens transparently on-chain, it requires a small transaction fee (around 0.017 KILT). + Locked tokens or tokens used for staking can be simultaneously used for voting, but a usable, unlocked balance to cover this fee is required. + ::: + +7. Vote โ€œAyeโ€ if you agree with the proposal and โ€œNayโ€ if you disagree. + +8. Click โ€œSign and Submitโ€ in the pop-up. + ![](/img/chain/vote-sign-sporran.png) + +9. Sign the transaction by entering your password (Sporran or Polkadot.JS, depending on where you are connected.) +10. Thatโ€™s it! + +## Backgrounder: Conviction Voting + +Like Polkadot and Kusama, KILT Protocol has conviction voting. +This means if you feel very strongly about a proposal, you can lock up tokens for longer periods to increase your voting power up to a maximum factor of 6. +The longer you lock your tokens, the stronger your vote will be weighted. + +The times range from no lockup to a period of around 224 days, with the lockup time beginning after the voting period ends. +Tokens used for voting will always be locked until the end of the voting period, no matter what conviction you vote with. +Of note: the lock time is based on the standard blocktime of 12 seconds per block and hence may vary due to differences in the real blocktime. + +![](/img/chain/vote-conviction.png) + +If you choose not to lock any tokens, your vote only counts as 10% of the tokens that you commit to the voting (vote value), while the maximum lock up of around 224 days means you can make your vote count for 600% of the vote value. +You can choose to lock all or some of your coins for any range between 0.1x and 6x, with a lockup time as outlined above. + +For example: You have a wallet with 1,001 KILT Coins. +This could include staked or vested coins. + +### Example 1 - Minimum + +* You want to vote but donโ€™t want to lock any coins. +* You enter 1,000 into the โ€œvote valueโ€ +* You choose โ€œ0.1 x voting balance, no lockup periodโ€ +* This gives you a voting power of 100 KILT Coins. +* Note that all your 1,000 coins are locked for the time of the voting period (7 days). + +### Example 2 - Maximum + +* You strongly believe in the referendum and want to vote with your full balance and maximum conviction. +* Choose โ€œ6 x voting balance, locked for 32x enactment (224 days)โ€ +* This will give you a voting power of 6,000 KILT Coins, if you use your full amount, or 6 times the voting power of the amount you chose. + The chosen amount will be locked for a period of around 224 days after the voting period ends (7 days). + +:::note + +Rounded numbers are used as an example only โ€“ make sure that you always leave enough free, usable balance to cover the transaction fees. + +::: + +Conviction voting allows users with a small amount of tokens to increase their voting power, and deters a token holder from creating and voting on a malicious proposal and then leaving the network. + +If the referendum is successful, your voting coins will remain locked for the time specified (which means that you will be unable to transfer them, but they will still be usable for staking during that time); if unsuccessful, your tokens will be unlocked after the referendum has finished. + +KILT also uses an algorithm to adapt the amount of โ€œayeโ€ (yes/agree) votes needed to pass depending on voter turnout: the greater the number of voters, the lower the threshold required to pass. +Therefore, when voter turnout is low a supermajority is generally required; with a high turnout a simple majority is sufficient. + +Before voting on any referendum, you can read more about it and join the discussion in [Polkassembly](https://kilt.polkassembly.network/referenda) (under โ€œDemocracyโ€ โ†’ โ€œReferendaโ€). +Polkassembly is an open source platform for providing information, context and a discussion forum for proposals and referenda in the Polkadot ecosystem. diff --git a/versioned_docs/version-0.35.0/participate/02_governance/02_remove_vote.md b/versioned_docs/version-0.35.0/participate/02_governance/02_remove_vote.md new file mode 100644 index 000000000..44b947cdd --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/02_governance/02_remove_vote.md @@ -0,0 +1,28 @@ +--- +id: remove_vote +title: Remove a Vote +--- + +If you happen to change your mind and want to remove a vote from an open referendum, you have to find the index of the referendum you voted on, remove your vote from that index and unlock your coins that are no longer locked up by this vote. + +## Find the Referendum Index + +1. Go to the [Democracy tab in Polkadot.JS Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fspiritnet.api.onfinality.io%2Fpublic-ws#/democracy) +2. Note the number next to the referendum you voted for + +![](/img/chain/find-referendum-index.png) + +## Remove the Vote +Go to the [Extrinsic tab in Polkadot.JS Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fspiritnet.api.onfinality.io%2Fpublic-ws#/extrinsics) + +1. Select the account you used for voting +1. Select the `democracy` pallet +2. Select the `removeVote` extrinsic +3. Enter the index of the referendum +4. Sign and send the extrinsic + +![](/img/chain/remove-vote.png) + +## Unlock Expired Voting Locks + +Please refer to the "[Unlock coins after lockup expires](./03_unlock_coins.md)" guide. diff --git a/versioned_docs/version-0.35.0/participate/02_governance/03_unlock_coins.md b/versioned_docs/version-0.35.0/participate/02_governance/03_unlock_coins.md new file mode 100644 index 000000000..e5e28ba80 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/02_governance/03_unlock_coins.md @@ -0,0 +1,16 @@ +--- +id: unlock_coins +title: Remove Expired Voting Locks +--- + +After the lockup time has been reached, a transaction is needed to clear the lock. +Of note: this will also require a transaction fee. + +1. Go to KILT Spiritnet on Polkadot.JS +2. Click the three dots on the right of your account. This opens up a pop-up. +3. Click โ€œClear expired democracy locksโ€ + +![](/img/chain/unlock-vote.jpg) + +Confirm the transaction. +This will clear the lock. diff --git a/versioned_docs/version-0.35.0/participate/02_governance/_category_.json b/versioned_docs/version-0.35.0/participate/02_governance/_category_.json new file mode 100644 index 000000000..8be4a0ebf --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/02_governance/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Governance", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-0.35.0/participate/03_treasury_proposal.md b/versioned_docs/version-0.35.0/participate/03_treasury_proposal.md new file mode 100644 index 000000000..3935a6e74 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/03_treasury_proposal.md @@ -0,0 +1,157 @@ +--- +id: treasury-proposal +title: Open a Treasury Proposal +--- + +Complete these steps to create a well-formed Treasury proposal. + +## Discuss + +The first step in applying for a Treasury grant is either to join the community in the [Discord Treasury Channel](https://discord.gg/nUpqDfQ6kJ) to brainstorm the scope of your proposal intention or immediately open a discussion on [Polkassembly](https://kilt.polkassembly.network/discussions). +This will help you get valuable community feedback throughout the process. +It also gives Council members an open and transparent way to measure community sentiment. + +## DID Sign + +The proposed document must be DID signed. +This requires a DID that must be associated with the proposal. +Therefore, it requires the proposer to have a DID. +The signature provides integrity and accountability about the submitter, which can give more confidence to the community and council. + +The DID Signature should be done via the [DIDSign](https://didsign.io/) dApp. +The DIDSign doesn't have a database, nor store any data by the user. +The following guide explains [how to create a signature using a DID with DIDSign](https://kilt-protocol.org/files/How-to-Guide-DIDsign.pdf). + +Once the document has been signed, the signature must be made publicly available for verification. +Depending on the services and software used, accessing the storage may require different instructions, e.g., on IPFS or as a GitHub gist or cloud provider. +The document should be made publicly available as well as the signature. + +## Example on IPFS + +An example of how to do this via IPFS using Google Drive. +Have a document ready for the proposal or discussion phase. + +1. Make the document publicly available to view and download. + +2. Sign the PDF version of the Document in the [DIDSign](https://didsign.io/). + +3. Download the zip file and upload it to IPFS. + +4. Following the instructions of the IPFS, pin the signature to IPFS and make it publicly available. One solution for doing is [web3 storage](https://web3.storage/). + +5. After the documents and signature have been uploaded to IPFS, add their URL to the proposal or discussion page for verification. + +Please include how to verify and download the necessary documents. +The following is an example done by BOTLabs GmbH. + +```md + +The current version of the proposal document has been digitally signed with one of the DIDs that BOTLabs GmbH controls. To verify the signature: + +1. Download the PDF version of the Google Document linked above. + +2. Download the DID signature of the file from IPFS, with CID QmRcYyPcCKGDQno2m5qBSZq7dftoZKuwraF9C9M96rXR36 (e.g., ipfs.io). + +3. Visit didsign.io, and upload both the PDF file and the downloaded signature. The signature should verify correctly and link to the KILT tx in which the timestamp was generated. +``` + +The example may change depending on the method of storing and creation of the document. + +If during the discussion the document is edited it will require a new upload and should be updated accordingly. + +## Deposit + +A deposit of 5% of the amount requested is required in order to submit a proposal. +If the proposal is denied, you will lose this amount and it will go to the Treasury to fund other projects. +This is why it is essential to engage with the community and show how the proposed work adds value to the network. + +## Create Proposal + +To maximize your chances of success, create a full proposal document with as much information as possible to communicate the value of your work and what it will add to the networkโ€™s growth and success. +Check out our Treasury proposal template or Polkassemblyโ€™s [proposal document #6](https://docs.google.com/document/d/1K0ScDodCxzgoqHSp-62rW0JLvBpMRgH97R37OoqYH-0) as examples to help guide your process. + +Multiple types of proposals can be created covering building and infrastructure, outreach and hackathons, or [educational content](04_content_creation_guidelines.md) such as videos, blogs and translations. + +Once your proposal document is complete, upload it so that itโ€™s accessible to the Council for review. +Donโ€™t forget to link it when completing the Polkassembly information! + +## Submit Proposal + +When you have feedback from the community and are satisfied with your proposal, head to [Polkadot.JS apps](https://polkadot.js.org/apps/?rpc=wss://spiritnet.api.onfinality.io/public-ws#/treasury) + +Scroll to the โ€œ+ Submit Proposalโ€ button and click. +Complete the form: + +* Submit with Account: this is the account that will make the 5% deposit +* Beneficiary: this is the account that will receive Treasury funding if successful +* Value: this is the full amount of KILT being requested +* Click submit to complete the proposal + +## Polkassembly Details + +Click the [Polkassembly](https://kilt.polkassembly.network/discussions) link to the right of the proposal on Polkadot.JS and connect with the account that you used to submit the proposal in order to be able to edit the proposal details. + +Enter the following information: + +* Title: a title for your project +* Purpose: whatโ€™s your motivation behind the effort +* Description: a short summary about you, the project and the need for what you are proposing +* Full Proposal: link to the full proposal +* Proposal Amount: the amount requested in USD +* KILT Rate: the current rate of exchange in USD +* Amount Requested: the total amount of KILT requested +* Beneficiary: the beneficiary address +* Period: intended date of delivery if applicable +* Contact: email or social handle (please specify social network) +* Engage +* Share your proposal in our channels to generate support from community and showcase your project (Discord, Telegram, Element, Twitter) + +Click [here](https://www.kilt.io/treasury/overview/) to get an overview of the Treasury. +Or click [here](https://www.kilt.io/treasury/content-creation/) to see the guidelines for content creation. + +## Illustration + +The following diagram depicts the flow of a Treasury proposal from having an idea to receiving the funds in the beneficiary address. +While all nodes with yellow background represent off-chain processes, the remaining ones involve on-chain activity. + +
+ +```mermaid +flowchart TD + %% nodes + Proposer --> |"Share contribution idea"|Discuss("Polkassembly: \n kilt.polkassembly.network") + Discuss --> |"Gather feedback"|Community + Discuss --> |"Come to agreement about \n scope and financial objective"|Council + Community --> |"Supports proposal"|Propose("Propose to chain") + Council --> |"Approves pre-proposal"|Propose + Propose --> |"reserve 5% of \n demanded amount \n"|Deposit + Propose --> |"On Polkassembly, \n provide details in"|Document("Proposal document") + Propose ----> |"Select address"|Beneficiary + Document --> |"Start work"|Deliverables + Deliverables --> |"Complete work"|Council_Review{"Council review"} + Council_Review ----> Council_Approval("Council approval") + Council_Review -...-> Council_Rejection("Council rejection") + Council_Approval ----> |"Receive requested \n funds from Treasury"|Beneficiary + Council_Approval ----> |Unreserve deposit|Deposit + Council_Rejection -.-> |"Slash deposit \n to Treasury"|Deposit + + %% class mapping + Proposer:::ofchain + Discuss:::ofchain + Community:::ofchain + Council:::ofchain + Propose:::onchain + Document:::ofchain + Deliverables:::ofchain + Council_Review:::ofchain + Council_Approval:::onchain + Deposit:::onchain + Council_Rejection:::onchain + Beneficiary:::onchain + + %% styling classes + classDef ofchain fill:#FFF4BD, stroke:black, stroke-width:1px, color:black; + classDef onchain fill:#85D2D0, stroke:black, stroke-width:1px, color:black; +``` + +
diff --git a/versioned_docs/version-0.35.0/participate/04_content_creation_guidelines.md b/versioned_docs/version-0.35.0/participate/04_content_creation_guidelines.md new file mode 100644 index 000000000..4824e8651 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/04_content_creation_guidelines.md @@ -0,0 +1,47 @@ +--- +id: content-creation-guidelines +title: Content Creation Guidelines +--- + +Content created should be unique in substance, reach, or delivery. +Copying or quickly iterating existing works are less likely to result in a successful proposal. +If providing translations, they must be done accurately by a native or expert speaker (i.e. no translation tools). +Content must be accessible and open source. +Any images used must be Creative Commons licensed. +Content should contain no harmful language or explicit content, or false or misleading information. + +Start your proposal with the following steps: + +## Title + +Give your project a title. + +## About You + +**General**: Tell the community about yourself and your team if applicable, outlining your interest and motivation in submitting the proposal. Mention any experience you have in the subject matter. + +**Profile**: Share links to your platforms and social networks. + +**Contact**: Add your contact email or social handles so the Council can reach out with questions and/or verify your authorship. + +## Purpose + +Explain your vision and motivation. +Whatโ€™s driving you to create content and whatโ€™s the intended outcome? + +## Description + +**Overview**: Describe the project in detail. Whatโ€™s the focus of the content series? (Technical / High-level, Technical / Education). + +**Platforms**: What platform will the content be published on? Where will it live? Whatโ€™s the format? Whatโ€™s your demographic / audience reach? + +**Work**: If the content has already been created, provide links to all works under consideration. If itโ€™s for future-facing content, provide links and evidence of related work. + +**Schedule**: Give an overview of the intended release schedule for the content. + +## Financial + +How much do you need? +Break down the costs. +Price it in terms of USD, and relate it to the current price of the KILT Coin at the time of the proposal. +Note the beneficiary address here. \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/participate/05_propose_tip.md b/versioned_docs/version-0.35.0/participate/05_propose_tip.md new file mode 100644 index 000000000..84196c2c7 --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/05_propose_tip.md @@ -0,0 +1,87 @@ +--- +id: treasury-tip +title: Treasury Tips +--- + +Similar to [opening a Treasury proposal](./03_treasury_proposal.md), anyone can start a tipping process. + +You can expect success if the tip is based on a meaningful contribution. +The variety of potential contributions is vast, read the [KILT Contribution guide](../develop/06_contribute.md) for a high level description of tips and the differences to Treasury proposals. + +This document covers the necessary steps from requesting a tip to receiving it. + +## Lifecycle of a tipping process + +Anyone can propose a tip, including for someone else, the **Beneficiary**. +In this case, you, the **Finder**, need to put down a **minor deposit**, which depends on the length in characters of the reason for the tip. +Overall, you should expect to provide **between 0.05 to 0.2 KILT** as a deposit. +For example, if you provide a URL that includes 60 characters, the deposit would be around 0.07 KILT. + +After making a tip proposal, the set of tippers, elected by the KILT Council, come to consensus on how much to pay. +Every member of this stakeholder group, the **Tippers**, can submit an appropriate amount. +Eventually, the median of all tips is taken as the final amount. + +Once at least half of the Tippers have declared their tip, the ending phase starts. +After 24 hours have passed, the tip is automatically closed and paid from the Treasury. +However, other Tippers can still submit their suitable amount and thus influence the final amount of the tip. +After payout, the original deposit is returned to the Finder. +The Tippers will not approve the proposal and pay it out until at least half the tippers have voted with `Aye`. At any point before the tip is approved, the Finder can cancel the tip proposal and get back their deposit. + +:::note No Finder's fees +While tipping allows a configurable percentage of the final tip to go to the original Finder, the current KILT configuration has set this fee to 0, meaning that the Finder's will not get rewarded for successful tips. +::: + +```mermaid +flowchart TD + %% Alice + Alice(("Alice \n (Finder or Tipper)")):::Finder --> Alice_Finder{Is Finder?}:::Finder + Alice_Finder -.-> |Yes| Alice_Finder_Deposit(reserve deposit):::Finder + Alice ----> |"Provide tipping reason (URL/Polkassembly) and set target"|Beneficiary(("Bob \n (Beneficiary)")):::Beneficiary + + %% Tipping Start + Beneficiary --> Tip_1_Start("Wait for tips"):::process + Tip_1_Start --> Tip_2_Threshold{"More than 50% \n of Tippers tipped?"}:::process + Tip_2_Threshold:::process --> |No| Tip_1_Start + + %% Tipping End + Tip_2_Threshold --> |Yes| Tip_3_End{{Start of Ending phase}} + Tip_3_End:::processEnd --> Tip_4_Wait(Wait for blocks to pass) + Tip_4_Wait:::processEnd --> Tip_5_Blocks{"TipCountdown: \n Sufficient number \n of blocks passed?"} + Tip_5_Blocks:::processEnd --> |No| Tip_4_Wait + + %% Tipping close + Tip_5_Blocks --> |Yes| Tip_6_Close(Trigger closing of tipping process):::Payment + Tip_6_Close -.-> |"Unreserve Deposit \n (only if Finder)"| Alice_Finder_Deposit + Tip_6_Close --> Payout_1("Final tip amount = median of received tips"):::Payment + + %% Treasury + Payout_1 --> Payout_2{Is there a Finder's fee?}:::Payment + Payout_2 --> |Yes| Payout_3(Reduce final tip amount by Finder's fee):::Payment + Payout_2 --> |No| Payout_4[("๐Ÿ’ฐ Treasury")]:::Payment + Payout_3 --> Payout_4{{"Ready to pay out"}} + Payout_4 --> Treasury[("๐Ÿ’ฐ Wait for Spending Period \n of Treasury to end")]:::Payment + Treasury ==> |"Receive tip"| Beneficiary + Treasury -.-> |"Pay out Finder's fee"| Alice + + %% classes + classDef Finder fill:#fff4bd,stroke:none; + classDef process fill:#c7fff9,stroke:black; + classDef processEnd fill:#6be6d8,stroke:black; + classDef Beneficiary fill:#7cd27c,stroke:#333,stroke-width:0px; + classDef Payment fill:#ff9393,stroke:black; +``` + +## Proposing a tip + +Proposing a tip much is simpler than opening a Treasury proposal. + +![A screenshot showing the Treasury options from the Governance menu](@site/static/img/chain/tipping-navigation.png) + +From [polkadot.js.org/apps](https://polkadot.js.org/apps), open _Governance > Treasury > Tips_ and click the _+ Propose tip_ button. + +![A screenshot showing selecting the tip request dialog](@site/static/img/chain/tipping-extrinsic.png) + +1. Select your account as the extrinsic submitter in the _submit with account_ field +2. Provide the address to receive the tip in the _beneficiary_ field +3. Provide a reason in the _tip reason_ field. This can either be some **descriptive words or a URL**. The _tip reason_ field should point to the contribution(s), e.g., the GitHub pull request, blog posts, translations or videos among other things. The tipping process will fail if the reason is not recognizable. +4. Sign and submit the extrinsic with the _Propose tip_ button \ No newline at end of file diff --git a/versioned_docs/version-0.35.0/participate/_category_.json b/versioned_docs/version-0.35.0/participate/_category_.json new file mode 100644 index 000000000..7ce6ec21a --- /dev/null +++ b/versioned_docs/version-0.35.0/participate/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Participate", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/concepts/01_what_is_kilt.md b/versioned_docs/version-1.0.0/concepts/01_what_is_kilt.md new file mode 100644 index 000000000..735059fbc --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/01_what_is_kilt.md @@ -0,0 +1,68 @@ +--- +id: what-is-kilt +title: What is KILT? +--- + +KILT is a protocol for self-sovereign data and interoperability built on top of the permissionless KILT blockchain. + +The core component of KILT is a digital identity protocol for: + +1. Generating and managing [**decentralized identifiers (DIDs)**](./10_glossary.md) +2. Issuing and presenting digital [**verifiable credentials (VCs)**](./10_glossary.md). + +In contrast to other centralized alternatives, KILT features self-sovereign data and revocable [credentials](./10_glossary.md) anchored to the KILT blockchain. + +KILT was built to be a business enabler, not only for the software industry but also for any entity. +Such entities can establish a business model based on the trust infrastructure KILT provides, which is an essential building block of Web 3.0. + +## What KILT provides + +In particular, KILT provides: + +* A **universal identity protocol** for individuals, organizations, objects, and intelligent agents to obtain credentials for arbitrary attributes about themselves issued by trusted [Attesters](./10_glossary.md). +* A **self-sovereign mechanism** for putting credential holders in control of their own data, allowing them to choose if and where they make their credentials public and how much information from those credentials they wish to share. +* A **[Trust Market](./10_glossary.md) for [Attesters](./10_glossary.md)** of such credentials, allowing widely trusted entities to be compensated for their valuable attestation work. + +KILT's main goal is to generate a level playing field for companies to explore new business models related to trust relationships and data sovereignty. +KILT enables businesses and governments to rely on a common standard owned by everyone participating and not by a single company or set thereof. + +## The problem + +In the beginning, identity and trust between entities were organized in a fully decentralized way. +Individuals created trust relationships directly between them based on their observations. +Of course, this had major drawbacks: + +* The size of the personal social network is limited +* It's not trivial to judge the trustworthiness of an individual +* It's hard to prove one's own identity to outsiders + +When people started to organize themselves in bigger groups, founding villages and cities, those drawbacks were amplified and people needed to address them. +People introduced mechanisms to create trust relationships between groups by issuing some form of attestation. +In this way, people who don't know the individual directly but who trusted the group that gave the attestation. For example, a carpenter's guild, a monastery or a Scottish clan could verify certain properties about another individual. +When the organizational structures grew further and large bureaucratic nations emerged, the authorities issuing those attestations and the scope of the trust relationships also grew. + +While there is now a more centralized way of organizing trust, the actual information that makes up an identity is still handed out directly to the individual, who is still responsible for their data. +Take official personal documents like passports as an example. +Trusted entities issue them and hand them out to the holder. +That holder then has full control of their credential (their passport) and can use it wherever needed. + +With the invention of the internet, and later of Web 2.0, services evolved and merged into totally centralized solutions including Google, Meta, and X among others. +They no longer attest to someone's email account, but due to their business model, those same service providers store and control our personal data (i.e., our identity). +For instance, they could stop allowing us to log into a certain website if they decide to. +More often than not, companies store the data out of necessity and for their own business purpose. +Every time users log into any service, they generate new data points which are then aggregated and sold for advertising purposes. + +KILT Protocol aims to change that and give users back control over their data. + +## The solution + +KILT provides a protocol and the tools for people to manage their own data, and to build a [digital identity](./10_glossary.md) by collecting credentials issued by trusted entities. +Such credentials aren't publicly available but stay within the user's control. +This is similar to the approach used for centuries before big corporations monetized our data. + +The core ideas are: + +* Managing user identities in the form of [decentralized identifiers (DIDs)](https://w3c-ccg.github.io/did-spec/), with the support of the KILT blockchain +* Obtaining digital [verifiable credentials](./10_glossary.md) for user-specified claims +* Supporting revocation of verifiable credentials by their Attesters +* Presenting and verifying verifiable credentials in a privacy-preserving and user-controlled way diff --git a/versioned_docs/version-1.0.0/concepts/02_did.md b/versioned_docs/version-1.0.0/concepts/02_did.md new file mode 100644 index 000000000..7c1164c6c --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/02_did.md @@ -0,0 +1,87 @@ +--- +id: did +title: KILT Decentralized Identifiers (DIDs) +--- + +A KILT decentralized identifier (DID) is a string of letters and numbers uniquely identifying each KILT user. + +Think of a DID as a container of different keys all under the control of the same DID subject. + +:::info DID spec + +For the official W3C DID spec, read the [DID Core spec page](https://www.w3.org/TR/did-core/); for the official KILT DID method specification, read the [KILT DID spec page](https://github.com/KILTprotocol/spec-kilt-did). + +::: + +The simplest type of KILT DID is a **[light DID](#light-dids)**, because you can generate and use it offline and no connection with the KILT blockchain. +Although cheap, light DIDs aren't flexible and are only suitable for low-security use cases. +In more complex use cases, you need an on-chain **[full DID](#full-dids)**, which allow the subject to store different keys and key types and replace them over time by using the KILT blockchain. + +## Light DIDs + +The following is an example of a light KILT DID: + +``` +did:kilt:light:014nv4phaKc4EcwENdRERuMF79ZSSB5xvnAk3zNySSbVbXhSwS +``` + +Beyond the standard prefix `did:kilt:`, the `light:` component indicates that this DID is a light DID, hence it can be resolved and used offline. + + + +Light DIDs optionally support the specification of an **encryption key** (of one of the supported key types) and services, which are both serialized, encoded, and added at the end of the DID, like the following: + +``` +did:kilt:light:014nv4phaKc4EcwENdRERuMF79ZSSB5xvnAk3zNySSbVbXhSwS:z1ERkVVjngcarMbJn6YssB1PYULescQneSSEfCTJwYbzT2aK8fzH5WPsp3G4UVuLWWfsTayketnFV74YCnyboHBUvqEs6J8jdYY5dK2XeqCCs653Sf9XVH4RN2WvPrDFZXzzKf3KigvcaE7kkaEwLZvcas3U1M2ZDZCajDG71winwaRNrDtcqkJL9V6Q5yKNWRacw7hJ58d +``` + +## Full DIDs + +The creation of a full DID requires interaction with the KILT blockchain. +Therefore, a KILT address with enough funds to pay the transaction fees and the required deposit must submit the DID creation operation. + +The following is an example of a full KILT DID: + +``` +did:kilt:4rp4rcDHP71YrBNvDhcH5iRoM3YzVoQVnCZvQPwPom9bjo2e +``` + +Above, there is no `light:` component. +This indicates that the DID is a full DID and that you can't derive the keys associated with it from the DID identifier, but retrieve them from the KILT blockchain. + +Along with an authentication key, encryption key, and services, a full DID also supports an **attestation key**, which you must use to write CTypes and attestations on the blockchain, and a **delegation key** to write delegations on the blockchain. + +## Migrating a light DID to a full DID + +The **migration** of a DID means that a light, off-chain DID is anchored to the KILT blockchain, supporting all the features that full DIDs provide. +In the current version (v1) of the KILT DID protocol, a light DID of the form `did:kilt:light:014nv4phaKc4EcwENdRERuMF79ZSSB5xvnAk3zNySSbVbXhSwS` would become a full DID of the form `did:kilt:4nv4phaKc4EcwENdRERuMF79ZSSB5xvnAk3zNySSbVbXhSwS`. + +:::note + +The identifier of the two DIDs, apart from the initial `01` sequence of the light DID, are the same since both DIDs are derived from the same seed. + +::: + +**Once you migrate a light DID, you can only present all the credentials collected by the light DID using the migrated on-chain full DID.** + +This restriction is by design, as it's assumed that the user had valid reasons to migrate the DID, as on-chain DIDs offer greater security guarantees. +KILT thus rejects light DID signatures even if the original claim in the credential was generated with that off-chain DID. + +:::tip + +For a detailed developer-oriented guide to KILT DIDs, read the [DID Cookbook section](../develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md). + +::: + +## Storing a DID + +Storing a DID on the KILT blockchain requires a deposit, consisting of a base deposit and an additional fee. The base deposit is a fixed amount of 2 KILT, while the additional fee is 0.05 KILT. + +In addition to the base deposit and fee, the total deposit increases based on the storage space used by the DID. Each byte of storage occupied by the DID requires a deposit of 50 micro KILT (0.000005 KILT). + +The inclusion of services and keys determines the overall size of the DID. +The more services and keys in the DID, the larger the storage space required and, consequently, the higher the additional deposit. + +When updating the DID, the deposit is automatically adjusted to match the updated size. This ensures that the deposit accurately reflects the current storage requirements of the DID, whether they increase or decrease. + +You can reclaim the deposit when the DID is deleted from the blockchain, allowing users to retrieve the deposited amount. However, the additional fee can't be refunded once paid. diff --git a/versioned_docs/version-1.0.0/concepts/03_web3names.md b/versioned_docs/version-1.0.0/concepts/03_web3names.md new file mode 100644 index 000000000..b2f54a1cc --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/03_web3names.md @@ -0,0 +1,76 @@ +--- +id: web3names +title: web3names +--- + +import ThemedImage from '@theme/ThemedImage'; + +web3names are user-friendly aliases for KILT DIDs. +They serve the same purpose as domain names for IP addresses. +Do you know the IP address for the "kilt.io" domain name? ๐Ÿคท๐Ÿฝโ€โ™€๏ธ +There is a one-to-one relationship between DIDs and web3names. +This means that you can link a KILT DID to only one web3name, and a web3name can only claim one DID. + +Each web3name is globally unique within the KILT blockchain and consists of a sequence of a minimum of 3 to a maximum of 32 characters taken from a specific character set to enhance human readability and reduce the chances of *two web3names looking the same, despite being different*. + +The character set includes only: + +- *lowercase letters*, from `a` to `z` +- *digits* from `0` to `9` +- the symbols `-` and `_` + +A regex that matches all and only the allowed web3names is the following: + +``` +^[a-z0-9_-]{3,32}$ +``` + +In the global URI space, web3names are prefixed with the `w3n:` URI namespace. +For example, the full URI for the web3name `example-web3name` is `w3n:example-web3name`. + +### Linking multiple accounts to a web3name + +Beyond linking a web3name, KILT lets DID owners link multiple accounts to a single DID. +These accounts aren't specific to the KILT blockchain. +They can reference any chain within the Polkadot ecosystem. +Each account to DID link requires paying a small deposit. + +For DIDs that have also claimed a web3name, the linking feature opens the way to a host of possibilities. +For example, showing the web3name of a collator's account on the [KILT Stakeboard](https://stakeboard.kilt.io/). + + + +For a detailed developer-oriented guide to web3names and account linking, read the [web3name Cookbook section](../develop/01_sdk/02_cookbook/02_web3names/01_claim.md) and the [account linking Cookbook section](../develop/01_sdk/02_cookbook/03_account_linking/01_link.md). + +## KILT DIDs vs. KILT accounts + +While you can link multiple accounts to a DID, it's important to notice the difference between the two. + +KILT *accounts* are classical blockchain accounts, that can hold and send KILT tokens, and sign and submit transactions. + +KILT *DIDs* are a higher level construct derived from KILT accounts, but are completely separated from them. + +This means that **KILT DIDs can't hold any KILT tokens**. + +You use DIDs to authorize (sign) some operations, but you must submit the resulting signature to the KILT blockchain with a KILT account, which must pay for the transaction fees. + +Don't consider a DID `did:kilt:4rp4rcDHP71YrBNvDhcH5iRoM3YzVoQVnCZvQPwPom9bjo2e` the same as the account `4rp4rcDHP71YrBNvDhcH5iRoM3YzVoQVnCZvQPwPom9bjo2e`, although they share the same identifier. + +:::caution + +There's no (immediate) relationship between the two, so you should consider a DID **only as a DID** and never as an account. +If instructed to "*send some funds to the DID by using the account after the `did:kilt` prefix*". Ignore the advice, as without the required technical expertise, sending funds to a DID can result in loss of those funds. + +::: + +### The cost for storing a web3name + +Storing a web3name on the KILT blockchain requires providing a constant deposit, which is currently around 0.11 KILT. The deposit amount is calculated based on the worst-case scenario for a web3name, which is when a user provides a name with 32 characters. +The deposit serves as a security measure to ensure the integrity of the KILT blockchain and incentivize users to manage their web3names responsibly. +A deposit discourages spamming or unnecessary creation of web3names. You can reclaim the deposit can by deleting a web3name. diff --git a/versioned_docs/version-1.0.0/concepts/04_asset_dids.md b/versioned_docs/version-1.0.0/concepts/04_asset_dids.md new file mode 100644 index 000000000..f0b3d8528 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/04_asset_dids.md @@ -0,0 +1,58 @@ +--- +id: asset-dids +title: AssetDIDs +--- + +import ThemedImage from '@theme/ThemedImage'; + +KILT DIDs are suitable for use cases that involve "active" participants. +For example, entities that can act of their will (a person, an organization, a DAO). + +There are classes of entities that represent "passive" participants. +That is, they can be "used" by active participants within a given use case. +KILT defines these class of participants as **assets**. +As with traditional KILT users, assets also need to be uniquely identified, with an *AssetDID*. + +An example of a valid AssetDID is the following: `did:asset:eip155:1.erc721:0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb`. +This AssetDID refers to the [CryptoPunks NFT collection][cryptopunks-nft]. + +## AssetDID structure + +An AssetDID is a *generative* identifier, meaning that it doesn't depend nor rely on any information stored anywhere. +Rather, given the asset to identify, it's **always** possible to generate its AssetDID. +The reverse is also true. Given an AssetDID, it's always possible to dereference it into its components, which, together, uniquely identify a given asset. + +AssetDIDs always start with the `did:asset` prefix, and then contain a *chain* component (namespace + reference) and an *asset* component (namespace + reference + identifier). + +### Chain namespace and reference + +Together, the namespace and reference identify the (blockchain) network on which the asset lives. + +In the case of NFTs, this represents the blockchain on which the smart contract is deployed. +Different deployments of the same network have the same chain namespace but a different reference. +For instance, both the Ethereum mainnet and the Goerli testnet have a chain namespace of `eip155`, but the former is identified by the reference `1` (as the mainnet), while the Goerli testnet is identified by the reference `5`. + +### Asset namespace, reference and identifier + +Similar to their chain counterparts, you use asset *namespaces* to distinguish among different asset classes within the same environment. +In the case of NFTs, a smart contract could support both ERC20 (fungible) and ERC721 (non-fungible) tokens, hence the namespace distinguishes between the two token types. + +Each asset namespace defines the semantics and the meaning of asset references and asset identifiers within that namespace. +In the example of Ethereum-based NFTs, the asset *reference* identifies the smart contract address that stores the NFT. + +**The combination of asset namespace + asset reference is sufficient to identify an NFT collection on a given network.** + +For some assets, for instance NFTs, it's possible to specify an asset *identifier*, used to refer to a single item within the collection. +In the example of the CryptoPunks collection, the AssetDID could be extended with an additional `:1005` to now refer to the [CryptoPunk piece #1005][cryptopunk-1005] rather than to the CryptoPunks collection as a whole. + +![][cryptopunk-1005-image] + +*Credits to OpenSea for the NFT image above.* + +For a more technical explanation of AssetDIDs, please visit our [official specification][asset-did-spec]. + +[cryptopunks-nft]: https://opensea.io/collection/cryptopunks +[cryptopunk-1005]: https://opensea.io/assets/ethereum/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb/1005 +[cryptopunk-1005-image]: https://i.seadn.io/gae/qoR1cWuIZzjlrNVcSMAzhrwDvXNtMxaYuDbNqkc_J5WGGqMSrF0wzO7K2MnSCEBLG8G8pZyJPqV7eTGt4wGwret85sbXJBYoAkypdQ?auto=format&w=3840 +[chainlist]: https://chainlist.org/ +[asset-did-spec]: https://github.com/KILTprotocol/spec-asset-did \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/concepts/05_credentials/01_overview.md b/versioned_docs/version-1.0.0/concepts/05_credentials/01_overview.md new file mode 100644 index 000000000..42ce07760 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/05_credentials/01_overview.md @@ -0,0 +1,44 @@ +--- +id: overview +title: Overview +--- + +import ThemedImage from '@theme/ThemedImage'; + +**Credentials** consist of a set of claims which belong to a **Claimer**, are attested by an **Attester**, and that a **Verifier** can verify. + +
+ +
+ +To get a credential, a Claimer needs to take the following steps: + +1. Find a **CType** to base a claim on. Potential Attesters and Verifiers might advertise this information themselves. +2. Make a **claim** containing a set of properties about themselves. +3. Fulfil any requirement from your Attester. For example, accepting their **Terms** and paying a **Quote**. +4. **Request an attestation** from the Attester. +5. Wait for the Attester to **attest** claims. + +Once attested, the wrapped claims are considered to be a valid credential. + +To use a Credential, the Claimer can generate a Credential-Presentation for a Verifier. +The verification would follow this process: + +1. The Verifier may request a **Credential** of a CType, along with with properties to reveal. +He would also provide a **challenge** to ensure the presentations are not recycled. +2. The Claimer selectively **discloses** the requested properties and signs them along with the challenge to generate a presentation. +3. The Verifier **verify** the presentation structure, content and signature, and decides whether they trust the Attester of the presented credential. + +The next sections describe each step in more detail. + +:::info + +To learn about how to implement the flow above in a dapp that interacts with a browser extension, read the [Credential API specification](https://github.com/KILTprotocol/spec-ext-credential-api). + +::: diff --git a/versioned_docs/version-1.0.0/concepts/05_credentials/02_ctypes.md b/versioned_docs/version-1.0.0/concepts/05_credentials/02_ctypes.md new file mode 100644 index 000000000..11aa11918 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/05_credentials/02_ctypes.md @@ -0,0 +1,131 @@ +--- +id: ctypes +title: CTypes +--- + +import CodeBlock from '@theme/CodeBlock'; + + + +import ctypeSchema from '@site/scripts/out/ctype-schema.json.raw!=!raw-loader!@site/scripts/out/ctype-schema.json'; +import ctype from '@site/scripts/out/ctype.json.raw!=!raw-loader!@site/scripts/out/ctype.json'; + +Claim types (CTypes) are data types specific to KILT that define the structure of a claim (i.e., its data model). +CTypes are based on [JSON Schema](https://json-schema.org/), a standard used to annotate and validate JSON documents. +The schema defines which properties exist and what their type should be, e.g., a string, a number, an object, etc. + +## CType model JSON schema + +The following are all required properties of the JSON schema for CType models: + +- `$id`: An **identifier**: in the format `kilt:ctype:0x{cTypeHash}`. +- `$schema`: A **reference to CType metaschema**: Describes what a valid CType must looks like. You can find the latest metaschema on IPFS at the following address [ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq/](ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq/). +- `title`: A user-friendly name for the CType that makes it easier for users to contextualize. +- `properties`: A set of fields (e.g., name, birth date) that the CType can contain, and that the Claimer can have attested. [Read more details about properties below](#properties). +- `type`: An object containing properties for a claim about the Claimer in the credential. +- `additionalProperties`: A boolean added since version 1 of CTypes, that must be set and allows or disallows any properties in addition to those in `properties`. If set to `false`, the CType validation will fail if there are any additional properties. + +### Properties + +When creating the accepted properties of a new CType schema, you define each property as a key-value pair. +The **key** is the property name (such as "age") and the **value** is an object that has a "type" property whose property defines which type the credential property should have (e.g., "number") or a `$ref` property whose value is a reference to another CType or one of its properties. Using a `$ref` allows for nested CTypes + +Each property must have: + +- One of the following fields: `type` or `$ref` +- A type of `string`, `integer`, `number` or `boolean` to define the attribute +- Reference nested JSON schemas from previously created CTypes with a `uri` using `$ref`. +- The format field is optionally: + - _Date_ format e.g., 2012-04-23T18:25:43.511Z + - _Time_ format e.g., T18:25:43.511Z + - _URI_ format e.g., "https://www.example.com" + + + {ctypeSchema} + + +When submitted, the CType schema is hashed to generate its own identifier, and it becomes the full CType object: + + + {ctype} + + +## CType metadata + +You can link CType Metadata to a given CType to provide title and descriptions in different languages for the whole CType and its properties. + + + +## Hashing + +Use the hash of the CType to identify and anchor it to the KILT blockchain. Once this is done, it's no longer possible to change or delete the CType schema. + +### Constructing the `hash` for the `$id` + +KILT uses the `blake2b256` hashing algorithm to compute the hash of CTypes, after sorting the CType object by a canonicalization algorithm to ensure that semantically equivalent CTypes with different orders of their properties result in the same final hash. + +KILT computes the hash from the following fields of the CType schema: + +- `$schema` +- `properties` + - `key` + - `$ref` + - `type` + - `format` +- `title` +- `type` + +A typical CType ID looks like this: `kilt:ctype:0xda3861a45e0197f3ca145c2c209f9126e5053fas503e459af4255cf8011d5101`. + +## Storing and querying CTypes + +As of the [KILT runtime 1.9.0][kilt-runtime-1.9.0], you can query CTypes directly from any KILT archive node. + +After creating a CType, its full content is only included in the blockchain block history and its hash and creation block number anchored to the blockchain state. + +To query the full content of a CType, use its hash to look up the creation block number, and use that to query any KILT archive node for the extrinsic information about the CType. + +The returned information includes the whole CType, which is now available for the user to, for example, verify credentials against it. + +:::info CType creation cost + +Currently, it costs 0.001 KILT to create a CType on the KILT blockchain. + +::: + +For a detailed developer-oriented guide to KILT CTypes, read the [CType Cookbook section](../../develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md). + +[kilt-runtime-1.9.0]: https://github.com/KILTprotocol/kilt-node/releases/tag/1.9.0 + +:::danger Deprecation Warning: CType metaschema draft-01 + +CTypes based on the [Draft 01](http://kilt-protocol.org/draft-01/ctype) metaschema are subject to a vulnerability that could fool an **Attester** by introducing data they never checked. + + +Due to this vulnerability, this version of the metaschema is deprecated and its use is discouraged when creating new CTypes. + +For optimal security and functionality, use SDK version `0.33.0` or later for creating CTypes. +This newer version defaults to using the updated metaschema available at [`ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq/`](ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq). + +This also means you should update existing CTypes. +While existing CTypes continue to work in the short term, we advise to upgrade to the latest metaschema at your earliest convenience. + +Old Property Value: `"$schema": "http://kilt-protocol.org/draft-01/ctype"` +New Property Value: `"$schema": "ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq/"` + +## Migration instructions + +Attesters should transition to issuing credentials using upgraded versions of CTypes currently in use. + +Using sdk version `0.33.0` or later, you can produce a copy of an existing CType `oldCType` as follows: + +```js +const newCType = CType.fromProperties(oldCType.title, oldCType.properties, 'V1') +``` + +The new CType has the same title and properties as the existing one, but be based on the new metaschema, resulting in a different hash and id. +After [registering the new CType on the KILT blockchain](../../develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md), you can use the new CType as a drop-in replacement in issuing credentials. + +Verifiers depending on these CTypes should accept both the old and new CType during a transition period. +Test thoroughly to ensure the correct behavior and functionality of the new CTypes in your application. +::: diff --git a/versioned_docs/version-1.0.0/concepts/05_credentials/03_claiming.md b/versioned_docs/version-1.0.0/concepts/05_credentials/03_claiming.md new file mode 100644 index 000000000..1779099f6 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/05_credentials/03_claiming.md @@ -0,0 +1,40 @@ +--- +id: claiming +title: Claims +--- + +import CodeBlock from '@theme/CodeBlock'; +import Claim from '@site/scripts/out/claim.json.raw!=!raw-loader!@site/scripts/out/claim.json'; + +As KILT is an open system, entities can make claims about any other entities, including themselves. +An entity can only trust a claim (as in the real world) if another trusted entity (called **Attesters**) *certifies* this claim. +Therefore, **Verifiers** might trust different **Attesters** for distinct scenarios. + +:::info Role recap +- **Claimers** want information about themselves certified. +They also issue credentials, but these remain invalid without an attestation. +- **Attester** check the truthfulness of a claim and certify them. +- **Verifiers** accept the credentials, only verifying that your certification are legitimate. +::: + +## Creating a claim + +In KILT, claims are based on claim types (CTypes). +Given a CType, a Claimer only needs to create a claim with the properties specified in the CType schema. +The resulting claim contains a reference to the CType by its hash and includes the identity of the claim subject (identified by the `owner` property, which has the value of a KILT DID). + + + {Claim} + + +## Requesting a credential + +Once the Claimer has wrapped their claims into a `Credential`, they send it to the chosen Attester using any messaging system for **certification**, i.e. attested. + +The to-be-attested `Credential` contains the original claim, data needed for future selective disclosure of the claim contents (read more in the [Verification documentation](./05_verification.md)), and the legitimation and / or delegation ID of the Attester and the credential root hash, used to identify both the credential and its on-chain attestation. + +:::info + +For a detailed developer-oriented guide to KILT claims, read the [Claim Cookbook section](../../develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md). + +::: diff --git a/versioned_docs/version-1.0.0/concepts/05_credentials/04_attestation.md b/versioned_docs/version-1.0.0/concepts/05_credentials/04_attestation.md new file mode 100644 index 000000000..33c9c2aae --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/05_credentials/04_attestation.md @@ -0,0 +1,28 @@ +--- +id: attestation +title: Attestations +--- + +KILT uses the terms Attestation and Credential interchangeably, but their meaning is different. +A _Credential_ includes the original claimer's data and all the information linked to it, while an _Attestation_ only refers to the on-chain proof that a given credential has been attested. + +To write an attestation on the KILT blockchain, the Attester checks the validity of the received to-be-attested `Credential` data, ensuring that the data inside it matches the requirements of the attestation. For example, that the user's name is indeed Alice. + +After that, the Attester writes the `Credential`'s root hash on the KILT blockchain, certifying that a credential with that root hash is valid. +The Claimer can monitor the blockchain to listen for the event resulting from the attestation process, marking when the credential is attested and usable. + +After the credential has been attested, the Claimer can store it in their wallet and can now use it with Verifiers that trust credentials issued by that Attester. + +:::info + +For a detailed developer-oriented guide to KILT attestations, read the [Attestation cookbook section](../../develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md). + +::: + +### Storing attestations + +Storing a attestation in the blockchain requires providing a constant deposit, which is currently around 0.12 KILT. The deposit amount is calculated based on the worst-case scenario for a attestation, where the maximum storage for one attestation reaches 179 bytes. +The deposit serves as a security measure to ensure the integrity of the blockchain and incentivize users to manage their attestation responsibly. +By requiring a deposit, it discourages spamming or unnecessary creation of attestation. +The attester can reclaim the deposit by deleting their attestation. +Revoking them isn't sufficient as the deposit still shows in chain storage, but marked as invalid. \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/concepts/05_credentials/05_verification.md b/versioned_docs/version-1.0.0/concepts/05_credentials/05_verification.md new file mode 100644 index 000000000..0c50f9dcb --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/05_credentials/05_verification.md @@ -0,0 +1,113 @@ +--- +id: verification +title: Verification +--- + +KILT lets a Verifier check if the information in a credential presented by a Claimer is correct and valid. +With the presentation of the credential, the Claimer also presents evidence that a third party (i.e., an Attester) ensured the correctness of the Claimerโ€™s attributes. + +The Verifier trusts this third party either because they trust their reputation directly or they trust a delegation structure that this Attester is part of. +For example, a State department issuing driving licenses. + +For the verification process: + +- The Claimer needs their credential and the private key associated with their identifier +- The Verifier needs the identifier of the trusted Attester + +During the verification process the Claimer wants to prove the following things to the Verifier: + +- The credential is valid (i.e., not revoked by its Attester) +- The attributes in the credential actually refer to it's Presenter +- The credential contains information relevant for the Verifier for this use case +- That an Attester ensured the correct and trustworthy-ness of the Claimer's attributes + +## Requesting a credential from a Claimer + +The Verifier may request a credential from a Claimer, providing the following data: + +- `cTypeHash`: Which CType hashes the Verifier can work with for the use case. They can provide multiple options, to regard as alternatives. +- `trustedAttesters`: Which Attesters to consider trusted for each specified CType. +- `requiredProperties`: Which properties for each specified CType must at least be revealed for the Verifier to consider the presentation sufficient. + + :::info + + [Read more on selective disclosure](#presenting-a-credential-with-selective-disclosure). + + ::: +- `challenge`: A nonce, which the Verifier can use to ensure that the presentation generated by the Claimer is fresh and not replayed by some other older interactions. + +### Example + +```json +{ + "body": { + "content": { + "cTypes": [ + { + "cTypeHash": "0x3291bb126e33b4862d421bfaa1d2f272e6cdfc4f96658988fbcffea8914bd9ac", + "trustedAttesters": [ + "did:kilt:4pehddkhEanexVTTzWAtrrfo2R7xPnePpuiJLC7shQU894aY" + ], + "requiredProperties": [ + "Email" + ] + } + ], + "challenge": "0x5a1a17eca9ddf6b4d14dffb2abd1411fe9235927975a246b3963db86dfb7de5f" + }, + "type": "request-credential" + } +} +``` + +## Presenting a credential with selective disclosure + +Given the `requiredProperties` specified by the Verifier, the Claimer can decide how much of the information they wish to reveal before they generate the presentation and send it to the Verifier. +If supported by the Verifier, they can choose to hide attributes and thus only disclose a subset of the original claim data. + +:::caution +The presentations can still be correlated, since the hash of the credential always stays the same, even when creating new presentations and selecting different attributes to show. +::: + +For example, verifying a driving license only requires the verification of the driver's name and picture. A Claimer can decide to hide additional information such as age and place of residence. +This increases the privacy of the Claimer since they only need to show attributes required in the specific context. + +:::info + +For a detailed developer-oriented guide to KILT presentation creation, read the [presentation creation cookbook section](../../develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md). + +::: + +## Verifying a presentation + +The Verifier receives the presentation from the Claimer, re-calculates the root hash of the credential from which the presentation was generated, and queries the KILT blockchain to obtain the associated attestation information, including the revocation status of the credential. + +If the Claimer tampered with the credential, the re-calculated root hash won't match any attestation on the chain. +On the other hand, if the Verifier can find an attestation with the calculated hash on the chain and hasn't been revoked, the credential is valid. + +However, this doesn't give the Verifier the guarantee that the Claimer is the rightful/legitimate owner of the credential presented. + +### Verifying the owner of the presented credential + +When issued, a credential is linked to the KILT decentralized identifier (DID) of the original Claimer. +The Verifier can resolve the DID to the public key of the Claimer according to the [KILT DID specification](https://github.com/KILTprotocol/spec-kilt-did). + +The Verifier assumes that the private key for the DID public key is only known to the owner of the credential, and isn't shared across users. +Therefore, when requesting the Claimer to generate a presentation, the Verifier challenges the Claimer to sign a nonce (a random number used once) that the Verifier sends together with their request. + +If the Claimer can sign both the nonce and the presentation with the private key that only the credential's owner should have knowledge of, the Verifier can be sure that the Claimer is the legitimate owner of the credential. + +### Verifying the content of the presented credential + +After the Verifier has checked that the credential is valid and belongs to the presenting Claimer, they need to verify that they have received all the required information. +This is to verify that the presentation received contains the right values **and** the right semantics. + +For example, the `age` property could have different meanings depending on whether it's defined for a passport CType or a Whisky certificate CType. +Therefore, the Verifier has to check if the CType matches one of the requested CTypes, and that the properties disclosed in the presentation includes all the properties requested for that CType presentation. + +:::info + +For a detailed developer-oriented guide to KILT credential verification, read the [verification cookbook section](../../develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md). + +::: + diff --git a/versioned_docs/version-1.0.0/concepts/05_credentials/06_public_credentials.md b/versioned_docs/version-1.0.0/concepts/05_credentials/06_public_credentials.md new file mode 100644 index 000000000..e220b1962 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/05_credentials/06_public_credentials.md @@ -0,0 +1,27 @@ +--- +id: public-credentials +title: Public Credentials for Assets +--- + +import CodeBlock from '@theme/CodeBlock'; + +import PublicCredential from '@site/scripts/out/public-credential.json.raw!=!raw-loader!@site/scripts/out/public-credential.json'; + +[AssetDIDs][asset-did-concepts] give a way to uniquely identify assets regardless of the blockchain they live on or their current owner. +KILT allows owners of an on-chain DID with an assertion key (a.k.a. attesters) to issue credentials to those assets. + +Public credentials aren't that different in their structure from traditional KILT credentials. +The main difference is that, since they're public, they don't have selective disclosure capabilities. +This is because the cryptographic information required to enable this is stripped away from the credential content. + + + {PublicCredential} + + +:::warning Anyone can be an attester! +While the owner of normal KILT credentials holds them in their wallet and decides what credential to share with who, public credentials are, as the name suggests, public by design. + +This means that when reading the credentials issued for a given asset, consumers should be aware of the level of trust they have towards the issuer of each credential. +::: + +[asset-did-concepts]: ../04_asset_dids.md \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/concepts/05_credentials/_category_.json b/versioned_docs/version-1.0.0/concepts/05_credentials/_category_.json new file mode 100644 index 000000000..ff74ea971 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/05_credentials/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Credentials", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/concepts/06_distributed_trust.md b/versioned_docs/version-1.0.0/concepts/06_distributed_trust.md new file mode 100644 index 000000000..261a38b77 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/06_distributed_trust.md @@ -0,0 +1,66 @@ +--- +id: distributed_trust +title: Distributed Trust +--- + +import ThemedImage from '@theme/ThemedImage'; + +Sometimes, Attesters are individuals that attest to the validity of claims made by Claimers. +However, usually multiple Attesters group together to build up trust in a brand. +In this way, Verifiers no longer need to trust each and every Attester individually. +They can put trust in the brand as a whole, which in return ensures that all Attesters working for this brand are credible. +Such a brand can be organized in many different ways. +The KILT protocol provides mechanisms to form such brands on the blockchain. + +There are two ways for Attesters to create groups and build an organization. +The first is by creating a Delegation Hierarchy, which provides a basic and traditional hierarchical structure. +The second option is a Virtual Credential Organization (VCO), which isn't yet implemented in KILT. +VCOs will be more flexible and able to support more decentralized use cases than Delegation Hierarchies. + +## Delegation hierarchies + +Delegation Hierarchies organize their members in a traditional hierarchical structure, and are modeled as a [Tree data structure](https://en.wikipedia.org/wiki/Tree_(data_structure)), also shown in the graph below. +Everyone can use KILT to create a new hierarchy and immediately become the only member of the newly created organization. +Not only is the creator the only member of the organization, they're also the root of the hierarchy. +This means that the creator has full control over the whole hierarchy. + +
+ + + +
+ +Following the laws of Tree data structures, when the hierarchy root adds new members to the hierarchy, the new members become direct "children" of the root. +Similarly, when someone other than root adds new members, it becomes the parent of the new children. + +The graph above provides an example Delegation Hierarchy containing five Attesters. +**Attester 1** is the root (i.e., the creator) of the Delegation Hierarchy. +At some point, Attester 1 has added two more Attesters, Attester 2 and Attester 3. +**Attester 2** was given the right to both further delegate to other entities and to issue credentials on behalf of the organization. +**Attester 3**, on the other hand, was only given the right to add more Attesters to the Delegation Hierarchy, so they can't issue any credentials. +This is useful in cases where someone should only have powers over the members, but isn't authorized to do any work themselves. +For example, in companies this could be someone who manages a team of Attesters. +**Attesters 4** and **Attester 5** were added by Attester 3 and were only given attestation permissions, meaning that they can issue new credentials, but can't delegate any work to other Attesters. +In the company example, these would be employees that attest the work but have no authority to hire new staff. + +### Revocation + +Delegation hierarchies limit who can change or remove permissions. + +For delegations, only the parents of a given Attester can change or remove the Attester's delegation itself or any of its children. +E.g., Attester 2 can't change the delegation information for Attester 4, but Attester 1 and Attester 3 can both remove Attester 4 from the organization, or give them permission to also hire new people, which it can't do right now. + +Credential revocation works similarly, with the difference that any parent can revoke a credential (as with delegations), or by the original Attester. +E.g., Attester 2 can't revoke credentials issued by Attester 1, 3, 4 and 5, while Attester 1 can revoke credentials issued by any Attester since Attester 1 is, directly or indirectly, the parent of every other node. + +## Storing delegation node + +Adding a new node in the delegation hierarchies requires providing a constant deposit, which is currently 1 KILT. +The deposit serves as a security measure to ensure the integrity of the blockchain and incentivize users to manage their nodes responsibly. By requiring a deposit, it discourages spamming or unnecessary creation of nodes. +When a user deletes their node, they can reclaim the deposit. \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/concepts/07_dip/01_overview.md b/versioned_docs/version-1.0.0/concepts/07_dip/01_overview.md new file mode 100644 index 000000000..06583d003 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/07_dip/01_overview.md @@ -0,0 +1,71 @@ +--- +id: what-is-dip +title: Overview +--- + +:::version-label[DIP] + +::: + +The Decentralized Identity Provider (DIP) enables a cross-chain decentralized identity system that mirrors the functionality of OpenID. + +DIP has three key roles: the identity **provider**, the **consumer**, and the **user**. + +- The identity **provider** is any blockchain with an identity system that makes it available for other chains, e.g., KILT Protocol, Litentry, etc. +- The **consumer** is any blockchain that has chosen to delegate identity management to the provider, thus relieving it of needing to maintain its identity infrastructure. +- The **user** is an entity with an identity on the provider chain and wants to use it on other chains without setting up a new identity on each. A Dapp developer can use the DIP SDK to make this process easier for the user and add other DIP-related features to their app. + +This means that parachains requiring an identity solution donโ€™t need to build their own infrastructure. +Instead, they can leverage the infrastructure DIP provides. +DIP is open-source, and you can integrate it with existing Polkadot-compatible runtimes with minimal changes and without affecting the fee model of the consumer system. + +## Adding support to a parachain + +There are several steps to add DIP support to a Substrate-based parachain, depending on the chain's role. + +### Provider chain + +1. Define the format of identity proofs and how verification works with the consumer chains. +2. Add the DIP provider pallet as a dependency to the chain runtime. +3. Configure the DIP provider pallet using the required `Config` trait. + +:::info + +Find more details in the [Provider pallet](./02_provider.md) section. + +::: + +### Consumer chain + +1. Discover and retrieve the format of your identity proofs and how verification works with your identity provider +2. Add the DIP consumer pallet as a dependency to the chain runtime +3. Configure the DIP consumer pallet using the required `Config` trait. +4. Deploy it on chain, along with any additional pallets the identity provider requires. + +:::info + +Find more details in the [Consumer pallet](./03_consumer.md) section. + +::: + +## User accounts on KILT + +For an account to take advantage of DIP with KILT it needs a decentralized identity (DID) and to create a transaction on the provider chain to generate a cross-chain identity commitment. + +For an account to be able to do this, a Dapp developer needs to build the functionality into their app for a user using the DIP SDK. + +:::info + +Find more details in the [user account](./04_user_account_kilt.md) section. + +::: + +## Dapp developer + +The DIP SDK is a JavaScript library that makes it easier for Dapp developers to integrate DIP into their apps. The SDK includes methods for interacting with runtimes, generating proofs, and more. + +:::info + +Find more details in the [Dapp developer](./05_dapp_developer.md) section. + +::: \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/concepts/07_dip/02_provider.md b/versioned_docs/version-1.0.0/concepts/07_dip/02_provider.md new file mode 100644 index 000000000..1803e52dd --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/07_dip/02_provider.md @@ -0,0 +1,50 @@ +# Provider pallet + +This pallet is a core component of the Decentralized Identity Provider protocol. +It enables a Substrate-based chain (provider) to bridge the identities of its users to other connected chains (consumers) trustlessly. +A consumer chain is *connected* to a provider if there is a way for the consumer chain to verify state proofs about parts of the state of the provider chain. + +The pallet is agnostic over the chain-specific definition of *identity*, and delegates the definition of it to the provider chain's runtime. + +What the pallet stores are *identity commitments*, which are opaque byte blobs put in the pallet storage and on which the cross-chain identity bridging protocol can be built. +As for identities, the definition of an identity commitment must be provided by the runtime and is therefore provider-specific. +Naturally, this definition must be made available to consumers willing to integrate the identities living on the provider chain. + +Because providers and consumers evolve at different speeds, identity commitments are versioned. +This allows the provider chain to upgrade to a newer commitment scheme, while still giving its users the possibility to use the old version, if the chains on which they want to use their identity does not yet support the new scheme. + +Identity commitments can be replaced (e.g., if something in the identity info changes), or removed altogether by the identity subject. +After removal, the identity becomes unusable cross-chain, although it will still continue to exist on the provider chain and will be usable for local operations. + +## The `Config` trait + +Being chain-agnostic, most of the runtime configurations must be passed to the pallet's `Config` trait. Specifically: + +* `type CommitOriginCheck: EnsureOrigin`: The check ensuring a given runtime origin is allowed to generate and remove identity commitments. +* `type CommitOrigin: SubmitterInfo`: The resulting origin if `CommitOriginCheck` returns without errors. The origin is not required to be an `AccountId`, but must include information about the `AccountId` of the tx submitter. +* `type Identifier: Parameter + MaxEncodedLen`: The type of an identifier used to retrieve identity information about a subject. +* `type IdentityCommitmentGenerator: IdentityCommitmentGenerator`: The type responsible for generating identity commitments, given the identity information associated to a given `Identifier`. +* `type IdentityProvider: IdentityProvider`: The type responsible for retrieving the information associated to a subject given their identifier. The information can potentially be retrieved from any source, using a combination of on-chain and off-chain solutions. +* `type IdentityProvider: IdentityProvider`: Customizable external logic to handle events in which a new identity commitment is generated or removed. +* `type RuntimeEvent: From> + IsType<::RuntimeEvent>`: The aggregate `Event` type. + +## Storage + +The pallet contains a single storage element, the `IdentityCommitments` double map. +Its first key is the `Identifier` of subjects, while the second key is the commitment version. +The values are identity commitments. + +As mentioned above, a double map allows the same subject to have one commitment for each version supported by the provider, without forcing consumers to upgrade to a new version to support the latest commitment scheme. + +## Events + +The pallet generates two events: a `VersionedIdentityCommitted` and a `VersionedIdentityDeleted`. + +The `VersionedIdentityCommited` is called whenever a new commitment is stored, and contains information about the `Identifier` of the subject, the value of the commitment, and the commitment version. + +Similarly, the `VersionedIdentityDeleted`, is called whenever a commitment is deleted, and contains information about the `Identifier` of the subject and the version of the commitment deleted. + +## Calls (bullet numbers represent each call's encoded index) + +0. `pub fn commit_identity(origin: OriginFor, identifier: T::Identifier, version: Option ) -> DispatchResult`: Generate a new versioned commitment for the subject identified by the provided `Identifier`. If an old commitment for the same version is present, it is overridden. Hooks are called before the new commitment is stored, and optionally before the old one is replaced. +1. `pub fn delete_identity_commitment(origin: OriginFor, identifier: T::Identifier, version: Option) -> DispatchResult`: Delete an identity commitment of a specific version for a specific `Identifier`. If a commitment of the provided version does not exist for the given `Identifier`, an error is returned. Hooks are called after the commitment has been removed. diff --git a/versioned_docs/version-1.0.0/concepts/07_dip/03_consumer.md b/versioned_docs/version-1.0.0/concepts/07_dip/03_consumer.md new file mode 100644 index 000000000..e19a811d0 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/07_dip/03_consumer.md @@ -0,0 +1,60 @@ +# Decentralized Identity Provider (DIP) provider consumer pallet + +This pallet is a core component of the Decentralized Identity Provider protocol. +It enables entities with an identity on a connected Substrate-based chain (provider) to use those identities on the chain this pallet is deployed (consumers) without requiring those entities to set up a new identity locally. +A consumer chain is *connected* to a provider if there is a way for the consumer chain to verify state proofs about parts of the state of the provider chain. + +A cross-chain transaction with DIP assumes the entity submitting the transaction has already generated a cross-chain identity commitment on the provider chain, by interacting with the DIP provider pallet on the provider chain. +With a generated identity commitment, a cross-chain transaction flow for a generic entity `A` works as follows: + +1. `A` generates a state proof proving the state of the identity commitment on the provider chain. +2. `A` generates any additional information required for an identity proof to be successfully verified by the consumer runtime. +3. `A`, using their account `AccC` on the consumer chain, calls the `dispatch_as` extrinsic by providing its identifier on the provider chain, the generated proof, and the `Call` to be dispatched on the consumer chain. + 1. This pallet verifies if the proof is correct, if not it returns an error. + 2. This pallet dispatches the provided `Call` with a new origin created by this pallet, returning any errors the dispatch action returns. The origin contains the information revealed in the proof, the identifier of the acting subject and the account `AccC` dispatching the transaction. + +The pallet is agnostic over the chain-specific definition of *identity proof verifier* and *identifier*, although, when deployed, they must be configured to respect the definition of identity and identity commitment established by the provider this pallet is linked to. + +For instance, if the provider establishes that an identity commitment is a Merkle root of a set of public keys, an identity proof for the consumer will most likely be a Merkle proof revealing a subset of those keys. +Similarly, if the provider defines an identity commitment as some ZK-commitment, the respective identity proof on the consumer chain will be a ZK-proof verifying the validity of the commitment and therefore of the revealed information. + +For identifiers, if the provider establishes that an identifier is a public key, the same definition must be used in the consumer pallet. +Other definitions for an identifier, such as a simple integer or a [Decentralized Identifier (DID)](https://www.w3.org/TR/did-core/), must also be configured in the same way. + +The pallet allows the consumer runtime to define some `LocalIdentityInfo` associated with each identifier, which the pallet's proof verifier can access and optionally modify upon proof verification. +Any changes made to the `LocalIdentityInfo` will be persisted if the identity proof is verified correctly and the extrinsic executed successfully. + +If the consumer does not need to store anything in addition to the information an identity proof conveys, they can use an empty tuple `()` for the local identity info. +Another example could be the use of signatures, which requires a nonce to avoid replay protections. +In this case, a numeric type such as a `u64` or a `u128` could be used, and increased by the proof verifier when validating each new cross-chain transaction proof. + +## The `Config` trait + +Being chain-agnostic, most of the runtime configurations must be passed to the pallet's `Config` trait. +Nevertheless, most of the types provided must reflect the definition of identity and identity commitment that the identity provider chain has established. +The trait has the following components: + +* `type DipCallOriginFilter: Contains>`: A preliminary filter that checks whether a provided `Call` accepts a DIP origin or not. If a call such as a system call does not accept a DIP origin, there is no need to verify the identity proof, hence the execution can bail out early. This does not guarantee that the dispatch call will succeed, but rather than it will mostly not fail with a `BadOrigin` error. +* `type DispatchOriginCheck: EnsureOrigin<::RuntimeOrigin, Success = Self::AccountId>`: The origin check on the `dispatch_as` extrinsic to verify that the caller is authorized to call the extrinsic. If successful, the check must return a `AccountId` as defined by the consumer runtime. +* `type Identifier: Parameter + MaxEncodedLen`: The type of a subject identifier. This must match the definition of `Identifier` the identity provider has defined in their deployment of the provider pallet. +* `type LocalIdentityInfo: FullCodec + TypeInfo + MaxEncodedLen`: Any additional information that must be available only to the provider runtime that is required to provide additional context when verifying a cross-chain identity proof. +* `type ProofVerifier: IdentityProofVerifier`: The core component of this pallet. It takes care of validating an identity proof and optionally update any `LocalIdentityInfo`. It also defines, via its associated type, the structure of the identity proof that must be passed to the `dispatch_as` extrinsic. Although not directly, the proof structure depends on the information that goes into the identity commitment on the provider chain, as that defines what information can be revealed as part of the commitment proof. Additional info to satisfy requirements according to the `LocalIdentityInfo` (e.g., a signature) must also be provided in the proof. +* `type RuntimeCall: Parameter + Dispatchable::RuntimeOrigin>`: The aggregated `Call` type. +* `type RuntimeOrigin: From> + From<::RuntimeOrigin>`: The aggregated `Origin` type, which must include the origin exposed by this pallet. + +## Storage + +The pallet contains a single storage element, the `IdentityEntries` map. +It maps from a subject `Identifier` to an instance of `LocalIdentityInfo`. + +This information is updated by the proof verifier whenever a new cross-chain transaction and its proof is submitted. + +## Origin + +Because the pallet allows other `Call`s to be dispatched after an identity proof has been verified, it also exposes a `Origin` that can be used for those calls that require indeed a call to be DIP-authorized. + +The origin is created after the identity proof has been successfully verified by the proof verifier, and it includes the identifier of the subject, the address of the tx submitter, and the result returned by the proof verifier upon successful verification. + +## Calls (bullet numbers represent each call's encoded index) + +0. `pub fn dispatch_as(origin: OriginFor, identifier: T::Identifier, proof: IdentityProofOf, call: Box>) -> DispatchResult`: Try to dispatch a new local call only if it passes all the DIP requirements. Specifically, the call will be dispatched if it passes the preliminary `DipCallOriginFilter` and if the proof verifier returns an `Ok(verification_result)` value. The value is then added to the `DipOrigin` and passed down as the origin for the specified `Call`. If the whole execution terminates successfully, any changes applied to the `LocalIdentityInfo` by the proof verifier are persisted to the pallet storage. diff --git a/versioned_docs/version-1.0.0/concepts/07_dip/04_user_account_kilt.md b/versioned_docs/version-1.0.0/concepts/07_dip/04_user_account_kilt.md new file mode 100644 index 000000000..97c5fb035 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/07_dip/04_user_account_kilt.md @@ -0,0 +1,64 @@ +--- +id: dip-accounts-kilt +title: Enabling DIP for user accounts on the KILT blockchain +--- + +:::version-label[DIP] + +::: + +For an account to take advantage of DIP it needs a decentralized identity (DID) and to create a transaction on the provider chain to generate a cross-chain identity commitment. + +For an account to be able to do this, a Dapp developer needs to build the functionality into their app for a user using the DIP SDK. + +The implementation of this transaction is per-chain and this documentation provides an example of how to do this on the KILT blockchain. + +## Using the KILT DIP SDK + +Add the SDK as a dependency: + +```bash npm2yarn +npm install @kiltprotocol/dip-sdk +``` + +Include the following imports in your code: + +```typescript +import { generateDipAuthorizedTxForSibling } from '@kiltprotocol/dip-sdk' +``` + +The `generateDipAuthorizedTxForSibling` method returns a submittable extrinsic promise for the provided call which includes a complete DIP proof according to the parameters provided. You can then use this on a consumer chain as the `submitterAddress` parameter of which the provider chain is a sibling. + +:::info What is a valid call + +A valid call is a HEX-encoded call of the parent relaychain with the right key re-generated from the provided seedling information, i.e., either with the provided mnemonic or with the provided combination of base mnemonic and derivation path. + +You can generate valid HEX-encoded calls at [PolkadotJS Apps](https://polkadot.js.org/apps/) from the `Developer > Extrinsics` menu. + +Copy the value from `encoded call data` and pass it as a parameter. + +::: + +The command requires the following variables: + +- `call` The `Call` on the consumer chain that requires a DIP origin. +- `consumerApi` The [`ApiPromise`](https://polkadot.js.org/docs/api/examples/promise/) instance for the consumer chain. +- `didUri` The DID URI of the DIP subject performing the cross-chain operation. +- `keyIds` The verification method IDs of the DID are revealed in the cross-chain operation. +- `proofVersion` The version of the DIP proof to generate. +- `providerApi` The [`ApiPromise`](https://polkadot.js.org/docs/api/examples/promise/) instance for the provider chain. +- `relayApi` The [`ApiPromise`](https://polkadot.js.org/docs/api/examples/promise/) instance for the parent relay chain. +- `signer` The signing callback to sign the cross-chain transaction. +- `submitterAddress` The address of the transaction submitter on the consumer chain. +- `keyRelationship` The `VerificationKeyRelationship` required for the DIP operation authorized on the relay chain. + +And the following optional environment variables: + +- `blockHeight` The block number on the consumer chain to use for the DID signature. Uses the latest best block number, if not provided. +- `genesisHash` The genesis hash of the consumer chain to use for the DID signature. Retrieved at runtime from the consumer chain If not provided. +- `providerBlockHeight` The block number of the provider to use for the generation of the DIP proof. Uses the latest finalized block number if not provided. +- `accountIdRuntimeType` The runtime type definition for an `AccountId` on the consumer chain. Uses the `AccountId` type if not provided. +- `blockNumberRuntimeType` The runtime type definition for a `BlockNumber` on the consumer chain. Uses the `u64` type if not provided. +- `identityDetailsRuntimeType` The runtime type definition for the `IdentityDetails` on the consumer chain. Uses the `Option` type, representing a simple nonce if not provided. +- `includeWeb3Name` Flag indicating whether the generated DIP proof should include the web3name of the DID subject. If not provided, the web3name is not revealed. +- `linkedAccounts` The list of linked accounts to revealed in the generated DIP proof. No account is revealed if not provided. \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/concepts/07_dip/05_dapp_developer.md b/versioned_docs/version-1.0.0/concepts/07_dip/05_dapp_developer.md new file mode 100644 index 000000000..0083e33f7 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/07_dip/05_dapp_developer.md @@ -0,0 +1,152 @@ +--- +id: dapp-developer +title: Dapp developer +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +:::version-label[DIP] + +::: + +The Decentralized Identity Provider (DIP) SDK helps Dapp developers build DIP functionality into their apps. + +## Installation + +Add the SDK as a dependency: + +```bash npm2yarn +npm install @kiltprotocol/dip-sdk +``` + +Import the SDK into your code: + +```typescript +import { * } from '@kiltprotocol/dip-sdk' +``` + +## Example application + +This example application walks through the code you can find in the tests for the DIP SDK. + +### 1. Generate a base proof + +Start by generating the base proof for the DIP using the `[generateDipSiblingBaseProof](https://kiltprotocol.github.io/dip-sdk/functions/generateDipSiblingBaseProof.html)` method and passing the desired configuration: + +```typescript +const baseDipProof = await DipSdk.generateDipSiblingBaseProof(config) +``` + +:::info What's a base proof? +A base proof is a cross-chain state proof, revealing the parts of a DID Document stored on the KILT blockchain. +::: + +The configuration for the base proof takes the following parameters: + +- `didUri`: (Required) The DID URI of the DIP subject performing the cross-chain operation. +For example, `did:kilt:4q4QzFTs9hKh4QizLB3B7zuGYCG3QPamiBFEgwM6gTM7gK3g` +- `keyIds`: (Required) An array of verification method IDs of the DID revealed in the cross-chain operation. +- `proofVersion`: (Required) The version of the DIP proof to generate. +Currently only supports version 1. +- `blockNumber`: The block number of the relay chain to use for the generation of the DIP proof. +If not provided, uses the last finalized block. +- `linkedAccounts`: An array of [account addresses linked to the DID](../../develop/01_sdk/02_cookbook/03_account_linking/01_link.md#linking-an-account-to-a-did) to reveal in the generated proof. +- `web3Name`: Whether to reveal [the web3name of the DID subject](../../develop/01_sdk/02_cookbook/02_web3names/01_claim.md) in the generated proof. + +In the example code, the configuration also has extra parameters for the time-bound DID signature extension [mentioned below](#creating-extensions-for-specific-proofs). + +The configuration also has details of the provider, which in this case uses a value populated from an environment variable: + +```typescript +const providerAddress = `ws://127.0.0.1:${process.env['PROVIDER_ALICE_RPC']}` +``` + +### 2. Generate a submittable extrinsic + +The method returns the DID base proof. +You have to call a second method, the `[generateDipSubmittableExtrinsic](https://kiltprotocol.github.io/dip-sdk/functions/generateDipSubmittableExtrinsic.html)` method to generate a submittable extrinsic that includes the generated proof. + +You need to pass the following parameters: + +- The API of the consumer chain. +- The base proof. +- The call to the consumer chain. +- The DID URI. + +:::info Submittable extrinsics + +A transaction that originates from an external account and affects the state of the blockchain. +An extrinisc executes actions on the network, such as transferring funds, making governance decisions, using functionality of the parachain, or interacting with smart contracts. + +::: + +```typescript +const dipSubmittable = DipSdk.generateDipSubmittableExtrinsic({ + api: consumerApi, + baseDipProof, + call, + didUri: did.uri, +}) +``` + +The method returns the different components of the proof, [which you can see in the example code](https://github.com/KILTprotocol/dip-sdk/blob/9ad141b3757e076744ab8b2d29bcf10bbeaddd9f/tests/dip-provider-template-dip-consumer-template/develop.test.ts#L219): + +- The provider head proof, which is proof of the provider parachain header on the relay chain. +- The commitment proof, which proves the DIP commitment for the subject of the action, which is the DID URI. +- The DID proof, which reveals parts of the DID document as specified by key IDs, proof version, and whether to include the web3name and any of its linked accounts. + +Behind the scenes, the method uses the `dispatchAs` method ([and corresponding chain method](https://github.com/KILTprotocol/kilt-node/blob/4ddb8a0ef6258873458f19d3ee9dcb6d7c24e645/pallets/did/src/lib.rs#L1152)) to pass the extrinsic following the consumer's type registry. +You can now sign and submit to the consumer chain. + +```typescript +await signAndSubmitTx(consumerApi, dipSubmittable, submitterKeypair) +``` + +### 3. Linking accounts (optional) + +Linked accounts let you specify which accounts you want to prove that you control when you make the cross-chain proof. +As part of the proof provided, you can also include other values, such as the web3name. + +For all the accounts you want to link, use the `associateAccountToChainArgs` method, [as detailed in this guide](../../develop/01_sdk/02_cookbook/03_account_linking/01_link.md#linking-an-account-to-a-did). + +You can then batch all the linked account transactions and authorize them using the `authorizeTx` method. + +```typescript +const signedLinkedAccounts = await Kilt.Did.authorizeTx( + newFullDidUri, + providerApi.tx.utility.batchAll(linkAccountTxs), + signCallback, + newSubmitterKeypair.address as KiltAddress, + { txCounter: new BN(4) } +) +``` + +## Creating extensions for specific proofs + +If you need a specific proof type for a consumer chain, then a chain developer needs to submit a PR to the SDK repository in the `src > dipProof > extensions` folder. +The extension included with the SDK adds support for a time-bound DID signature, i.e., a signature which is valid only until a certain block number on the consumer chain. + +The extension can take any form, but must return [a SCALE encoded](https://docs.substrate.io/reference/scale-codec/) object. +There's an example of how the extension does this [on GitHub](https://github.com/KILTprotocol/dip-sdk/blob/9ad141b3757e076744ab8b2d29bcf10bbeaddd9f/src/dipProof/extensions/timeBoundDidSignature.ts#L113). + +To add the extension, use the `generateDipSubmittableExtrinsic` method and pass the additional proof elements along with consumer chain specific components. + +```typescript +const dipSubmittable = DipSdk.generateDipSubmittableExtrinsic({ + additionalProofElements: + DipSdk.dipProof.extensions.timeBoundDidSignature.toChain( + crossChainDidSignature + ), + api: consumerApi, + baseDipProof, + call, + didUri: did.uri, +}) +``` + +:::info + +Read the auto-generated [API documentation](https://kiltprotocol.github.io/dip-sdk) for more details on the methods the SDK provides. + +::: diff --git a/versioned_docs/version-1.0.0/concepts/07_dip/_category_.json b/versioned_docs/version-1.0.0/concepts/07_dip/_category_.json new file mode 100644 index 000000000..86efa9440 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/07_dip/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Decentralized Identity Protocol (DIP)", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/concepts/08_messaging.md b/versioned_docs/version-1.0.0/concepts/08_messaging.md new file mode 100644 index 000000000..1070ed633 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/08_messaging.md @@ -0,0 +1,44 @@ +--- +id: messaging +title: KILT Messaging +--- +import CodeBlock from '@theme/CodeBlock'; + + +import encryptedMessage from '@site/scripts/out/encrypted-message.json.raw!=!raw-loader!@site/scripts/out/encrypted-message.json'; + +Distributed trust on the internet only works if credentials and other information can be exchanged securely, and communicating parties can be confident that bad actors aren't fooling or eavesdropping on them. +KILT provides a **transport-agnostic messaging layer** that helps with securely exchanging data between the respective owners of two DIDs. + +This messaging layer provides **authenticated end-to-end encryption**, the gold standard in secure communication, in a way that hides the security of the technologies used for transporting the message over the internet โ€“ย be it sending the encrypted messages via email, or posting them to and fetching them from a centralized or decentralized messaging service. + +:::info +The messaging layer enables secure communication between two digital identities, DIDs. +A necessary condition for secure communication with a given person or organization is to make sure that the DID on the other side of the communication channel is really controlled by the other party to avoid attacks such as *Man in the Middle* (MitM) attacks. + + + +::: + +To be able to communicate, the two DIDs need to expose **key agreement public keys** for that purpose (a.k.a., an **encryption key**). +To send a message to the other party, a DID owner (called **Alice**) looks up her peer's (called **Bob**) encryption public key, which can be part of either a [full DID](./02_did.md#full-dids) or a [light DID](./02_did.md#light-dids). +Using this key in combination with her secret encryption key, **Alice** can now encrypt the message such that only she and **Bob** can decrypt it. A **nonce** introduces randomness and uniqueness into encryption operations, making it highly challenging for an attacker to predict or replicate the encryption process. +Each message has a different **nonce**, resulting in the creation of a unique encryption context for every message. + +**Bob** can decrypt this message after looking up **Alice's** encryption key. +An additional _message authentication code_ (MAC) added during encryption and verified on decryption protects against manipulation of the encrypted data. +As long as both parties keep their secret keys well protected, the combination of these measures allows **Bob** to be confident that if the message decrypts successfully, only **Alice** could have encrypted it and that malicious third party hasn't read or tampered with it while in transport. + +While encrypted, the message travels in a compact and privacy-preserving envelope format that only exposes data that the recipient needs to be able to decrypt. + + + {encryptedMessage} + + +The encrypted message not only references the DIDs of sender and recipient, it also references the unique identifier of the keys that used in encryption. +Therefore, this scheme still works if a DID should expose multiple encryption keys from which a message sender may choose. + +:::caution +While no one can read or change what's inside an encrypted message even if they intercept it while traveling on the network, a sophisticated attacker may try to guess what's inside and trick either side of the channel by resubmitting a copy of that message later. +For a detailed developer-oriented guide about how to protect against *replay attacks*, read the [Replay Protection Cookbook section](../develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md). +::: diff --git a/versioned_docs/version-1.0.0/concepts/09_advanced_concepts/01_terms_and_quote.md b/versioned_docs/version-1.0.0/concepts/09_advanced_concepts/01_terms_and_quote.md new file mode 100644 index 000000000..c79fcbb63 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/09_advanced_concepts/01_terms_and_quote.md @@ -0,0 +1,87 @@ +--- +id: terms-and-quotes +title: Terms and Quotes +--- + +During the attestation flow, it can happen that either the Claimer requests or the Attester sends the terms of the attestation, i.e., the requirements set by the both parties (the Claimer and the Attester) for the conditions of the attestation. + +These terms are defined and agreed upon before the credential is issued. +This part of the process requires interaction and communication between both parties. +This communication can be done independently, e.g., in person, via messaging, on social media etc., or via the KILT Software Development Kit (SDK). + +## Defining Terms + +The `Terms` object consists of following items: + +- **Claim**: A partial claim with information the Attester already has about the Claimer. + - This helps the Claimer to pre-fill their claims with information only known to the Attester. + - The partial claim has to at least contain the CType hash the attestation will be based on. +- **CTypes**: An optional list of full CTypes, in case the Claimer does not know the correct CType for the credential, yet. +- **Legitimations**: A legitimation is a credential, issued to the Attester, showing that the Attester has the authority or legitimacy to attest the claim requested. + - This is a way of establishing trust between the participants. +- **Delegation Id**: An Attester may be part of a top-down trust authority that has given them the right to attest in the name of an institution, or similar, as explained in the [Distributed Trust section](../06_distributed_trust.md). If the Attester has attestation rights, delegated from another entity, this should be stated clearly at this point. +- **Quote**: As shown in the [section below](#defining-a-quote). + +Only the CType hash in the partial claim is required, everything else is optional. + +## Sending Terms + +Both "request terms" and "submit terms" are part of the messaging system: the message is sent as "request terms" and received as "submit terms". + +The interaction is as follows: + +- The Claimer creates a partial `Claim` (optionally) and sends a message to the Attester, requesting the `Terms`. +- An Attester creates a `Terms` object and sends it, as part of a "submit terms" message, back to the Claimer. +- The Claimer receives the message, checks the `Terms` and, if all is in order, agrees to them. + + +## Defining a Quote + +A `Quote` object consists of costs, a time frame for delivering the attestation, and the terms and conditions of the work to be performed. +It may be sent to the Claimer by the Attester as part of the terms. +In cases where multiple Attesters provide the same attestation (for example, a car inspection) the Claimer may request a Quote from several Attesters to choose the Attester with the best conditions. + +To come to an agreement on the Quote, the participants may message back and forth, signing the object. +If the Attester wishes to add a Quote to their Terms, the Attester signs the `Quote` object before sending it as part of the "submit terms" message to the Claimer. +After the Claimer has received the signed Quote and accepts it, the Claimer counter-signs it and attaches the credential hash for linking the Quote to the credential that it refers to. +After the final exchange, the Attester checks all the information and issues the credential. + +```mermaid +classDiagram + class Quote { + String attesterDid + String cTypeHash + Cost cost + String currency + String timeframe + String termsAndConditions + } + + class Cost { + Number gross + Number net + Object tax + } + + Quote *-- Cost + + class Signature { + String keyId + String signature + } + + class QuoteAttesterSigned { + Signature attesterSignature + } + + QuoteAttesterSigned *-- Signature + QuoteAttesterSigned --|> Quote + + class QuoteAgreement { + String rootHash + Signature claimerSignature + } + + QuoteAgreement *-- Signature + QuoteAgreement --|> QuoteAttesterSigned +``` diff --git a/versioned_docs/version-1.0.0/concepts/09_advanced_concepts/02_nested_ctypes.md b/versioned_docs/version-1.0.0/concepts/09_advanced_concepts/02_nested_ctypes.md new file mode 100644 index 000000000..4b96cbced --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/09_advanced_concepts/02_nested_ctypes.md @@ -0,0 +1,16 @@ +--- +id: nested-ctypes +title: Nested CTypes +--- + +A Nested CType is a hierarchical composite schema that includes other CTypes as substructures by referencing them. +For example, a company could use a Nested CType that includes the required credentials, qualifications, health and safety certificates, etc. of its current employees. +When verifying a Nested CType, the sub-CTypes need to be available. + +## Referencing + +JSON-schema provides a referencing keyword `$ref` that can be used as a pointer from other JSON schemas. +This allows CTypes to either reference fields in other CTypes or nest entire CTypes within one another, providing flexibility for several different use cases. +A claim from a Nested CType requires the given CType, a list of comprised schemas, the claim content and the address of the owner. + +This facility requires all JSON objects to build the schema and allows the reuse of previous schemas, reducing the need for copy-and-paste. diff --git a/versioned_docs/version-1.0.0/concepts/09_advanced_concepts/_category_.json b/versioned_docs/version-1.0.0/concepts/09_advanced_concepts/_category_.json new file mode 100644 index 000000000..2a674ea41 --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/09_advanced_concepts/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Advanced Concepts", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/concepts/10_glossary.md b/versioned_docs/version-1.0.0/concepts/10_glossary.md new file mode 100644 index 000000000..b607253bc --- /dev/null +++ b/versioned_docs/version-1.0.0/concepts/10_glossary.md @@ -0,0 +1,102 @@ +--- +id: glossary +title: KILT Glossary +--- + +Here is a glossary of terms related to the KILT Protocol: + +## W3C: Self-Sovereign Identity (SSI) + +**Decentralized Identifier (DID)** โ€“ a unique digital identifier for entities (people, machines, services, and anything that identities can be built on) which can be anchored to a blockchain to provide the core of a verifiable digital identity. +For example, **did:kilt:4sxSYXakw1ZXBymzT9t3Yw91mUaqKST5bFUEjGEpvkTuckar**. +In KILT, identity is built by adding credentials to the DID. + +**DID Authentication** โ€“ the process of proving that an entity has control over a DID, typically by using a digital signature or other cryptographic mechanism. + +**DID Communication** โ€“ the use of DIDs to enable secure and decentralized communication between two or more parties, without the need for a central intermediary. + +**DID Controller** โ€“ an entity that has control over a DID. +This may be the entity that generated the DID or an entity that has been authorized by the DID owner to manage the DID. + +**DID Document** โ€“ a JSON-LD document that contains information about a DID, including public keys, services, and other metadata. + +**DID Method** โ€“ a set of rules and specifications for how a DID is created, resolved, and managed on a particular network or platform. + +**DID Resolver** โ€“ a software component that can resolve a DID to a DID Document, which contains information about the DID, such as public keys, services, and other metadata. + +**Self-Sovereign Identity (SSI)** - a decentralized digital identity management system that enables individuals to own and control their identity information using secure digital technologies, such as blockchain. +SSI eliminates the need for intermediaries and provides individuals with greater privacy, security, and control over their personal data. +It is an emerging concept that has the potential to transform how identity is managed and verified across various sectors. + +**Verifiable Credentials (VCs)** - digital credentials that can be used to prove claims about a person, organization, or thing, and are designed to be portable, interoperable, and privacy-preserving. +Verifiable credentials are often associated with DIDs and can be stored and managed using a DID-based identity system. + +## KILT Protocol Specific Terms + +**Attestation** -the act of formally confirming and certifying the validity of the data within a claim, typically performed by a trusted Attester. + +**Attester** - a trusted entity or organization that attests claims and issues credentials on the KILT Protocol. +The Attester confirms the truth of the claim requested based on the information presented by the Claimer. + +**Claimer** - an individual or entity that asserts a claim or statement about their identity or qualifications. +The Claimer can use credentials to provide evidence of their claims, which can be verified by third-party entities or systems. + +**Claim Type (CType)** - a specific type of claim that can be made about an individual, such as their education, work experience, or identity information. +Each claim type has a defined set of attributes that must be provided to support the claims data type and structure. +It can be used to generate verifiable credentials that can be shared with others. [See the CTypes concept page for more details](https://docs.kilt.io/docs/concepts/credentials/ctypes) + +**Credential** - a verifiable digital representation of a claim made by a Claimer, which has been attested to by a trusted entity, such as an Attester or Issuer. +It consists of a set of attributes that describe the claim and the proof of its validity, and can be shared with third parties to provide verifiable proof of the claim. + +**KILT Digital Identity** - a self-sovereign identity that is owned and controlled by the individual or entity it represents. +It consists of verifiable credentials that are issued by trusted entities, such as Attesters, and can be used to prove claims about the individual or entity's identity, qualifications, or other attributes. + +**KILT Coin** - the native token of the KILT blockchain used for paying for attestations and DIDs. It can also be used for governance, staking, transaction fees and as a means of exchange on the network. + +**KILT Protocol** - an open-source blockchain protocol for issuing self-sovereign, and verifiable credentials for Web3, the next generation of the Internet. +KILTโ€™s mission is to return control over personal data to its owner, restoring privacy to the individual. + +### Request for Attestation + + +**Trust Anchors** - entities that are trusted to issue or verify claims on the KILT network, such as governments, educational institutions, or professional organizations. + +**Trust Market** - a market that operates on trust and reputation in addition to financial incentives, where buyers and sellers exchange goods or services based on established reputation through digital platforms. +While trust markets offer benefits such as reducing the need for intermediaries, they also face challenges that need to be addressed to maintain trust and fairness in transactions. + +**Transport-Agnostic Messaging Layer** - a messaging system that is not dependent on any particular communication protocol or technology. +It allows different systems or applications to communicate with each other regardless of the underlying transport protocol used, providing a standardized way of exchanging messages across different platforms and technologies. + +**Verifier** - a person, organization, or system that checks the validity and authenticity of an individual's credentials or qualifications. +Verifiers play a critical role in building trust and ensuring that credentials are accurate and reliable. + +## Ecosystem Terms + +**Blockchain Technology** - a type of distributed ledger technology that allows multiple parties to have a synchronized, transparent, and immutable record of transactions. +It uses cryptographic techniques to secure and verify transactions, and it does not require a central authority or intermediaries. + +**Decentralized Network** - a network of computers or nodes that operate without a central authority or control. +In a decentralized network, each node has equal control over the network, and decisions are made through a consensus mechanism, rather than by a single entity or group. + +**Distributed Ledger Technology (DLT)** - a type of digital database that stores information across a network of computers or nodes. +It allows multiple parties to have a synchronized, transparent, and immutable record of transactions, without the need for a central authority or intermediaries. + +**Extrinsic** - a transaction that originates from an external account and affects the state of the blockchain. +It can be used to execute actions on the network, such as transferring funds, making governance decisions, using functionality of the parachain, or interacting with smart contracts. More details about Extrinsics can be found in the [official Polkadot documentation](https://wiki.polkadot.network/docs/learn-extrinsics) + +**Parachains** - sovereign blockchains running in parallel within the Kusama or Polkadot networks, connected via the Relay Chain of that network. +KILT launched as a parachain on the Kusama network in September 2021 and moved to Polkadot in September 2022. +More details about parachains can be found in the [offical Polkadot documentation](https://wiki.polkadot.network/docs/learn-parachains) + +**Polkadot** - a multi-chain network that allows for interoperability between different blockchain protocols, including the KILT Protocol. +More details about Polkadot can be found in the [official Polkadot documentation](https://wiki.polkadot.network/docs/getting-started#what-is-polkadot) + +**polkadot.js** - a JavaScript library that allows developers to interact with Substrate-based blockchains, including KILT Spiritnet and Peregrine. +It is the basis of the KILT SDK and provides many utilities and functions that may be useful for application developers. +More details about polkadot.js can be found in their [official documentation](https://polkadot.js.org/docs/). + +**Substrate** - a modular blockchain development framework used to build custom blockchain solutions, including the KILT Protocol blockchain. +More details about Substrate can be found in the [official Polkadot documentation](https://docs.substrate.io/) + +**Relay Chain** - the central chain in the Polkadot network that coordinates communication and consensus between different parachains. +More details about parachains can be found in the [official Polkadot documentation](https://wiki.polkadot.network/docs/learn-architecture) diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/01_quickstart.md b/versioned_docs/version-1.0.0/develop/01_sdk/01_quickstart.md new file mode 100644 index 000000000..02bd1c8f5 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/01_quickstart.md @@ -0,0 +1,227 @@ +--- +id: quickstart +title: Quickstart +--- + +import CodeBlock from '@theme/CodeBlock'; +import SnippetBlock from '@site/src/components/SnippetBlock'; +import TsJsSnippet from '@site/src/components/TsJsSnippet'; +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import PrintHelloWorld from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/01_print_hello_world.ts'; +import ConnectSpirit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/02_connect_spirit.ts'; +import ConnectPere from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/02_connect_pere.ts'; +import FetchDid from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/03_fetch_did.ts'; +import FetchEndpoints from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/04_fetch_endpoints.ts'; +import FetchEndpointData from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/05_fetch_endpoint_data.ts'; +import VerifyCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/06_verify_credential.ts'; +import Disconnect from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/07_disconnect.ts'; + +Get started with KILT by following this guide, which teaches you to: + +1. Import the **KILT SDK** into your project +2. Connect to the **KILT blockchain** +3. Query a **web3name** to retrieve its **DID** +4. Verify a **credential** using a **DID service** + +:::info Prerequisites + +This quickstart guide provides hands-on experience to enhance your understanding of KILT. +Basic knowledge of JavaScript and command-line tools is recommended. + +::: + +## Setup + +Create a new project and directory and move into the directory by running `mkdir kilt-rocks && cd kilt-rocks`. + + + + +Inside the `kilt-rocks` project directory, install the **KILT SDK**, **Typescript**, **ts-node**, and **Axios** dependencies: + +```bash npm2yarn +npm init -y +npm install @kiltprotocol/sdk-js ts-node typescript axios +``` + +With the required dependencies installed, create a TypeScript file with `touch quickstart.ts`. + + + + +From inside the `kilt-rocks` project directory, install the **KILT SDK**, **Node**, and **Axios** dependencies: + +```bash npm2yarn +npm init -y +npm install @kiltprotocol/sdk-js node axios +``` + +With the required dependencies installed, create a JavaScript file with `touch quickstart.js`. + +To enable ES modules in your project, add `"type": "module"` to the `package.json` file. + + + + +Declare an `async main` function in the `quickstart.ts` file that executes the rest of the code in this quickstart and call the `main()` function by default: + +{/* TODO: Do we need to test this or provide JS/TS equivalent? */} + +```js +async function main() { +} + +main() +``` + +**With the setup completed, let's get started! ๐Ÿ”ฅ** + +### Import the KILT SDK + +Begin by importing the **KILT SDK** and **Axios** at the top of the file: + +```js +import * as Kilt from '@kiltprotocol/sdk-js' +import axios from 'axios' +``` + +Now, you can access the SDK and all its functionality. +The next step is connecting to the **KILT blockchain**. + +### Connect to the KILT Blockchain + +To perform operations that rely on the **KILT blockchain**, such as querying and verifying a credential, you must first connect to the **KILT blockchain**. + +Within the `main` function, configure the SDK to connect to a KILT node using the `Kilt.connect()` method: + + + +

Peregrine is the development blockchain. + Connect to this network for testing and development purposes.

+ + {ConnectPere} + +
+ +

Spiritnet is the production blockchain. + When you are ready to publish your DApp, connect to the Spiritnet network for production purposes.

+ + {ConnectSpirit} + +
+
+ +To ensure proper cleanup, call the `Kilt.disconnect()` function at the bottom of the `main()` function. +You should add all other code before this function call: + + +{Disconnect} + + +By adding `await Kilt.disconnect()`, you ensure that the connection to the blockchain node is properly closed when the script finishes executing, which helps maintain the integrity of your application and is a good practice to follow. + +Run the code by calling the name of the file. +If you set up everything correctly, you should see no output showing that your code connected to the **KILT blockchain**. + + + + +```bash +yarn ts-node quickstart.ts +``` + + + + +```bash +node quickstart.js +``` + + + + +As you add to the code in this file, you can always run it with the same command. + +**Congratulations! ๐Ÿ”ฅ** + +You have connected to a KILT blockchain node. +The next step is to start querying data from the blockchain. + +## Query a KILT Identity + +The following code queries information related to a **web3name** (`kiltnerd123`) and uses it to retrieve the **KILT DID** linked to it. + +Between the `Kilt.connect()` and `Kilt.disconnect()` lines, add the following code: + + +{FetchDid} + + +Try running the code and check the result. + +Did you get the DID? You now have `kiltnerd123`'s DID. +The next step is to see if `kiltnerd123` has any publicly linked KILT credentials to retrieve and verify. + +## Retrieve and Verify a Credential + +A **KILT DID** can expose services that allow external resources to be linked to the DID. +**KILT credentials** represent one type of external resource. + +You can retrieve the **services** attached to kiltnerd123's DID and see if they link to any public credentials to **query** and **verify**. + +Add the following code after the code you added in the previous step but before the `await Kilt.disconnect()`. +It retrieves the services exposed by the DID found for `kiltnerd123`: + + +{FetchEndpoints} + + +The code should print endpoints as JSON. + +The next step is to see if you can find a credential among them. +You do this by selecting one of the endpoints and querying the URL to see if it returns a KILT credential collection as described in the [KiltPublishedCredentialCollectionV1 specification](https://github.com/KILTprotocol/spec-KiltPublishedCredentialCollectionV1). + +Add the following code after the code you added in the previous step but before `await Kilt.disconnect()`: + + + {FetchEndpointData} + + +If the script completes without errors, you retrieved the published credential using the URL specified in the service. + +The next step is to make sure the credential is **valid** and has a valid **structure**. + +The following code outputs a string depending on whether the credential is valid, revoked, or not valid. +Add it before `await Kilt.disconnect()`: + + +{VerifyCredential} + + +Run the code and wait to see if you can retrieve **and** verify one of kiltnerd123's credentials! + +:::info Next steps + +- If you want to explore more of KILT's features, read our [Concepts section](../../concepts/01_what_is_kilt.md). +- If you want to dive deeper into the SDK, read the next section, [the KILT Cookbook](./02_cookbook/01_dids/01_light_did_creation.md). + +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/00_generate_keys.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/00_generate_keys.md new file mode 100644 index 000000000..1553de1f2 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/00_generate_keys.md @@ -0,0 +1,63 @@ +--- +id: key-generation +title: Generate DID keys +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import GenerateKeys from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/00_generate_did_keys.ts'; + +Creating a Decentralized Identifier (DID) on the KILT network involves generating keying material for authentication and encryption. +This guide shows how to create a set of key pairs suitable for generating a KILT DID. + +Before proceeding, it's important to note that this example assumes the usage of the `@kiltprotocol/sdk-js` library along with the `@polkadot/util-crypto` library for cryptographic operations. + +Additionally, it's important to securely store keys and the mnemonic seed phrase. +For production use, ensure that private keys are encrypted and stored safely, while also creating a backup of the mnemonic seed phrase. + +## Derivation paths + +The code example below derives different types of keys from a single account using derivation paths. + +A derivation path is a way to derive a new key from a parent key and is a sequence of indices separated by a delimiter. +The most common delimiter is `/` (forward slash). + +KILT uses the same derivation paths as the underlying Polkadot libraries, using soft and hard key derivation. + +## Soft derivation + +A soft derivation allows someone to potentially figure out the initial account's private key if they know the derived account's private key. +It is also possible to determine that different accounts generated from the same seed are linked to that seed. + +A `/` (single slash) indicates a soft derivation path. +For example, `deal rice sunny now boss cluster team use wreck electric wing deliver/0` is a soft derivation path. + +## Hard derivation + +A hard derivation path does not allow someone to do either of these. +Even if you know a derived private key, it's not possible to figure out the private key of the root address, and it's impossible to prove that the first account is linked with the second. + +A `//` (double slash) indicates a hard derivation path. +For example, `deal rice sunny now boss cluster team use wreck electric wing deliver//0` is a hard derivation path. + +## Creating new accounts from a seed + +This approach allows you to generate various key pairs for authentication, key agreement, assertion methods, and capability delegation from one mnemonic seed phrase. + +To create another account using the same seed, change the number at the end of the string. For example, `/1`, `/2`, and `/3` create different derived accounts. + +Using derivation paths simplifies key management, ensuring that a single mnemonic seed serves as the basis for multiple keys associated with a DID. +This method improves efficiency while maintaining security. +However, it's essential to handle and store private keys securely to prevent unauthorized access and ensure the overall integrity and privacy of the decentralized identity system. + +Below is an example code snippet illustrating the key pair generation for a KILT DID: + + + {GenerateKeys} + + +:::info +This example doesn't show how to store the keys. +It is recommended to store the keys in a secure manner, e.g. only storing the private keys encrypted on disk. +The mnemonic seed phrase can be used to regenerate the keys, so it is recommended to also store the mnemonic in a secure manner and create a backup of it. +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md new file mode 100644 index 000000000..01c59ac8b --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md @@ -0,0 +1,36 @@ +--- +id: light-did-creation +title: Create a Light DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import LightDidSimple from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/01_light_did_simple.ts'; +import LightDidComplete from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/02_light_did_complete.ts'; + +The creation of a light DID requires the generation of some keying material for keys that are to be used for authentication and encryption. +For the sake of ease of use, the example snippets below show how to use keys generated with a `Keyring`, provided also by the `@polkadot/api` library, to generate key pairs that are kept in memory and disappear at the end of the program execution, unless saved to some persistent storage. + +The following is an example of how to create a light DID after creating an authentication keypair. + + + {LightDidSimple} + + +For cases in which an encryption key and some services also need to be added to a light DID: + + + {LightDidComplete} + + +:::info +In KILT, light DIDs are meant to be used in one of two cases: + +1. As *ephemeral, one-time identifiers* when establishing new communication channels with untrusted parties. +2. As an *entrypoint into the KILT ecosystem*, i.e., to obtain one's first credentials and get acquainted with KILT. + +As such, light DIDs do not support updates of any sort, but they retain the same identifier until they are upgraded to full DIDs. +They are not intended for use in complex and/or high-security use cases. +In those situations, a full DID should be used. +Visit the [next section](./02_full_did_creation.md) to see how to create and manage full DIDs. +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/02_full_did_creation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/02_full_did_creation.md new file mode 100644 index 000000000..389e8e940 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/02_full_did_creation.md @@ -0,0 +1,34 @@ +--- +id: full-did-creation +title: Create a Full DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import FullDidSimple from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/04_full_did_simple.ts'; +import FullDidComplete from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/05_full_did_complete.ts'; +import LightDidMigrate from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/03_light_did_migrate.ts'; + +The following is an example of how to create and write on the blockchain a full DID that specifies only an authentication key. + + + {FullDidSimple} + + +If additional keys or services are to be specified, they can be passed as parameters to the creation transaction. + + + {FullDidComplete} + + +## Upgrade a Light DID to a Full DID + +Another way to obtain a full DID is by upgrading a previously-created light DID. +KILT supports this operation in a way that does not invalidate any credentials that had been issued to the light DID before being upgraded. + +The following code shows how to migrate a light DID to a full DID. +Credentials, presentations, and verifications remain unchanged and remain valid. + + + {LightDidMigrate} + diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/03_full_did_update.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/03_full_did_update.md new file mode 100644 index 000000000..688385841 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/03_full_did_update.md @@ -0,0 +1,15 @@ +--- +id: full-did-update +title: Update a Full DID keys and service endpoints +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import FullDidUpdate from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/07_full_did_update.ts'; + +Once anchored to the KILT blockchain, a full DID can be updated. +For instance, the following snippet shows how to use the `authorizeBatch` function to update the authentication key, remove an old service *and* add a new one for a full DID in the same transaction. + + + {FullDidUpdate} + diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/04_did_query.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/04_did_query.md new file mode 100644 index 000000000..99f68590b --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/04_did_query.md @@ -0,0 +1,22 @@ +--- +id: did-query +title: Resolve a DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DidQuery from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/06_did_query.ts'; + +Querying the state of a DID is called **resolution**. +The entity that queries the DID Document for a given DID, i.e., resolves it, is called a **resolver**. + +The KILT SDK provides such a resolver to use with KILT DIDs, as the snippet below shows: + + + {DidQuery} + + +:::note +The DID resolver can resolve both light and full DIDs. +For a more in-depth explanation about the KILT DID method and resolution, refer to our [specification](https://github.com/KILTprotocol/spec-kilt-did). +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/05_full_did_delete.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/05_full_did_delete.md new file mode 100644 index 000000000..4e4232956 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/05_full_did_delete.md @@ -0,0 +1,29 @@ +--- +id: full-did-delete +title: Delete a Full DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import FullDidDelete from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/11_full_did_delete.ts'; +import FullDidDepositReclaim from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/13_full_did_deposit_reclaim.ts'; + +Once a DID is no longer needed, it is recommended to deactivate it by removing it from the KILT blockchain. +The following snippet shows how to do it: + + + {FullDidDelete} + + +:::warning +Please note that once deleted, a full DID becomes unusable and cannot be re-created anymore. +This means that all credentials obtained with that DID are no longer valid and must be obtained with a different DID if needed. +::: + +## Claim back a DID deposit + +Claiming back the deposit of a DID is semantically equivalent to deactivating and deleting the DID, with the difference that the extrinsic to claim the deposit can only be called by the deposit owner and does not require a signature by the DID subject: + + + {FullDidDepositReclaim} + \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/06_full_did_tx.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/06_full_did_tx.md new file mode 100644 index 000000000..ace83349e --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/06_full_did_tx.md @@ -0,0 +1,57 @@ +--- +id: full-did-batch +title: Build DID Extrinsics +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import FullDidSignTx from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/09_full_did_tx.ts'; +import FullDidBatch from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/08_full_did_batch.ts'; + +DID keys can be used to sign extrinsic. +But not every extrinsic can be signed using a DID. +The Spiritnet blockchain offers two types of extrinsics. + +The first type can only be called using an account. +We call them account extrinsic. +The second callable type are DID extrinsics. +They must be used for all KILT features like creating CTypes, issue attestations, etc. +Since every extrinsic requires fees to be paid, this type needs to be wrapped inside an account extrinsic. +Accounts hold balances and can therefore pay fees and provide deposits. + +This document describes how to sign the DID extrinsics. +The KILT SDK provides two functions for signing DID extrinsics. +The first function signs a single extrinsic while the second one batches multiple extrinsics together. + +## Single extrinsics + +To sign a single extrinsic, you need to provide: + +* the DID that wants to sign the extrinsic (also called *origin* of the extrinsic) + * refer to the [full did creation guide](02_full_did_creation.md) to learn how to create a DID +* [a `SignCallback` that signs the extrinsic](../07_signCallback.md) +* the extrinsic that should be signed and submitted +* and the address of the account that pays for the fees. + + + {FullDidSignTx} + + + +## Batch multiple extrinsics + +Full DIDs can also be used to batch multiple extrinsics that require the signature of the DID. +For instance, a batch could create multiple services with a single submission to the blockchain. +This would save the user the time of generating one additional signature, as multiple extrinsics are batched and signed at once. +The extrinsics are also submitted and executed in the same block. +For more information, see the [official Substrate documentation](https://paritytech.github.io/substrate/master/pallet_utility/pallet/struct.Pallet.html). + +An example of a batch using the `authorizeBatch` is provided below. + + + {FullDidBatch} + + +DIDs have different keys that posses different capabilities. +Each key can only be used to authorize a specific subset of extrinsics. +If extrinsics are batched together that require different DID keys, the `authorizeBatch` function will call the sign callback multiple times. diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/07_did_signature.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/07_did_signature.md new file mode 100644 index 000000000..7c6659fb4 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/07_did_signature.md @@ -0,0 +1,25 @@ +--- +id: did-signature +title: Generate and Verify a DID Signature +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DidSignature from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/10_did_signature.ts'; + +In addition to being used to authorize chain operations, both light and full DIDs have off-chain applications. + +One such applications is generating digital signatures. +As a DID can have multiple keys, in addition to the signature data itself, a DID signature contains information about the signer's DID and key used, so that Verifiers have all the information needed to resolve the DID from the KILT blockchain and use the right key to verify the generated signature. + +The snippet below shows how to generate and verify a DID signature using the KILT SDK. + + + {DidSignature} + + +:::note +Notice that the snippet above takes a `DidDocument` instance to generate the signature. +A `DidDocument` can represent either a light or a full DID. +This means that both light and full DIDs can generate signatures, and the KILT SDK implements the right verification logic depending on whether the signer is a light or a full DID. +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/08_did_export.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/08_did_export.md new file mode 100644 index 000000000..8b53f209d --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/08_did_export.md @@ -0,0 +1,21 @@ +--- +id: did-export +title: Exporting a KILT DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DidExport from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/12_did_export.ts'; + +The DID Document exporter provides the functionality needed to convert an instance of an SDK `DidDocument` object into a document that is compliant with the [W3C specification](https://www.w3.org/TR/did-core/). +This component is required for the KILT plugin for the [DIF Universal Resolver](https://dev.uniresolver.io/). + +## How to use the exporter + +The exporter interface and used types are part of the `@kiltprotocol/types` package, while the actual `DidDocumentExporter` is part of the `@kiltprotocol/did` package. +Both types and DID packages are accessible via the top-level `@kiltprotocol/sdk-js` import. +The following shows how to use the exporter to generate a W3C-compliant DID Document from a given `DidDocument`, which can represent either a light or a full DID. + + + {DidExport} + \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/_category_.json b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/_category_.json new file mode 100644 index 000000000..cd4de73d6 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "KILT DIDs", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/01_claim.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/01_claim.md new file mode 100644 index 000000000..88f687ba8 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/01_claim.md @@ -0,0 +1,19 @@ +--- +id: web3name-claim +title: Claim a web3name +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import Claim from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/01_claim.ts'; + +A web3name can be claimed if it currently has no owner, using the following snippet as reference. + + + {Claim} + + +The claiming process requires the reservation of a deposit that is freed upon web3name release. + +Once claimed, the web3name will start appearing whenever the DID of its owner is resolved, for instance via the [Universal Resolver](https://dev.uniresolver.io/#did:kilt:4pZGzLSybfMsxB1DcpFNYmnqFv5QihbFb1zuSuuATqjRQv2g). +For more information about web3names and DIDs, see the official [KILT DID Specification](https://github.com/KILTprotocol/spec-kilt-did/blob/main/README.md). diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/02_credential_query.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/02_credential_query.md new file mode 100644 index 000000000..9213f6810 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/02_credential_query.md @@ -0,0 +1,21 @@ +--- +id: credential-query +title: Query Public Credentials for a web3name +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import QueryNameCredentials from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/03_query_name_credentials.ts'; + +web3names are linked to KILT DIDs, and KILT DIDs can define services to expose additional service/information. +One of the possible endpoint types is the [`KiltPublishedCredentialCollectionV1`][kilt-published-credential-collection-v1-type] type. +The type defines the structure to make KILT credentials public and accessible to anyone. + +Because of the relationship between web3names and DIDs, it is possible, given a certain web3name, to retrieve all public credentials that the DID subject identified by that web3name has made available. +Below is a code snippet showing how to do that using the KILT SDK, and how to perform the needed security checks/validation as recommended by the [specification][kilt-published-credential-collection-v1-type]. + + + {QueryNameCredentials} + + +[kilt-published-credential-collection-v1-type]: https://github.com/KILTprotocol/spec-KiltPublishedCredentialCollectionV1/blob/main/README.md diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/03_release.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/03_release.md new file mode 100644 index 000000000..a22050964 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/03_release.md @@ -0,0 +1,48 @@ +--- +id: web3name-release +title: Release a web3name +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import Release from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/04_release.ts'; +import ReclaimDeposit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/05_reclaim_deposit.ts'; + +If a web3name is no longer needed, either the DID owner or the deposit payer can release it, with deposit being released and returned to the original payer. + +## Releasing a Web3name by the DID Owner + +In the case of the DID owner willing to release the web3name, the following snippet provides a reference implementation on how to achieve that. + + + {Release} + + +In the code above, the `releaseWeb3Name` function takes the following parameters: + +* **did**: The DID URI of the owner. +* **submitterAccount**: The keyring pair of the submitter. +* **signCallback**: The sign extrinsic callback function. This function is used to sign the extrinsic, read more that in [the SignCallback section](../07_signCallback.md). + +The function `releaseWeb3Name` uses the KILT SDK to create a *web3name release transaction* using `api.tx.web3Names.releaseByOwner`. +It then authorizes the transaction using the `Kilt.Did.authorizeTx` method and submits the authorized transaction to the blockchain using `Kilt.Blockchain.signAndSubmitTx`. +This process ensures that the release transaction is signed by the DID owner. + + +## Reclaiming a Web3name Deposit by the Deposit Payer + +If the web3name is being released by the deposit payer, the signature of the DID owner is not required; a regular signed extrinsic can be submitted to the KILT blockchain, as shown below. + + + {ReclaimDeposit} + + +In the code above, the `reclaimWeb3NameDeposit` function takes the following parameters: + +* **submitterAddress**: The keyring pair of the submitter. +* **web3Name**: The web3name for which the deposit is to be reclaimed. + +The function creates a web3name deposit reclaim transaction using `api.tx.web3Names.reclaimDeposit` and submits the signed transaction to the blockchain using `Kilt.Blockchain.signAndSubmitTx`. +Since the web3name is being released by the deposit payer, the signature of the DID owner is not required. + +By using these code examples, you can easily release or reclaim the deposit of a web3name, depending on the scenario and the role of the entity initiating the release. diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/04_query.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/04_query.md new file mode 100644 index 000000000..8112e5886 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/04_query.md @@ -0,0 +1,24 @@ +--- +id: web3name-query +title: Resolve a web3name +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import QueryDid from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/02_query_did_name.ts'; + + +A web3name can be resolved in a similar manner to [how a DID is resolved](../01_dids/04_did_query.md). +Resolving the web3name will provide the same information as resolving a DID does. + +To query and retrieve the DID document associated with a web3name, you can use the following code example: + + + + {QueryDid} + + +In the code example above, the `queryDidDocument` function takes a web3Name parameter, which represents the web3name to be resolved. +It internally uses the `api.call.did.queryByWeb3Name` method to query the information of the provided web3name from the blockchain. + +The function then decodes the result using `Kilt.Did.linkedInfoFromChain` to extract the associated DID document and any other linked blockchain accounts. Finally, it returns the resolved DID document. diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/_category_.json b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/_category_.json new file mode 100644 index 000000000..6dab303b4 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "web3names", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/01_link.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/01_link.md new file mode 100644 index 000000000..db6735186 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/01_link.md @@ -0,0 +1,87 @@ +--- +id: account-link +title: Link an Account to a KILT DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import SubAccLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/01_sub_link.ts'; +import EthAccLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/01_eth_link.ts'; +import EthWeb3AccLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/01_eth_link_web3js.ts'; +import EthMetamaskAccLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/01_eth_link_metamask.ts'; +import SenderLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/02_sender_link.ts'; + +Sometimes there is the need to link a DID to an account publicly. +The link makes it possible to lookup a DID for an account. +The other directions is also possible. +With a DID you can lookup a list of linked account. + +Linking accounts can be useful when your account should have an identity. +E.g. as a collator, you might want to provide some public information so that delegator can better decide who earned their stake. + +An account can be linked to a DID in one of two ways. +Either the account that sends the transaction links itself to the DID, or the sender is unrelated to the DID and a third account is linked. +In the latter case, a challenge needs to be signed using the third account, to prove ownership. + +The second option is useful in cases where the account that should be linked doesn't own KILT tokens and the transaction is paid for by a third party. +This option also allows to link account schemes that are not native to the Spiritnet Blockchain. +Right now the only other address scheme supported are ethereum accounts. + +:::warning Don't use linked accounts for asset transfers + +Don't use these linked accounts for asset transfers. +Since these accounts are not limited to KILT accounts, but can be used on any chain, the recipient might not be able to access the transferred asset on other chains. +When a link to an account on a different Polkadot chain is created, this account might only be usable on this specific chain. + +If you want transfer assets to a DID have a look at [the asset transfer service](https://github.com/KILTprotocol/spec-KiltTransferAssetRecipientV1). + +::: + +## Linking the sender to a DID + +Link the sender of the transaction to the DID. +The sender will provide the deposit and pay the fees. +They will also be linked to the DID. + + + {SenderLink} + + +## Linking an account to a DID + +Link another account to the DID. +The sender will provide the deposit and pay the fees, but will not be linked to the DID in any way. +The account that should be linked must sign a challenge to prove that the account agrees to be linked. + +The proof contains the DID that the account will be linked to and an expiration date (in terms of blocks), to prevent replay attacks. +The proof will only be valid up until the blocknumber is reached. + +With this option you can link addresses that are supported by the Spiritnet blockchain (Sr25519, Ed25519, Ecdsa), but also ethereum addresses. + + + + + {SubAccLink} + + + + + {EthAccLink} + + + + + {EthWeb3AccLink} + + + + Refer to the Metamask documentation for further information. + + {EthMetamaskAccLink} + + + diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/02_account_name.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/02_account_name.md new file mode 100644 index 000000000..ed7357fb6 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/02_account_name.md @@ -0,0 +1,27 @@ +--- +id: account-name +title: Query the web3name of an Account +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import AccountWeb3NameQuery from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/03_account_web3name_query.ts'; +import AccountWeb3NameQueryNoSDK from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/04_account_web3name_query_no_sdk.ts'; + +For accounts that have been linked to DIDs that have claimed a web3name, the linking feature opens the way to a host of possibilities, e.g., showing the web3name of a collator's account on the [KILT Stakeboard][kilt-stakeboard]. + +This section shows how to perform the `account -> web3name` querying both with and without the support of the KILT SDK. + +## Query an Account's web3name with the KILT SDK + + + {AccountWeb3NameQuery} + + +## Query an Account's web3name without the KILT SDK + + + {AccountWeb3NameQueryNoSDK} + + +[kilt-stakeboard]: https://stakeboard.kilt.io/ diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/03_unlink.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/03_unlink.md new file mode 100644 index 000000000..08711f178 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/03_unlink.md @@ -0,0 +1,30 @@ +--- +id: account-unlink +title: Unlink an Account From a KILT DID +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DidUnlink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/05_did_unlink.ts'; +import AccountUnlink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/06_account_unlink.ts'; +import ReclaimDeposit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/07_reclaim_deposit.ts'; + +Similar to the way a new account to DID link is created, removing a link can happen in one of three ways: + +1. The DID owner submits a transaction indicating which account to unlink: + + + {DidUnlink} + + +2. The linked account submits a transaction indicating that the link with the DID should be removed: + + + {AccountUnlink} + + +3. The deposit payer submits a transaction indicating that they want to reclaim their deposit, which in turn removes the existing link between the specified account and DID: + + + {ReclaimDeposit} + \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/_category_.json b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/_category_.json new file mode 100644 index 000000000..ac71ff896 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Account <-> KILT DID Relationship", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md new file mode 100644 index 000000000..12d3aba54 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md @@ -0,0 +1,44 @@ +--- +id: ctype-creation +title: Create a CType +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import CreateCType from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/01_create_ctype.ts'; +import FetchCType from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/02_fetch_ctype.ts'; + +Every KILT credential has to conform to a CType. +A CType describes which properties a credential has and what type these properties have. +CTypes must be registered on the Spiritnet blockchain. +To learn more about CTypes, see the [CType concept section](../../../../concepts/05_credentials/02_ctypes.md). + +The creation of a CType in KILT involves two steps: the definition of a CType and the anchoring of its hash on the KILT blockchain. + +:::info DID required +The creator of a CType is required to have a full DID with an attestation key. +To see how to manage DIDs, please refer to the [DID section](../01_dids/03_full_did_update.md). +::: + +:::info CTypes are unique +The creation of a new CType requires the CType hash to be unique. +Before writing a new CType, Attesters should check whether there is already an existing CType which matches their requirements. + +Visit our [CType index repository](https://github.com/KILTprotocol/ctype-index) for a non-exhaustive list of existing CTypes. +::: + +The following snippets show how to create a CType: + + + {CreateCType} + + + +## Retrieve a CType from its ID + +CTypes can be queried directly from any KILT archive nodes. +The following example shows how to query a CType using the SDK: + + + {FetchCType} + diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md new file mode 100644 index 000000000..bd602126f --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md @@ -0,0 +1,21 @@ +--- +id: attestation-request +title: Request an Attestation +--- +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import RequestAttestation from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/03_request_attestation.ts'; + +To obtain credentials, Claimers have to request an attestation for a set of claims from an Attester. +The resulting object is a `Credential`, which can be created following the snippet below. + +This process does not involve any interaction with the KILT blockchain, but is simply a communication channel where the Claimer and the Attester can communicate. + + + {RequestAttestation} + + +:::note +The structure of the claims must respect the schema defined in the specified CType. +Attesters (and Verifiers) will reject claims that fail to verify correctly. +::: \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md new file mode 100644 index 000000000..1a53d3755 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md @@ -0,0 +1,21 @@ +--- +id: attestation-creation +title: Attest a Claim (Issue a Credential) +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import CreateAttestation from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/04_create_attestation.ts'; + +Once an Attester has received a to-be-attested `Credential` from a Claimer, they will typically verify the information in the claim. +If the claims correspond to truth, the Attester will proceed by attesting the root hash of the credential on the KILT blockchain, timestamping the attestation operation. +A deposit is reserved from the balance of the KILT account submitting the creation transaction, which is returned if and when the attestation is removed from the chain. + +:::info +An Attester is required to have a full DID with an attestation key. +To see how to manage DIDs, please refer to the [DID section](../01_dids/03_full_did_update.md). +::: + + + {CreateAttestation} + \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md new file mode 100644 index 000000000..facd14d49 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md @@ -0,0 +1,26 @@ +--- +id: presentation-creation +title: Present a Credential +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import CreatePresentation from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/05_create_presentation.ts'; + +With a valid credential, Claimers can now go to Verifiers to request some service upon providing proof of validity of a certain credential. +The process of presenting one or more credentials to a Verifier is called `Presentation`. + +This step, similar to the [attestation request](./02_attestation_request.md), requires that a communication channel exist between the Claimer and the Verifier so that information about the presentation can be shared. +To verify the revocation status of the presented credential(s), a Verifier must be able to interact with a KILT full node. + +:::info +KILT supports selective disclosure of claims when creating presentations. +This means that given a credential, it is possible for the Claimer to reveal only a subset of its claims, depending on the requirements set by the Verifier. +Check the snippet below to see how that is done using the KILT SDK. +::: + +The Claimer can generate a presentation starting from a credential, optionally specifying the fields to reveal and a presentation challenge, which is useful to prove freshness of the generated presentation. + + + {CreatePresentation} + \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md new file mode 100644 index 000000000..480cc236d --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md @@ -0,0 +1,27 @@ +--- +id: presentation-verification +title: Verify a Credential or a Presentation +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import VerifyPresentation from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/06_verify_presentation.ts'; + +Whether a presentation involves selective disclosure or a whole credential is not technically relevant to Verifiers. +This is because in KILT a presentation **is** a credential. +This means that the logic for Verifiers does not change depending on the case, thus verifying a presentation is as easy as calling one SDK function, like the following code snippet: + + + {VerifyPresentation} + + +:::warning Check if the presenter is the credential subject +Verifying a presentation provides proof that all the information is correct and authentic, and that the credential has not been revoked. +Verifiers still need to match the subject of the credential to the entity that is presenting it. +One way of achieving this is by asking the Claimer to include a challenge in the presentation signature, as shown in the snippet above. +Without a challenge, Verifiers must implement other measures to be certain about the identity of the presenter. +::: + +:::warning Evaluation of the attester's trust is up to the Verifiers +Verifiers must also have a registry of attesters they trust, and verify that the issuer of the credential they are verifying belongs to such list and, where necessary, whether it is still in operation or not, i.e., whether its DID still exists or has been deleted. +::: \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/06_credential_revocation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/06_credential_revocation.md new file mode 100644 index 000000000..da6ff398b --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/06_credential_revocation.md @@ -0,0 +1,26 @@ +--- +id: attestation-removal +title: Revoke a Credential +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import RevokeCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/07_revoke_credential.ts'; +import ReclaimDeposit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/08_reclaim_attestation_deposit.ts'; + +If the conditions that make a credential valid cease to exist, an Attester can revoke and optionally remove their attestation from the KILT blockchain. +This does not automatically delete the credential from the Claimer's wallet, of course, but it makes it impossible for the Claimer to use the credential in the future. + +Since the attestation creation reserved some KILT tokens from the submitter's balance, removing an attestation would return those funds into the payer's pockets. + + + {RevokeCredential} + + +## Claim Back an Attestation Deposit + +Claiming back the deposit of an attestation is semantically equivalent to revoking and removing the attestation, with the difference that the extrinsic to claim the deposit can only be called by the deposit owner and does not require the Attester's signature: + + + {ReclaimDeposit} + \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/_category_.json b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/_category_.json new file mode 100644 index 000000000..21073c229 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "KILT Credentials", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/01_credential_issuance.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/01_credential_issuance.md new file mode 100644 index 000000000..2bd743f12 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/01_credential_issuance.md @@ -0,0 +1,44 @@ +--- +id: public-credential-issuance +title: Credential Issuance +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import CreateCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/01_create_credential.ts'; +import IssueCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/02_issue_credential.ts'; + +As for traditional KILT credentials, public credentials also have their structure defined by a [CType][ctypes-link], although CTypes that can be used to represent information about assets would probably differ from the ones used to represent information about people. + +As mentioned in the section about credentials, the creation of a CType in KILT involves two steps: the definition of a CType and the anchoring of its hash on the KILT blockchain. + +We will not cover the creation of a CType, please refer to the [CType creation](../04_claiming/01_ctype_creation.md) + +## Create and Issue the Credential + +Using the existing CType, the new public credential object can be created with the actual content, and then written to the chain for the rest of the KILT users (and beyond) to consume. + +Creating a public credential is as simple as creating an object that conforms to the required structure of the CType: + + + {CreateCredential} + + +:::note +The creation of the credential object does not require any interaction with the blockchain per se. +This also means that, until the object is written to the blockchain (see below), it cannot be used/retrieved/verified by anyone else, so it is, by all means, not existing. +::: + +Once the credential object is created, it must be written to the blockchain for other people to be able to use it. + + + {IssueCredential} + + +:::info Credential has to be CBOR-encoded! +Given a public credential object, the SDK internally CBOR-encodes it before firing the extrinsic to the blockchain! +This is to save space on credentials that actually benefit from CBOR compression (e.g., if they contain a lot of binary information). +Hence, creating public credentials without the SDK requires the credential to be CBOR-encoded! +::: + +[ctypes-link]: ../../../../concepts/05_credentials/02_ctypes.md diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/02_credential_retrieval.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/02_credential_retrieval.md new file mode 100644 index 000000000..925becd7f --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/02_credential_retrieval.md @@ -0,0 +1,68 @@ +--- +id: public-credential-retrieval +title: Retrieve Public Credentials +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import RetrieveCredentialbyId from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/03_retrieve_credential_by_id.ts'; +import RetrieveCredentialsbySubject from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/04_retrieve_credentials_by_subject.ts'; +import VerifyCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/05_verify_credential.ts'; + +Public credentials have their best capability in the fact that they are, indeed, public by design. +This means that once issued, anyone who has access to an archive or full node for the KILT blockchain can retrieve them, making them very decentralized in nature. + +The KILT SDK exposes different ways to fetch public credentials. + +## Retrieve a Credential by its Identifier + +Some use cases might involve the communication of just the ID of one or more public credentials, e.g., to offload the retrieval of the full credential to the receiver, and save some communication bandwidth. + +The KILT SDK accounts for this use case, and makes it very easy to query a public credential given its ID: + + + {RetrieveCredentialbyId} + + +If a credential with the provided ID cannot be found, then the ID is invalid and should be treated as such by the received. + +## Retrieve All Credentials for an Asset + +Other use cases might work differently: given an asset identified by an [AssetDID][asset-did-concept], a user might want to retrieve all the credentials that have been issued to that asset. + +The KILT SDK makes also this use case very easy: + + + {RetrieveCredentialsbySubject} + + +## Verify a Public Credential + +A third class of use cases might involve users exchanging whole public credentials, for instance when showing some sort of proof. + +This case is also supported by the KILT SDK, and relies on an important feature of public credentials: **the identifier (ID) of a public credential is generated from its content and from the KILT DID of its attester**. +This means that even a minimal change in the content of a public credential object before being shared with other parties, will result in those parties deriving a different identifier from the credential, which will then lead to an error during the verification process. + +Verifying a public credential is shown in the following snippet: + + + {VerifyCredential} + + +What the `verifyCredential` function does internally is the following: + +1. Derive the credential identifier from the provided content and attester information. +2. Fetch the actual credential from the blockchain, as shown in the [section above](#retrieve-a-credential-by-its-identifier), failing if the credential does not exist. +3. [OPTIONAL] Verify that the credential structure matches what the optionally-provided CType defines. +4. Verify that the rest of the fields in the provided credential (i.e., revocation status, identifier, creation block number) match the retrieved credential. + +If all the tests above pass, the credential is considered valid! โœ… + +:::info How are public credentials stored on the blockchain? +Because public credentials need to be public and accessible by everyone, their full content needs to be somehow stored on the blockchain. +Nevertheless, the credential itself is not stored as part of the blockchain database. +Rather, the block number in which the extrinsic is submitted is stored inside the blockchain database, and serves as a "pointer" to the block containing the whole information, that clients (including the SDK) can use. +This represents a very good tradeoff between **security** - because the blockchain itself dictates what the creation block number is for any given public credential - and **storage efficiency** - since the full credential is stored off-chain, accessible via any KILT archive node or indexing service. +::: + +[asset-did-concept]: ../../../../concepts/04_asset_dids.md diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/03_credential_revocation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/03_credential_revocation.md new file mode 100644 index 000000000..23f9a79f9 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/03_credential_revocation.md @@ -0,0 +1,63 @@ +--- +id: public-credential-revocation +title: Revoke (and remove) Public Credentials +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import RevokeRemoveCredentialById from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/06_revoke_remove_credential_by_id.ts'; +import RevokeCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/07_revoke_remove_credential_by_content.ts'; +import UnrevokeCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/08_unrevoke_credential.ts'; +import ReclaimDeposit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/09_reclaim_deposit.ts'; + +Depending on the use cases, some credentials, as with any other type of credential, might need to be temporarily or permanently revoked. + +The KILT SDK provides different features depending on the needs of the use case. + +## Revoke and Remove a Credential + +As we have seen for [public credential retrieval][credential-retrieval], a credential identifier is sufficient to perform most operations on public credentials. +This is true also for revocation and removal. + +Some use cases might need a revoked credential to remain on chain and marked as revoked, while other use cases might combine together revocation and removal, removing a credential whenever it is to be marked as revoked, fulfilling the same goal of marking the credential as invalid. + +In the former case, the deposit taken at the time when the credential is created is not returned, since the credential is still on chain. +In the latter case, all information about the information is cleared, hence the deposit is returned to its original payer. + + + {RevokeRemoveCredentialById} + + +Because a credential identifier can also be calculated starting from the credential itself and the information about its attester, it is also possible to revoke (and optionally remove) a credential given the credential itself. + + + {RevokeCredential} + + +## Unrevoke a Credential + +For public credentials that have been revoked but not removed from chain, it is possible to un-revoke them, making them valid again. + +For instance, a driving license can be marked as "suspended" for three years, without being completely invalidated. +At the end of the suspension period, it is enabled again by being unrevoked. + +As for revocation, both the credential ID and the whole credential can be used, since the SDK provides the primitives to always obtain the former from the latter, but here we show how the whole credential can be used to generate and submit an un-revocation transaction. + + + {UnrevokeCredential} + + +## Reclaim the Deposit for a Credential + +All the operations mentioned so far, always require the participation of the public credential attester, who must use their assertion key to sign all operations before they are submitted to the KILT blockchain. + +The only operation that can be submitted directly by someone else, as with other places in the SDK, is the transaction to remove a credential and obtain the initial deposit. + +This is, technically speaking, a different operation compared to the one to remove a credential, albeit the two yield the same result: all traces of the credential are removed from the chain and the deposit is returned to its payer. +The difference between the two is about who is authorized to perform the operation: while credential removal requires a DID signature by the original credential creator (a.k.a. issuer), the deposit claiming operation requires a regular transaction signature by the KILT account that paid the original deposit, with no involvement of the original attester. + + + {ReclaimDeposit} + + +[credential-retrieval]: ./02_credential_retrieval.md \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/_category_.json b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/_category_.json new file mode 100644 index 000000000..ddf9ba6eb --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Public Credentials and AssetDIDs", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/01_messaging.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/01_messaging.md new file mode 100644 index 000000000..406b53343 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/01_messaging.md @@ -0,0 +1,55 @@ +--- +id: messaging_book +title: Generate a Message +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import GenerateRequestCredentialMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/01_generate_request_credential_message.ts'; +import EncryptMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/02_encrypt_message.ts'; +import DecryptMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/03_decrypt_message.ts'; + +KILT defines a [unicast](https://en.wikipedia.org/wiki/Unicast) messaging protocol + +Each of the messages sent is encrypted using the [DID key agreement key](https://www.w3.org/TR/did-core/#key-agreement). +A message consists of the sender's DID URI, the receiver's DID URI, the message type and the body. +There are multiple different message types, each of them with a different structure and containing different information. +In this example we are going to build a `request-credential` message. +The message structure is checked and validated on by the KILT SDK to ensure the users are sending correctly structured messages. + +The following example here will generate a message by constructing the message content. +The message content includes a valid `cTypeHash` and a list of `trusted attesters`. +The message requires a `messageBody`, sender and receiver uri. + + + {GenerateRequestCredentialMessage} + + +## Encryption + +The messages data are encrypted and decrypted using [nacl's](https://github.com/dchest/tweetnacl-js) 'x25519-xsalsa20-poly1305' algorithm, which provides repudiable authenticated encryption based on an x25519 key agreement protocol. +The DID holds keys for the encryption and decryption. +The key is called `KeyAgreement` keys. +They may also be known as encryption keys. + +The content of the object is converted from a serialized string to a byte array, which is passed into the callback function along with the sender's DID and key agreement public key of the receiver. + +The following example here will take a generated message and encrypt the message for the receiver to decrypt later. + + + {EncryptMessage} + + +The encrypted data is converted into a hex string which is known as the ciphertext along with the nonce that was generated during encryption. + +## Decryption + +The decryption takes the encrypted message and decyphers its content. +The following example here will take a encrypted message and decrypt using the private key of the receiver. +Once decrypted, it checks the content is a valid message. +The decrypted data can be used for additional steps. +After decrypting, the receiver may wish to present a credential from the trusted attester list with a given CType. + + + {DecryptMessage} + diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md new file mode 100644 index 000000000..4c5d93b87 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md @@ -0,0 +1,43 @@ +--- +id: replay_protection +title: Protect Against Replay Attacks +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DefineRange from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_01.ts'; +import EvaluateMessageTime from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_02.ts'; +import PurgeTimeout from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_03.ts'; + +Whenever data travels on a public network, even when encrypted or signed, the communicating parties need to make sure they never accept and process a message more than once to protect against exploits by malicious third parties (so-called replay attacks). +When requesting and submitting credential presentations, vulnerabilities for replay attacks can be prevented by requesting that the Claimer sign a unique piece of data as part of the presentation, as shown in the [Verification Cookbook section](../04_claiming/04_presentation_creation.md). + +However, protection against replay attacks can also happen on the message layer. +To help prevent these types of attacks, KILT messages are timestamped and expose a unique identifier as part of their encrypted content, which therefore cannot be tampered with. +It is good practice to impose limits on an acceptable range for timestamps on incoming messages and to keep a record of the ids of previous submissions, which can be purged after their acceptance range has run out. +This way, any resubmission is either rejected because its id is known to the recipient, or because its timestamp is too old. +Below you can find example code of how this could be implemented. + +1. Define acceptance range and set up a record of past submissions: + + + {DefineRange} + + +2. Check record for each incoming message and update if accepted: + + + {EvaluateMessageTime} + + +3. Purge at regular intervals: + + + {PurgeTimeout} + diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/_category_.json b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/_category_.json new file mode 100644 index 000000000..2c3437f16 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Messaging", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/07_signCallback.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/07_signCallback.md new file mode 100644 index 000000000..e704093ab --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/07_signCallback.md @@ -0,0 +1,83 @@ +--- +id: signCallback +title: SignCallback +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import SignCallback from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/signCallback/useSignCallback.ts'; +import SignExtrinsicCallback from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/signCallback/useExtrinsicCallback.ts'; +import GetStoreTxSignCallback from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/signCallback/useStoreTxSignCallback.ts'; + +Signing data involves using the private key and therefore needs to be secure. +There are many different options how data could be signed. +You might have the private key stored in memory and are therefore able to simply sign the data. +This is the easiest option but also comes with higher security risk. +Storing the private key on a separate device or inside a sandboxed application can increase security. +But to enable these security options, we need a generic interface to talk to the signer. +This is what the `SignCallback` does. + +The `SignCallback` defines an interface between the SDK and an arbitrary signing strategy. +May it be a ledger, an air gapped phone or your browser extension. +The interface is generic enough to support implementations for all these security measures. + +## The SignCallback Family + +There are three types of signing callbacks: +1. The `SignCallback` is the most general and can be used in almost all cases, except when signing a full DID creation transaction. +2. The `SignExtrinsicCallback` is a special `SignCallback` which can only be used to sign extrinsics. + Thus, every `SignCallback` can also be used as a `SignExtrinsicCallback`. +3. The `GetStoreTxSignCallback` can only be used to sign the creation of a new DID. + +### SignCallback + +The plain `SignCallback` signs arbitrary data. +It is called with `SignRequestData` which contains + +* the `data` as `UInt8Array` that should be signed +* the `keyRelationship` which specifies which DID key must be used +* and the `did` (`DidUri`) which specifies the DID that must sign the data + +The callback is expected to return a `SignResponseData` which contains + +* the `signature` as an `UInt8Array` +* the `keyUri` which identifies the key that was used for signing +* and the `keyType` which specifies the signature scheme that was used (either `sr25519`, `ed25519` or `ecdsa`) + +The signed callback can be used as a closure. +If you already have the private key of the DID stored in the surrounding scope, you can just use this key. + + + {SignCallback} + + +### SignExtrinsicCallback + +The `SignExtrinsicCallback` is a special case of the `SignCallback`. +Signing an extrinsic doesn't require the `keyUri` as a return value since the chain will pick the appropriate key using information from the extrinsic. +The extrinsic that is submitted has a specific `VerificationKeyRelationship`, which defines which key must be used to sign the extrinsic. +Using this relation between extrinsic and key, the chain looks up the public key and verifies the signature. + +The `SignExtrinsicCallback` is called with the same `SignRequestData`, but can return a `SignResponseData` that doesn't contain the `keyUri` but only + +* the `signature` as an `UInt8Array` +* and the `keyType` which specifies the signature scheme that was used (either `sr25519`, `ed25519` or `ecdsa`). + + + {SignExtrinsicCallback} + + +### GetStoreTxSignCallback + +The `GetStoreTxSignCallback` is only used to sign the data that is submitted to the blockchain when a DID is being created. +Because there is no DID identifier before the DID is registered on chain, this callback doesn't receive the DID as a parameter. +There is also no DID document and no public key stored if the DID hasn't yet been created. +Therefore the `keyUri` cannot point to a valid DID key and is not included in the return data. + + + {GetStoreTxSignCallback} + + +## Signing using an extension + +๐Ÿšง This section is work in progress ๐Ÿšง diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/01_backward_compatibility.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/01_backward_compatibility.md new file mode 100644 index 000000000..5cd11e026 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/01_backward_compatibility.md @@ -0,0 +1,93 @@ +--- +id: v29-backward-compatibility +title: Backward Compatibility with Pre-0.29.x Versions +--- + +Depending on how exactly your application interacts with other applications, changes to some data formats and interfaces might mean that conversions are required for them to remain compatible. + +To align with breaking changes to data structures in messaging, credentials, and CTypes, we published version 3.0 of the [Credentials API specification](https://github.com/KILTprotocol/spec-ext-credential-api) that specifies how browser extensions like the [Sporran credential wallet](https://github.com/BTE-Trusted-Entity/sporran-extension) interact with web applications that produce or consume credentials. + +When upgrading to a 0.29.x version of the SDK and to the Credentials API version 3.0, we recommend backward support of Credentials API version 2.0, as supporting only the latest version may result in poor user experience. In what follows, we outline an upgrade strategy for implementers of the Credentials API specification. + +These instructions will also help with translating from and to data types of pre-0.29 SDK versions in other scenarios, such as when sending messages between clients, or when importing older data (e.g. credentials). + +## General Strategy + +Since version 3.0, the specification requires conformant web apps as well as extensions to announce the versions of the API they use, allowing for version negotiation. +Because extensions inject themselves into web pages that signal support for kilt features via the `window.kilt` property, the recommended strategy is to handle backward compatibility on the extension side. +This way, extensions can be upgraded ahead of time, and implement a fallback to a version 2.0 compatible interface if a web application does not signal version 3.0 support. +Following this strategy, backward compatibility on the application side is not strictly necessary. +We recommend notifying users of web apps that have upgraded to version 3.0 if they try to connect with an older extension, pointing them to the need to upgrade their extension to use this app. + +## Message Conversion + +Breaking changes introduced with version 3.0 of the Credential Api exclusively affect selected data types of messages passed between the application backend and extension. +In the attester (credential issuance) flow the message types `submit-terms` and `request-attestation` have changed. +In the verifier (presentation exchange) flow the message type `submit-credential` message is affected. + +Version 3.0 extensions can achieve backward compatibility by translating messages received from and sent to the application which implements an earlier version of the specification. +Below you can find brief descriptions of how these conversions can be implemented. + + + +### `submit-terms` + +When receiving a `submit-terms` message from the old web app, replace the items of the `cTypes` content property with the values of their `schema` properties: + +```ts +interface Old { + cTypes: Array<{ + schema: ICTypeSchema + hash: HexString // duplicates `schema.$id` + owner: DidUri | null // apparently unused + }> + ... +} + +interface New { + cTypes: Array // Note that 0.29 renames ICTypeSchema to ICType + ... +} +``` + + + +### `request-attestation` + +Before encrypting a `request-attestation` type message destined for an older web app, rename `credential` to `requestForAttestation`: + +```ts +interface New { + credential: { claim, ... } + quote?: IQuoteAgreement +} + +interface Old { + requestForAttestation: { claim, ... } + quote?: IQuoteAgreement +} +``` + +:::info +The old `IRequestForAttestation` interface optionally allowed claimers to attach a signature for authentication. +There is no property intended for this purpose on the new interface, as the message encryption scheme already takes care of authentication. +What has changed is that this form of authentication is __not publicly verifiable__. +Attesters can instead require claimers to sign a quote agreement for the purpose of bookkeeping, which contains the credential hash and thus represents a commitment to any claims made. +::: + +### `submit-credential` + +Before encrypting a `submit-credential` message for the older application, replace every item with an object having the property `request` with the value of item itself, and the property `attestation` with the attestation for this credential. + +```ts +interface New extends Array<{ claim, ..., claimerSignature }> {} + +interface Old extends Array<{ + attestation: { claimHash, owner, ... } + request: { claim, ..., claimerSignature } +}> {} +``` diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/_category_.json b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/_category_.json new file mode 100644 index 000000000..a58847a1c --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Upgrading to v0.29", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/index.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/index.md new file mode 100644 index 000000000..810b3c4c0 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/08_upgrading_to_v0_29/index.md @@ -0,0 +1,15 @@ +--- +id: howto-upgrade-v29-index +title: Upgrading to v0.29 +--- + +Version 0.29.0 is the result of our efforts to make the SDK easier to understand and to use. + +As a consequence, quite a few things have changed relative to previous versions. +These pages serve as a reference point for what to consider when upgrading to make your transition as smooth as possible. + + + +Find out what has changed and how to upgrade in the [release notes](https://github.com/KILTprotocol/sdk-js/releases/tag/0.29.0). + +Also make sure to read up on [how to remain interoperable](./01_backward_compatibility.md) with previous versions of the SDK. diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/_category_.json b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/_category_.json new file mode 100644 index 000000000..3eda769a1 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Cookbook", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/01_standalone_setup.md b/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/01_standalone_setup.md new file mode 100644 index 000000000..5ba705d44 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/01_standalone_setup.md @@ -0,0 +1,113 @@ +--- +id: standalone-chain-setup +title: BYOB - Bring Your Own Blockchain +--- + +If you want to have full control over your blockchain deployment, e.g., if you want to reset the state repeatedly or need more funds than a faucet can provide for a single account, you will need to run your own blockchain. +For this purpose, we provide a Docker image which runs in standalone mode. +This means that the blockchain doesn't act as a parachain but as an independent chain. +There is no need to run a Relay Chain and register the KILT chain as a parachain. +This greatly simplifies the setup. + +You only need to start the Docker image: + +```bash +docker run --rm -it -p 9944:9944 -p 9933:9933 kiltprotocol/standalone-node:latest --dev --ws-external --rpc-external +``` + +You should see output similar to the following: + +``` +2022-05-05 13:25:12 KILT Node +2022-05-05 13:25:12 โœŒ๏ธ version 1.6.2 +2022-05-05 13:25:12 โค๏ธ by KILT , 2019-2022 +2022-05-05 13:25:12 ๐Ÿ“‹ Chain specification: Development +2022-05-05 13:25:12 ๐Ÿท Node name: subdued-chair-0035 +2022-05-05 13:25:12 ๐Ÿ‘ค Role: AUTHORITY +2022-05-05 13:25:12 ๐Ÿ’พ Database: RocksDb at /tmp/substrateufCNUV/chains/development/db/full +2022-05-05 13:25:12 โ›“ Native runtime: kilt-kestrel (kilt-kestrel-0.tx3.au4) +2022-05-05 13:25:13 ๐Ÿ”จ Initializing Genesis block/state (state: 0xb4a2โ€ฆ94b3, header-hash: 0x09fcโ€ฆ3a2b) +2022-05-05 13:25:13 ๐Ÿ‘ด Loading GRANDPA authority set from genesis on what appears to be first startup. +2022-05-05 13:25:14 Using default protocol ID "sup" because none is configured in the chain specs +2022-05-05 13:25:14 ๐Ÿท Local node identity is: 12D3KooWMCqWaxXTQbmG9feCe4cMzjCzUKfm5T6VvGDmh8X5QHe9 +2022-05-05 13:25:14 ๐Ÿ“ฆ Highest known block at #0 +2022-05-05 13:25:14 ใ€ฝ๏ธ Prometheus exporter started at 127.0.0.1:9615 +2022-05-05 13:25:14 Listening for new connections on 0.0.0.0:9944. +2022-05-05 13:25:19 ๐Ÿ’ค Idle (0 peers), best: #0 (0x09fcโ€ฆ3a2b), finalized #0 (0x09fcโ€ฆ3a2b), โฌ‡ 0 โฌ† 0 +2022-05-05 13:25:20 Accepted a new tcp connection from 172.17.0.1:56636. +2022-05-05 13:25:23 ๐Ÿ™Œ Starting consensus session on top of parent 0x... +2022-05-05 13:25:23 ๐ŸŽ Prepared block for proposing at 1 (3 ms) [hash: 0x...; parent_hash: 0x09fcโ€ฆ3a2b; extrinsics (1): [0xae1aโ€ฆ0701]] +2022-05-05 13:25:23 ๐Ÿ”– Pre-sealed block for proposal at 1. Hash now 0x..., previously 0x.... +``` + +Congratulations! +You are running your own KILT blockchain. ๐ŸŽ‰ + +The blockchain exposes a RPC endpoint on port `9944`. +You can test that by calling an RPC endpoint using curl. + +```bash +curl -H "Content-Type: application/json" -d '{"id":1, "jsonrpc":"2.0", "method": "system_name", "params":[]}' http://127.0.0.1:9944/ +``` + +This should give you `{"jsonrpc":"2.0","result":"KILT Node","id":1}` as a response. + +The `--dev` parameter provides a pre-funded account which you can use as a faucet, and that has the following mnemonic: `receive clutch item involve chaos clutch furnace arrest claw isolate okay together`. + +You can create the account with the following SDK function: + +```ts +// Creates an ed25519 key by default which is required to access the funds. +const devFaucet = Crypto.makeKeypairFromUri(faucetSeed) +``` + +With the new `devFaucet`, you can transfer funds to other accounts and test all the KILT features that require tx fee payment. + +## Standalone vs. Parachain (Peregrine/Spiritnet) + +The standalone chain is close in functionality to Kilt parachains but there are a few fundamental differences between them. + + + +### Governance + +While governance is an important part of Kilt parachains, it's not used in the standalone version and the **Sudo** pallet replaces it. +None of the following pallets are part of the standalone chain, but they are all part of the parachain runtime: + +* Democracy +* Council +* TechnicalCommittee +* TechnicalMembership +* Treasury +* Scheduler + +### Staking + +Staking is part of the consensus protocol and is used to elect who is allowed to produce blocks. +Parachains need to have this election process as decentralized as possible. +On the other hand, for a standalone development chain, it's not necessary since all nodes are probably controlled by you or your organization. + +### Deployment Complexity + +Deploying a parachain is more complex than deploying a standalone chain. +For the standalone node, a single Docker command is enough. +In contrast, the task of spinning up a parachain is split into three steps. + +1. Setup a Relay Chain with 4 validators. +2. Start and connect your parachain node to the Relay Chain. +3. Register your parachain using the runtime WASM and the genesis state. + +Since these steps are not trivial to execute and take some time to do manually, you can use this [Docker-based setup script](https://github.com/KILTprotocol/local-parachain-setup) to automate the steps. + +### Transaction Encoding + +Before transactions are sent to the chain, they are encoded and signed. +The encoding depends on the runtime and can differ from chain to chain. +Even the same call in the same pallet can have a different encoding for different chains, for instance, the `vest`()` call of the `vesting` pallet: + +| Chain | Encoding of Vesting.vest() | +| ---------- | -------------------------- | +| Spiritnet | `0x2900` | +| Standalone | `0x2100` | diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/02_peregrine_setup.md b/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/02_peregrine_setup.md new file mode 100644 index 000000000..9d23c2544 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/02_peregrine_setup.md @@ -0,0 +1,21 @@ +--- +id: peregrine-chain-setup +title: Connect to Peregrine +--- + +Before connecting to the production Spiritnet, it is recommended to test applications using its canary network _Peregrine_. +In contrast to [running your own blockchain](./01_standalone_setup.md), you will neither have control over the blockchain, nor have any initial funds. + +In this section we will guide you through the process of receiving funds on Peregrine and connecting to one of the network nodes. +Additionally, we explain the difference between the Standalone and Parachain runtimes. + +## Receive Funds + +Since the native token of Peregrine, the _PILT_, does not have any economic value, you can request 100 PILT from the [Peregrine faucet](https://faucet.peregrine.kilt.io). + +## Connect to the Network + +Replace the WebSocket address of [your script](./index.md#set-up-your-project) or application with `wss://peregrine.kilt.io`. + +You can either use your own frontend or the [Polkadot JS Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine.kilt.io%2Fparachain-public-ws#/explorer) to interact with the chain. +For a full list of deployments and services, take a look [here](../../02_chain/03_deployments.md). diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/03_prod_chain_setup.md b/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/03_prod_chain_setup.md new file mode 100644 index 000000000..121c34335 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/03_prod_chain_setup.md @@ -0,0 +1,25 @@ +--- +id: prod-chain-setup +title: Connect to Spiritnet +--- + +For production setups it is important to run your own full node. +Running your own full node has several advantages over relying on a public full node. + +The most important advantage is security. +You rely on the full node to provide you with correct data. +When using a public full node, you rely on a third party: there is no 100% guarantee that the information returned is correct. + +Another important aspect when hosting a full node is availability. +Public full nodes typically do not come with a Service Level Agreement (SLA) and might go down for maintenance or are simply too slow. +With your own full node infrastructure, you can ensure that there is always enough capacity to serve your needs and your customers. + +In our [blockchain section](../../02_chain/01_introduction.md), you can find a [tutorial on how to run your own full node](../../02_chain/04_fullnode.md). + +## Connect to the Network + +Replace the WebSocket address of [your script](./index.md#set-up-your-project) or application with `wss://kilt-rpc.dwellir.com`. + +You can either use your own frontend or the [Polkadot JS Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkilt-rpc.dwellir.com/explorer) to interact with the chain. +Moreover, you can use [Subscan](https://spiritnet.subscan.io/) as a chain explorer. +For a full list of deployments and services, see [here](../../02_chain/03_deployments.md). diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/_category_.json b/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/_category_.json new file mode 100644 index 000000000..88da89b23 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Chain Setup for Development", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/index.md b/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/index.md new file mode 100644 index 000000000..76cb5d16e --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/03_chain_setup/index.md @@ -0,0 +1,24 @@ +--- +id: dev-chain-setup +title: Chain Setup for Development +--- + +If you want to develop solutions that integrate KILT, such as a dapp, a wallet, or a Web3 login, you will need a blockchain environment that can be used for development and testing without requiring you to buy actual KILT tokens. +For that purpose, you can either use the public KILT Peregrine testnet or run your own development blockchain. + +The **Peregrine** network is a parachain that is similar to Spiritnet (our mainnet) in functionality, but its coin, the PILT, doesn't hold any monetary value. +Any new features that we plan to add to our Spiritnet runtime will first undergo a testing period on Peregrine. +This gives developers like you the chance to test your software with any new features before they are available on Spiritnet. + +Nevertheless, there are a scenarios where a public network (that everyone else is also using) is not ideal. +For instance, if you need more funds than the faucet can provide, or if you need to reset the state of the blockchain at any time, you will need to setup your own little KILT blockchain. + +In this section, we will guide you through the process of +1. [Running your own KILT blockchain](./01_standalone_setup.md) +2. [Connecting to the Peregrine test network](./02_peregrine_setup.md) +3. [Connecting to the Spiritnet production network](./03_prod_chain_setup.md) + +## Set up your Project + +We expect you to already have a small project which can connect and potentially interact with a KILT blockchain given the WebSocket address of a KILT node. +If that is not the case, please take a look at our [Quickstart section](../01_quickstart.md) which will provide you with all necessary means to create and run a basic script. diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/01_nodejs.md b/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/01_nodejs.md new file mode 100644 index 000000000..57a4acf2e --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/01_nodejs.md @@ -0,0 +1,29 @@ +--- +id: howto-integrate-nodejs +title: NodeJS +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import QueryAccountName from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/03_account_web3name_query.ts'; + +NodeJS is natively supported and doesn't require any additional setup. + +Have a look at these example `package.json` and `index.js` files for reference: + +```json +{ + "name": "kilt-sdk-node-test", + "type": "module", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "@kiltprotocol/sdk-js": "0.35.0" + } +} +``` + + + {QueryAccountName} + diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/02_browser.md b/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/02_browser.md new file mode 100644 index 000000000..b0a291ec4 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/02_browser.md @@ -0,0 +1,45 @@ +--- +id: howto-integrate-browser +title: Browser +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Our JavaScript SDK (`@kiltprotocol/sdk-js`) is ready to be used in a browser context. For rapid prototyping of simple web apps, we provide a code bundle of the entire SDK which you can embed in a site by adding the following script tag: + +```html + +``` + +The SDK's functions then become available via a new `kilt` property on the global `window` object. + +To get started with your first **React application** using KILT, we recommend using either the [KILT Distillery](./03_distillery.md) CLI tool for bootstrapping or a framework like [Vite](https://vitejs.dev) or [Next.js](https://nextjs.org) that takes away some of the complexity in building and testing a React application. You can find a broader selection of popular React-powered frameworks on the [React project's homepage](https://react.dev/learn/start-a-new-react-project). + +After completing the respective tool's recommended steps to initialize your project, simply add the SDK to your dependencies and you are ready to hack away! + +:::info + +You should of course familiarize yourself with the tool of your choice, but these commands have served us well in the past: + + + +```bash +yarn create vite my-kilt-app --template react-ts +cd my-kilt-app +yarn add @kiltprotocol/sdk-js +``` + + + + +```bash +yarn create next-app my-kilt-app +cd my-kilt-app +yarn add @kiltprotocol/sdk-js +``` + + + + +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/03_distillery.md b/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/03_distillery.md new file mode 100644 index 000000000..f61dd9fb2 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/03_distillery.md @@ -0,0 +1,12 @@ +--- +id: howto-integrate-distillery +title: KILT Distillery +--- + +Different types of projects can be bootstrapped using our [KILT distillery CLI](https://github.com/KILTprotocol/kilt-distillery-cli). + +Please read the README.md file for more information, but if you are impatient you can execute this command and follow the instructions: + +```bash +npx git+https://github.com/KILTprotocol/kilt-distillery-cli +``` diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/_category_.json b/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/_category_.json new file mode 100644 index 000000000..6ca72770c --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Integrate the KILT SDK", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/index.md b/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/index.md new file mode 100644 index 000000000..bac181a29 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/04_integrate/index.md @@ -0,0 +1,11 @@ +--- +id: howto-integrate-index +title: How to Integrate +--- + +Integrating with KILT is easy. +If your project needs to integrate KILT in a frontend and/or a backend application, we've got you covered! + +These pages are dedicated to helping you set up a [NodeJS application](./01_nodejs.md) or [web app](./02_browser.md). + +We also introduce the [KILT distillery CLI tool](./03_distillery.md) which helps you quickly spin up your first KILT-based project. diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/05_troubleshoot.md b/versioned_docs/version-1.0.0/develop/01_sdk/05_troubleshoot.md new file mode 100644 index 000000000..369a3e616 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/05_troubleshoot.md @@ -0,0 +1,36 @@ +--- +id: troubleshoot-sdk +title: Troubleshoot +--- + +Solutions and workarounds for common or unresolved issues. + +## Webpack < 5 used to include polyfills + +``` +ERROR in ./node_modules/cbor/lib/commented.js 3:15-32 +Module not found: Error: Can't resolve 'stream' in 'node_modules/cbor/lib' + +BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default. +This is no longer the case. +Verify if you need this module and configure a polyfill for it. +``` + +### Solution + +The problem occurs because one of the dependecies you are using in your project (or used by a library you depend on) relies on NodeJS built-ins which are not available in a browser context. +You should aim to identify and replace these dependencies with browser-compatible alternatives. + +You might see the above error when using older versions of the KILT SDK with `create-react-app`. Make sure that you are using `@kiltprotocol/sdk-js` version 0.33.0 and above, which work in a browser context out-of-the-box. + +If the affected dependencies cannot be removed or replaced, you may need to look into setting up polyfills for the required NodeJS built-ins. + +## `redeclaration of import Buffer` + +``` +Uncaught SyntaxError: redeclaration of import Buffer +``` + +### Solution + +Your project might be using polyfills for the NodeJS built-in `Buffer`, which can cause conflicts with some polkadot-js libraries such as `@polkadot/react-identicon`. You can try upgrading the SDK and its dependencies to their latest versions. It's possible that upgrading will allow you to drop these polyfills from your configuration. diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/_category_.json b/versioned_docs/version-1.0.0/develop/01_sdk/_category_.json new file mode 100644 index 000000000..13d35e4e8 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/01_sdk/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "SDK", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/02_chain/01_introduction.md b/versioned_docs/version-1.0.0/develop/02_chain/01_introduction.md new file mode 100644 index 000000000..20b625490 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/02_chain/01_introduction.md @@ -0,0 +1,10 @@ +--- +id: introduction +title: Introduction +--- + +The section covers KILT chain specific topics. + +* Learn about the different [KILT pallets](./02_pallets/01_did.md) (still a WIP) +* Learn about the different [KILT deployments](./03_deployments.md) +* Learn how to run a [KILT full node](./04_fullnode.md) diff --git a/versioned_docs/version-1.0.0/develop/02_chain/02_pallets/01_did.md b/versioned_docs/version-1.0.0/develop/02_chain/02_pallets/01_did.md new file mode 100644 index 000000000..d0e8c3385 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/02_chain/02_pallets/01_did.md @@ -0,0 +1,115 @@ +--- +id: pallet-did +title: DID pallet +--- + +In KILT a DID is a decentralized identifier that the user owns and controls. +It consists of a unique set of keys that can be used for different operations on the blockchain. +For an in-depth explanation see the [KILT DID spec](https://github.com/KILTprotocol/kilt-did-driver/blob/master/docs/did-spec/spec.md). + +A DID may be a "light" DID, which is not stored on-chain, or a "full" on-chain DID. +A light DID is issued by default, with the keys stored locally on your device. +By upgrading this to a full DID registered on the blockchain, all the keys associated with it can be retrieved from the KILT blockchain storage. + +A full DID can then be used to perform certain on-chain actions which include: + +* Writing CTypes to the chain +* Writing attestations to the chain +* Setting delegations +* Doing key rotations on the DID keys + +## Register a Full DID + +A full DID is needed if the user wants to become an Attester or wants to setup delegations. +A full DID also allows the user to embed a list of URLs, known as services, into the DID document so that they can be retrieved from the chain as part of the DID document. +To create a full DID the user first has to create some keys, and optionally some services: + +* one authentication key for signing extrinsics from your DID +* zero or more key agreement keys for encrypting messages that are sent to you +* (optional) one attestation key for signing attestations +* (optional) one delegation key for authorizing delegations +* (optional) service that point to external hostings for others to find + +After the relevant components have been created, they are ready to write the DID to the KILT blockchain. +The user then has to create the `did::create` extrinsic and sign it with any KILT account that has enough funding to pay both the transaction fees and the DID deposit. +The extrinsic consists of + +* The `DidCreationDetails` object containing keys, services and the account id of the submitter for the creation +* The `DidSignature` which is a signature using your authentication key over the scale encoded `DidCreationDetails` from above +* A regular signature authenticating the sender of the extrinsic + +The DID owner and the submitter can be two different parties. +This allows the creation of a DID without having to pay any fees or deposits. +Beware that this also means that the DID creator gives up some power over the DID: The submitter who pays the deposit will be able to delete the DID from the blockchain and claim back its deposit. +Once the `did::create` extrinsic is submitted and executed, the DID is written to the chain. + +## Use a Full DID + +Once the DID is successfully registered on chain, it can be used to perform certain on-chain actions that are not possible to do with a regular account. +This includes the handling of attestations and CTypes, setting up trust hierarchies through delegations, managing web3names and much more. + +Those actions need to be signed by the DID before they can be submitted to chain by any account that the DID owner specifies when signing. +We are naming those actions "DID-Calls". +To submit those there is a special extrinsic called `submit_did_call`. + +The process of doing any DID-Call is always the same: + +* Construct the actual call you want to execute including all arguments of that extrinsic. +* Wrap the call in a `DidAuthorizedCallOperation` together with the + * Senders DID to indicate who wants this operation to happen + * Senders DID tx_counter + 1 to prevent replay attacks + * Current block number to prevent the operation being submitted too far in the future + * Account of the submitter to allow the DID owner to specify who is allowed to submit +* Create a signature over the `DidAuthorizedCallOperation` by scale-encoding it and signing it using the appropriate key + * Most operations require the authentication key of the DID to be used + * Managing Attestations requires the attestation key + * Managing Delegations requires the delegation key +* Construct the `submit_did_call` extrinsic consisting of + * The `DidAuthorizedCallOperation` + * The DID signature +* Pass the call over to the submitter who can now sign and submit it to the chain + * The submitter will have to pay for all fees and deposits that result from the operation + * In general the submitter will have the power to delete all on-chain objects to reclaim their deposit +* The chain now checks that + * The submitter's signature is correct + * The submitter is the one specified in the `DidAuthorizedCallOperation` + * The DID signature is correct + * The tx_counter is valid (current tx_counter + 1) + * The blocknumber is not older than an hour (given 12s block time) +* After that the actual call gets dispatched with a special `DidOrigin` + * This allows the executer of the actual call to get the DID and the account of the submitter + +## Update a Full DID + +There is a set of extrinsics available to update a full DID. +These are: + +* `set_authentication_key` +* `set_delegation_key` +* `remove_delegation_key` +* `set_attestation_key` +* `remove_attestation_key` +* `add_key_agreement_key` +* `remove_key_agreement_key` +* `add_service_endpoint` +* `remove_service_endpoint` +* `delete` + +All of them have to be authenticated using the DID that is updated following the process described above. + +## What About the Deposit? + +When writing a DID to the chain the submitter of the extrinsic has to pay a deposit. +The base deposit is currently 2 KILT. +For additional used storage, for example by adding more services, more tokens are taken as deposit, depending on the amount of additional storage taken. +Freeing up storage reduces the deposit. +This is to incentivize deleting unused DIDs or keys to reduce the total storage of the chain. +The deposit is always bound to the account that submitted the extrinsic to create the DID, and not to the DID itself. +Consequently there are also two ways of reclaiming the deposit: + +1) The DID owner decides to delete the DID using the `did::delete` extrinsic. + This call needs to be authorized by the DID and can therefore be submitted by any account. + Despite the fact that this account can differ from the deposit owner, the deposit will always be reimbursed to the account that paid for it. +2) The deposit owner can decide to claim their deposit back using the `did::reclaim_deposit` extrinsic. + This will also cause the DID to be fully deleted but it doesn't require a signature from the DID. + Only the signature of the account that created the DID is needed for this. diff --git a/versioned_docs/version-1.0.0/develop/02_chain/02_pallets/_category_.json b/versioned_docs/version-1.0.0/develop/02_chain/02_pallets/_category_.json new file mode 100644 index 000000000..fd547d13d --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/02_chain/02_pallets/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "KILT Pallets", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/02_chain/03_deployments.md b/versioned_docs/version-1.0.0/develop/02_chain/03_deployments.md new file mode 100644 index 000000000..e1ae294c1 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/02_chain/03_deployments.md @@ -0,0 +1,32 @@ +--- +id: deployments +title: Deployments and Services +--- + +KILT has two public deployments: a production one, called **Spiritnet**, and a test/dev one, called **Peregrine**. +To learn more about how to set up a node for either environment, please check our [fullnode set up guide](./04_fullnode.md). + +**Spiritnet** is the production blockchain, and has been live since September 2021. + +**Peregrine** is the public testnet, which can be used to build and test products that use the KILT blockchain, before switching to Spiritnet. + +| Service | Spiritnet | Peregrine | +| :--------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------: | +| Faucet | - | [Peregrine Faucet][pere-faucet] | +| Public Endpoints | [BOTLabs: wss://spiritnet.kilt.io][spirit-wss-kilt]
[OnFinality: wss://spiritnet.api.onfinality.io/public-ws][spirit-wss-onfinality]
[Dwellir: wss://kilt-rpc.dwellir.com][spirit-wss-dwellir] | [BOTLabs: wss://peregrine.kilt.io][pere-wss-kilt] | +| Wallet | [Sporran](https://www.sporran.org/) | [GitHub](https://github.com/BTE-Trusted-Entity/sporran-extension/releases) (manual loading into the browser) | +| Staking UI | Collators' performance (view only): [Stakekilt](https://stakekilt.com/)
Delegation staking platform: [Stakeboard](https://stakeboard.kilt.io) | - | +| Governance UI | [Polkassembly][spirit-polkassembly] | - | +| Chain Explorer | [Subscan](https://spiritnet.subscan.io) | - | +| w3n Service | [w3n.id](https://w3n.id) | [test.w3n.id](https://test.w3n.id/) | +| Link Accounts | [linking.trusted-entity.io](https://linking.trusted-entity.io/) | [test.linking.trusted-entity.io](https://test.linking.trusted-entity.io/) | +| DIDsign | [didsign.io](https://didsign.io/) | [test.didsign.io](https://test.didsign.io/) | +| SocialKYC | [socialkyc.io](https://socialkyc.io/) | [test.socialkyc.io](https://test.socialkyc.io/) | + + +[spirit-polkassembly]: https://kilt.polkassembly.network +[spirit-wss-kilt]: https://polkadot.js.org/apps/?rpc=wss://spiritnet.kilt.io +[spirit-wss-onfinality]: https://polkadot.js.org/apps/?rpc=wss://spiritnet.api.onfinality.io/public-ws +[spirit-wss-dwellir]: https://polkadot.js.org/apps/?rpc=wss://kilt-rpc.dwellir.com +[pere-faucet]: https://faucet.peregrine.kilt.io +[pere-wss-kilt]: https://polkadot.js.org/apps/?rpc=wss://peregrine.kilt.io diff --git a/versioned_docs/version-1.0.0/develop/02_chain/04_fullnode.md b/versioned_docs/version-1.0.0/develop/02_chain/04_fullnode.md new file mode 100644 index 000000000..80264abf7 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/02_chain/04_fullnode.md @@ -0,0 +1,227 @@ +--- +id: fullnode-setup +title: Set Up a KILT Full Node +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +We will guide you through the process of setting up and connecting to a KILT full node. +In contrast [to a collator](../../participate/01_staking/01_become_a_collator/03_setup_node.md), full nodes do not author blocks. +They act as a backend for websites and help to verify new blocks or validate extrinsics (e.g., coin transfers and other transactions) directly on the network without relying on a centralized infrastructure provider. + +## Setup + +There are currently two different runtimes (i.e., two different parachain environments) that a KILT full node can be part of: + +- **Spiritnet**: the official public network, which contains only stable and thoroughly-tested features +- **Peregrine**: the public test network whose runtime is as close to that of Spiritnet as possible. It can be used to test applications that use KILT before connecting them to the production Spiritnet chain, which requires tokens that have real monetary value + +Each runtime has its own benchmark measurements. + +:::info +The remainder of this guide will focus on the official **Spiritnet**. +Nevertheless, we recommend trying out the setup on our Peregrine testnet first. +Hence, at each step where it is applicable, we indicate what differs between the Peregrine and Spiritnet configuration for the full node to join either network. +::: + +### WASM Runtime Execution + +A KILT full node should use the `--execution=wasm` parameter for both the Relay Chain and parachain collation. +The alternative to WASM runtime execution is native runtime execution, which might be faster but can, in some cases, deviate from the WASM execution logic and result in a different state. +When this happens, the full node will crash and will stop synchronizing with the network. +Since the WASM runtime logic is part of the blockchain state itself and hence represents the single source of truth, all nodes should execute the WASM version of the runtime logic. + +### Specify the Right Chainspec + +The `--chain` parameter indicates which blockchain the KILT full node will join. +This parameter must be specified for both the parachain **and** the Relay Chain, since both chains are, as a matter of fact, separate blockchains. +The KILT parachain accepts an additional parameter to select the environment to use for the WASM runtime execution. +This can either be `peregrine` or `spiritnet`. + +Hence, to start a full node for the Spiritnet network, the parameter would be `--chain=spiritnet`. +Unfortunately, there is no hardcoded chain spec for the Peregrine network, so the full path of the chainspec file must be provided `--chain=/node/dev-specs/kilt-parachain/peregrine-kilt.json`. +Please refer to the [KILT node repository](https://github.com/KILTprotocol/kilt-node/blob/master/chainspecs/peregrine/peregrine-paseo.json) or the [Docker image](https://hub.docker.com/r/kiltprotocol/kilt-node/tags) for more information. + +### Specify the Blockchain Storage Path + +The `--base-path` parameter specifies where all the persistent files must be stored. +By default, the session keys will also be stored in the *base path*, but we recommend separating them from the other files. +This makes sure that the keyfiles are not accidentally lost or published when the blockchain database is either backed up or restored. +You can configure where to store the session keys using the `--keystore-path` option. +Since the collator will collate only for the parachain, there is no need to add this to the Relay Chain part of the command. + +## Join the Network + + + + + +### Build the Full Node + +In order to build the KILT full node executable, you need to have [rustup and Rust installed](https://www.rust-lang.org/tools/install). +After cloning the repository, you can build the executable by running the `cargo build` command below from the root directory. + +```bash +# Clone the repository +git clone https://github.com/KILTprotocol/kilt-node.git +# Check out master branch +git checkout master +# Build the executable from source enabling all the optimizations with --release. +cargo build --release -p kilt-parachain +``` + +:::info +You must not use the default `develop` branch to build the executable. +Instead, the [latest release](https://github.com/KILTprotocol/kilt-node/releases) from `master` should be used. +::: + +The compiled executable can be found in `./target/release/kilt-parachain` after the build process completes successfully. + +### Run an Archive Node + +To run an Archive full node, add the option `--pruning archive` to the command. + + + + + +```bash +./target/release/kilt-parachain \ + --chain=spiritnet \ + --runtime=spiritnet \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-external \ + --name="name of full node" \ + --execution=wasm \ + --pruning archive \ + -- \ + --chain=polkadot \ + --execution=wasm +``` + + + + +```bash +./target/release/kilt-parachain \ + --chain=/node/dev-specs/kilt-parachain/peregrine-kilt.json \ + --runtime=peregrine \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-external \ + --name="name of full node" \ + --execution=wasm \ + --pruning archive \ + -- \ + --chain=/node/dev-specs/kilt-parachain/peregrine-relay.json \ + --execution=wasm +``` + + + + + + + +### Run an Archive Node + +The full node can also be started as a Docker container. +To expose the WebSockets ensure that the `--rpc-external` flags is set. + +To run an Archive full node add the option `--pruning archive` to the command. + +First, you can fetch the latest pre-built image: + +```bash +docker pull kiltprotocol/kilt-node:latest +``` + +Once you have the image, you can spin up the container. +Make sure to choose whether you want to start a full node for Peregrine or Spiritnet by selecting the correct runtime and chain. + + + + + +```bash +docker run -v kilt-node-data:/data kiltprotocol/kilt-node:latest \ + --base-path=/data/para \ + --chain=spiritnet \ + --runtime=spiritnet \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-external \ + --name="name of full node" \ + --execution=wasm \ + --pruning archive \ + -- \ + --base-path=/data/relay \ + --chain=polkadot \ + --execution=wasm +``` + + + + +```bash +docker run -v kilt-node-data:/data kiltprotocol/kilt-node:latest \ + --base-path=/data/para \ + --chain=/node/dev-specs/kilt-parachain/peregrine-kilt.json \ + --runtime=peregrine \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-external \ + --name="name of full node" \ + --execution=wasm \ + --pruning archive \ + -- \ + --base-path=/data/relay \ + --chain=/node/dev-specs/kilt-parachain/peregrine-relay.json \ + --execution=wasm +``` + + + + + + + +## Sync the Blockchain State + +Once started, the full node needs to fully sync up with both the parachain and the Relay Chain states. +Depending on the size of both blockchain states and the node hardware specs, it may take from a number of hours to a few days for the node to fully synchronize. +More details can be found in the [Polkadot network documentation](https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#synchronize-chain-data). + +:::note Example of node sync + +```Example of node sync +2021-06-17 02:34:34 ๐Ÿ” Discovered new external address for our node: /ip4/100.102.231.64/tcp/30333/ws/p2p/12D3KooWLE7ivpuXJQpFVP4fuuutAqEsk8nrNEpuR3tddqnXgLPB +2021-06-17 02:34:36 โš™๏ธ Syncing 409.2 bps, target=#8062689 (5 peers), best: #3477 (0x63adโ€ฆe046), finalized #3072 (0x0e4cโ€ฆf587), โฌ‡ 153.2kiB/s โฌ† 12.9kiB/s +2021-06-17 02:34:37 ๐Ÿ” Discovered new external address for our node: /ip4/100.111.175.0/tcp/30333/ws/p2p/12D3KooWLE7ivpuXJQpFVP4fuuutAqEsk8nrNEpuR3tddqnXgLPB +2021-06-17 02:34:38 ๐Ÿ” Discovered new external address for our node: /ip4/100.100.176.0/tcp/30333/ws/p2p/12D3KooWLE7ivpuXJQpFVP4fuuutAqEsk8nrNEpuR3tddqnXgLPB +2021-06-17 02:34:41 โš™๏ธ Syncing 386.2 bps, target=#8062690 (7 peers), best: #5409 (0x1d76โ€ฆ8c3d), finalized #5121 (0x8ad1โ€ฆb6dc), โฌ‡ 96.1kiB/s โฌ† 10.9kiB/s +2021-06-17 02:34:46 โš™๏ธ Syncing 394.8 bps, target=#8062691 (11 peers), best: #7383 (0x0689โ€ฆ6f1e), finalized #7168 (0x72a9โ€ฆ8d8c), โฌ‡ 352.9kiB/s โฌ† 5.1kiB/s +2021-06-17 02:34:51 โš™๏ธ Syncing 347.0 bps, target=#8062692 (12 peers), best: #9118 (0x66fcโ€ฆcce3), finalized #8704 (0x14c9โ€ฆ705e), โฌ‡ 62.7kiB/s โฌ† 1.7kiB/s +``` + +::: diff --git a/versioned_docs/version-1.0.0/develop/02_chain/_category_.json b/versioned_docs/version-1.0.0/develop/02_chain/_category_.json new file mode 100644 index 000000000..1b41abda0 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/02_chain/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Chain", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/01_welcome.md b/versioned_docs/version-1.0.0/develop/03_workshop/01_welcome.md new file mode 100644 index 000000000..6ed35f2f3 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/01_welcome.md @@ -0,0 +1,38 @@ +--- +id: welcome +title: ๐Ÿ‘‹๐Ÿป Welcome +--- + + + + +SDK version **0.35.0**. + +:::info What you can expect to learn + +๐Ÿ“ฆ **Topics**: [KILT SDK](https://github.com/KILTprotocol/sdk-js) essentials, basic credential workflow. +This includes creating a CType and a claim, attesting a claim, and finally verifying the credential. + +โณ **Duration**: 15-45 minutes. + +๐Ÿค“ **Prerequisites**: + +- Basic JavaScript or TypeScript knowledge. +- [Node.js](https://nodejs.org/) installed. Any stable LTS version >= 16.0. + +โ“ **Questions?** Join our [developer community channel](https://discord.gg/hX4pc8rdHS)! + +::: + +## Welcome, curious mind! + +In this tutorial, you will: + +โœ” Get familiar with the essential concepts in KILT: accounts, DIDs, CTypes, claims, credentials, and more. + +โœ” Use the KILT SDK to implement the basic flow of a KILT claim, from creation until verification. +You'll create a claim as a Claimer, attest it as an Attester and verify it as a Verifier. + +โœ” Use the KILT SDK to write onto and read from the KILT blockchain. + +Ready? Let's go! \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/02_setup.md b/versioned_docs/version-1.0.0/develop/03_workshop/02_setup.md new file mode 100644 index 000000000..c63d7c19e --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/02_setup.md @@ -0,0 +1,108 @@ +--- +id: setup +title: ๐ŸŽ’ Setup +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Project setup + +Create a new project in a fresh directory and navigate into it by running `mkdir kilt-rocks && cd kilt-rocks`. + + + +The dependencies needed are the following: + +- [KILT SDK-JS](https://github.com/KILTprotocol/sdk-js#readme) - for KILT functionality +- [dotenv](https://github.com/motdotla/dotenv#readme) - to load environment variables +- If you use Typescript and not JavaScript [ts-node](https://www.npmjs.com/package/ts-node) and [Typescript](https://www.typescriptlang.org/) - to execute TS code + + + + + Initialize the project and install dependencies. + + ```bash npm2yarn + npm init -y + npm install @kiltprotocol/sdk-js dotenv ts-node typescript + ``` + + + + + Initialize the project and install dependencies. + + ```bash npm2yarn + npm init -y + npm install @kiltprotocol/sdk-js dotenv + ``` + + + + +## Project Folder + + + + + Create the following remaining files and folders to end up with the folder structure below: + + ``` + โ””โ”€ kilt-rocks/ # project + โ”œโ”€ attester/ # all attester code + โ”œโ”€ claimer/ # all claimer code + โ”œโ”€ verify.ts # all verifier code + โ””โ”€ .env # environment variables + ``` + ``` + mkdir attester claimer && touch verify.ts .env + ``` + + + + + + Create the following remaining files and folders to end up with the folder structure below: + + ``` + โ””โ”€ kilt-rocks/ # project + โ”œโ”€ attester/ # all attester code + โ”œโ”€ claimer/ # all claimer code + โ”œโ”€ verify.js # all verifier code + โ””โ”€ .env # environment variables + ``` + ``` + mkdir attester claimer && touch verify.js .env + ``` + + + + +## PILT Tokens + +This workshop interacts with the Peregrine test blockchain, which requires you to pay for each transaction with Peregrine Kilt (PILT) tokens. + +But don't worry. PILT tokens have no value, and you can request them from the [faucet](https://faucet.peregrine.kilt.io). + +## Blockchain Connection + +Before using any SDK functionality, you must initialize and configure the Kilt SDK. + +As this workshop uses the [Peregrine Testnet](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine.kilt.io%2Fparachain-public-ws%2F#/explorer) you use its address whenever using the SDK to interact with the Kilt blockchain. + +You do this by calling the following function: + +```JavaScript +await Kilt.connect({address}) +``` + +Where `address` is the address of the full node you want to connect to, which for this workshop, is `wss://peregrine.kilt.io`. + +For convenience, add the address to the `.env` file. + +```env title=".env" +WSS_ADDRESS=wss://peregrine.kilt.io +``` + +That's it for the basic setup - You're good to go! \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/03_overview.md b/versioned_docs/version-1.0.0/develop/03_workshop/03_overview.md new file mode 100644 index 000000000..bcb80e36d --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/03_overview.md @@ -0,0 +1,96 @@ +--- +id: overview +title: ๐Ÿ‘“ Overview +--- + +This tutorial runs through the full story of a claim. + +It involves three actors which work together to create **distributed trust**: + +- A Claimer is an actor who claims to possess certain credentials, abilities, or other attributes. +- An Attester is an actor that verifies the claims of a Claimer. +- A Verifier is an actor that asks for proof of a claim. + +For the workshop, you play all three roles. + +In a real-world use case, these actors would be different people and services, which this workshop simulates using different folders for each service. +Each actor typically performs different roles: + +- Both the Verifier and the Attester have to interact with the KILT blockchain. +- But only the Attester is required to own KILTs since they have to pay for storing the attestation on chain. +- The Verifier only needs to query the KILT blockchain to ensure that the attestation is still valid and was not revoked. +- The Claimer is not required to query the blockchain, but they might do so to check whether their credential is still valid or if the Attester has revoked it in the meantime. + +## Request an Attestation + +Before the Claimer can attest a credential, they need to generate a [light DID](../01_sdk/02_cookbook/01_dids/01_light_did_creation.md), which can happen off-chain. + +The Attester has to register their DID on chain and needs KILT coins. + +After both the Attester and the Claimer have set up their identities, the Claimer can start the attestation process by requesting an attestation from the Attester. + +```mermaid +sequenceDiagram +actor C as Claimer +actor A as Attester +participant B as KILT Blockchain + C->>+C: Create credential from provided claims + C->>+A: Transmit credential to request attestation + A->>A: Validate received attributes + A->>+B: Store attestation + B-->>-A: Attestation hash + A-->>-C: Attestation Hash +``` + +1. The Claimer prepares the Credential to attest, along with some proof, for example, a bank statement and ID. +2. They send the document to the Attester for attestation. +3. Upon receiving the credential, the Attester decides whether the claim is valid by examining the proofs. If the Attester trusts the claim, they store the attestation document's hash value on the chain, which is a non-functional copy of the document. +4. The Attester sends this hash value to the Claimer, which represents verification of a document. + +## Verify an Attestation + +The Verifier requests a presentation from the Claimer for a specific required CType. Without a specific CType, the presentation is meaningless. + + + +A presentation is derived from a credential and does not need to contain all attributes. + +After the request, the Claimer can choose to hide elements of their credentials that aren't relevant to the claim. +For example, hide their address from their ID if the Verifier is only interested in their age. + +:::info + +A later step in the workshop [explains CTypes in more detail](./04_attester/03_ctype.md). + +::: + +```mermaid +sequenceDiagram +actor C as Claimer +actor V as Verifier +participant B as KILT Blockchain + V->>+C: Request presentation for CType + C->>C: Derive a presentation from a credential + C-->>-V: submit presentation + V->>B: check validity of presentation +``` + +### Example: Requesting a travel visa + +To take an example of applying for a travel visa: + +1. The Embassy (analogous to the Verifier) asks a traveler (analogous to the Claimer) for a specific document or CType. For example, it could be a bank statement. The Embassy asks, "Provide proof of financial stability, and we'll grant you a visa." The traveler gets the bank statement from their bank, gets it attested by the bank (The Attester), and prepares the document. +2. The document is ready, but the Embassy doesn't need all the information in the document. The embassy wants to know if a traveler has sufficient funds, but they don't need to know any transaction details. The traveler redacts or hides these details while presenting. +3. The traveler presents the document to the embassy. +4. The embassy verified the document's authenticity by comparing its hash value with the one on their internal system or a decentralized ledger. +5. Since they trust the Attester (in this case, the bank that attested the bank statement), they approved the visa application. + +:::tip Summary + +As you can see, the Embassy didn't need to trust the Claimer directly in this system. +They trust the Attester, whom they had previously worked with, or respect due to their position. +And with that trust, they grant the visa with no knowledge of what the Claimer has used the credential for. +Even though this process emerged due to the trust in the Attester, the Attester was not involved in the second stage, so they were unaware of it. +Privacy was achieved with distributed trust. + +::: \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/01_account.md b/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/01_account.md new file mode 100644 index 000000000..e2710f623 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/01_account.md @@ -0,0 +1,111 @@ +--- +id: account +title: Account +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import GenerateAccount from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/attester/generateAccount.ts'; + +With the [project structure setup](./) in the last step, you can create your Attester account. + +With KILT, an account is an object that interacts with the blockchain. + +:::info KILT Account + +A KILT account is a set of cryptographic elements: + +- The address, generated from the public key, is the entity's unique and public on-chain identifier, used to pay fees and deposits. +- A signing key pair to write transactions on-chain + +::: + +To create an account, you need a mnemonic. + +:::info Mnemonic + +In cryptography, a mnemonic consists of a series of 12 or 24 random words. + +For example, `waste frown beach save hidden bar inmate oil mind member junk famous` is a mnemonic. + +You use a mnemonic to generate signing key pairs. +What's great about a mnemonic is that it's **human-readable**, and a person could memorize it to later re-generate their key pairs and address. +A mnemonic is critical for security, so it's crucial to keep it safe! + +::: + +## Create the Account + +To generate an account, use the `addFromMnemonic()` function on the [`KiltKeyringPair`](https://kiltprotocol.github.io/sdk-js/interfaces/types_src.KiltKeyringPair.html) interface of the SDK. +The function uses the underlying polkadot `mnemonicGenerate()` function to generate a 12-word mnemonic. + +:::info polkadot.js + +The KILT SDK is built on top of the [polkadot.js](https://polkadot.js.org/) library, so this workshop uses several functions from the library. + +The library provides tools to interact with the KILT blockchain and other Substrate-based blockchains. + +In addition, the polkadot.js library offers cryptographic primitives and a serialization framework to encode/decode data sent to and received from the blockchain. +Read the [API documentation](https://polkadot.js.org/docs/) to learn more about the functions available. + +::: + +Add the following code to the `generateAccount` file. + + + {GenerateAccount} + + +The `generateAccount` method returns an object with the following two properties: + +- A key `account` with the type `Kilt.KiltKeyringPair`. +- A key `mnemonic` with the type `string`. + +Generating these values takes two steps: + +1. Create the `mnemonic` value using the `mnemonicGenerate()` method from the `Utils.Crypto` package. +2. The `account` value first needs a `keyring` value defined, which is a data structure for defining the key pair type. This example uses `ed25519`, but `sr25519` or `ecdsa` are also valid. + +The function then returns the value using the `makeKeypairFromUri()` method to create a key pair for the address using the given mnemonic. + +The rest of the code runs the `generateAccount` function and logs the results to the console. + +## Run code + +Run the code above to receive your Attester `
` and ``. + + + + +```bash +yarn ts-node ./attester/generateAccount.ts +``` + + + + +```bash +node ./attester/generateAccount.js +``` + + + + +The output provides you with an `ATTESTER_ACCOUNT_MNEMONIC` and `ATTESTER_ACCOUNT_ADDRESS`. +Save both values in your `.env` file, which should look similar to the below. + +```env title=".env" +WSS_ADDRESS=wss://peregrine.kilt.io + +ATTESTER_ACCOUNT_MNEMONIC="warrior icon use cry..." +ATTESTER_ACCOUNT_ADDRESS="4ohMvUHsyeDhMVZF..." +``` + +:::warning Get PILT coins! + +You now have a blockchain account to use to pay fees and deposits. +If you haven't already requested PILT, go to the [faucet](https://faucet.peregrine.kilt.io) and request tokens for your `
`. + +::: diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/02_did.md b/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/02_did.md new file mode 100644 index 000000000..fa4bc03cd --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/02_did.md @@ -0,0 +1,139 @@ +--- +id: did +title: DID +--- + +import CodeBlock from '@theme/CodeBlock'; +import TsJsBlock from '@site/src/components/TsJsBlock'; +import SnippetBlock from '@site/src/components/SnippetBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import GenerateKeypairs from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/attester/generateKeypairs.ts'; +import GenerateDid from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/attester/generateDid.ts'; + +The next step is to generate a KILT decentralized identifier (DID) using the account you created for the Attester in [the previous step](./01_account.md). + +A DID may represent any entity, such as a person, an organization, or a machine. + +A DID is a string uniquely identifying each KILT user. +You can store information about a DID on the KILT chain, which is useful for different use cases. + +One use case is messaging. +You could store a public encryption key and a service on chain, and a user can query both using a DID. +Other users can now encrypt messages using your public encryption key and send a message to your service. + +## Light and full DIDs + +Kilt supports two DID types: **light** and **full**. + +There are differences between the two types, but the most crucial is that you can use a light DID offline, but a full DID needs access to the blockchain to work. +Read the [DID documentation](../../../develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md) to learn more about the difference between the light and full types. + +:::info KILT DID + +A DID supports four different key types: + +- An _authentication key pair_, used to sign claims and present authenticated credentials +- A _key-agreement key pair_, used to encrypt/decrypt messages +- An _assertion-method key pair_, used to write CTypes and attestations on chain +- A _capability-delegation key pair_, used to write delegations on chain + +You can replace keys over time, e.g., if a key becomes compromised. + +::: + +## What's the difference between a DID and an account? + +A DID and an account sound quite similar, but there are some differences: + +- You record both to chain +- You can have a DID without an account +- You can have an account without a DID +- Only an account can pay deposits and fees and attest claims +- DIDs don't hold any coins + +In summary, you register a DID on the blockchain by an account submitting the DID creation transaction and paying the fees. + +## Create a DID + +As an Attester needs to interact with the chain, you must create a full DID. + +### Write DID to chain + +The KILT SDK provides multiple methods to create DIDs, this workshop highlights the `createFromAccount` method, that creates a DID from any pre-existing substrate-compatible account. + + + + +:::info Bring your own account + +This workshop assumes you followed the [create account step](./01_account.md), but if you have a pre-existing account, you can use that instead. + +::: + +Create and submit the extrinsic (aka transaction) that registers the DID. + + + {GenerateDid} + + +The `publicKeyToChain` helper method returns a public key of the correct type. + +The `txs` array holds the two transactions containing the extrinsics needed to submit to the chain for the Attester's DID creation. + +The `createFromAccount` method takes the authenticated key of the account to attach the DID to, and the `setAttestationKey` method takes the same parameter to set the attestation key the DID needs and uses. + +An Attester account needs to have an attestation key to write CTypes and attestations on chain. Use the `setAttestationKey` method to set this. For this example transaction, the Attester account uses the `dispatchAs` proxy method to assign the attestation key to the same account. However, you can also use this method to assign the attestation key to another account. + +The `signAndSubmitTx` method then takes those transactions and submits them as a batch to the chain. + +## Run the code + +Now run the code with: + + + + + ```bash + yarn ts-node ./attester/generateDid.ts + ``` + + + + + ```bash + node ./attester/generateDid.js + ``` + + + + +Once you have run the script, the output should provide you with the `ATTESTER_DID_URI`. + +The output should look like the following, but not identical since the code creates the DIDs from your account: + +``` +ATTESTER_DID_URI="did:kilt:4ohMvUHsyeDโ€ฆ" +``` + +Save the values in the `.env` file, which should now look like the following: + +```env title=".env" +WSS_ADDRESS=wss://peregrine.kilt.io + +ATTESTER_ACCOUNT_MNEMONIC="warrior icon use cry... +ATTESTER_ACCOUNT_ADDRESS=4ohMvUHsyeDhMVZF... +ATTESTER_DID_URI="did:kilt:4ohMvUHsyeD..." +``` + +Well done - You've generated a full DID! The next step is to create a CType! + +## Generate Keys + +Add the following code to the `generateKeypairs` file. + + + {GenerateKeypairs} + + diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/03_ctype.md b/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/03_ctype.md new file mode 100644 index 000000000..417885275 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/03_ctype.md @@ -0,0 +1,120 @@ +--- +id: ctype +title: CType +--- + +import CodeBlock from '@theme/CodeBlock'; +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import CtypeSchema from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/attester/ctypeSchema.ts'; +import GenerateCtype from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/attester/generateCtype.ts'; + + +import Ctype from '@site/scripts/out/ctype.json.raw!=!raw-loader!@site/scripts/out/ctype.json'; + +A claim type (CType) is a KILT-specific term, but the concept is simple: +A CType is a JSON schema that defines the structure of a claim, and you can think of it as the data model for your claim. + +:::info CType + +A CType ensures that a credential contains all required attributes, e.g., a driver's license has to contain a name, date of birth, and the vehicle types that the claimer can drive. +The CType is important since a Verifier requests credentials for a specific CType. +For example, the traffic police want to see your driver's license, not your gym membership. + +To learn more about CTypes, read the [in-depth CType documentation](../../../concepts/05_credentials/02_ctypes.md). +You can also [read through existing CTypes in the CType-index](https://github.com/KILTprotocol/ctype-index). +::: + +Before the Attester can attest credentials, they must decide which CType they support. +For example, a traffic authority only issues driver's licenses (A CType for driver's license), not a university diploma. + +Since CTypes enable interoperability between Attesters, using existing CTypes rather than creating new ones is highly recommended. +However, this workshop creates a new CType to show the process. + +Creating CTypes requires an account and a full DID. +Make sure your account holds KILT tokens so that you can pay the fees for creating a CType. + +For example, a basic CType for a driver's license could look like this: + + + {Ctype} + + +The CType has the following attributes: + +| Key | Value | +| -------------| ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `$id` | The KILT id of this CType. It's the most important property as it represents the **digital footprint** of the CType. | +| `$schema` | A reference to the meta-schema describing what a CType may look like. There are two versions. | +| `title` | The title of the CType. | +| `properties` | The properties that a claim conforming to this CType may have. | +| `type` | Type is an object for all CTypes. | +| `additionalProperties` | The default is false. This restricts unwanted properties in a claim. | + +A CType is stored on the KILT blockchain. + +In a real-world situation, a user would retrieve an existing CType from the chain or a CType registry. +For example, via a Credential Registry's REST API. + +In this tutorial, the Attester creates and attempts to store a CType on the KILT test blockchain. + +## Create CType + +Copy the following to define a `CType` with a given schema: + + + {CtypeSchema} + + +:::warning + +As many people follow this workshop, using the CType schema defined above will result in a duplicate error when you run the code later. +To avoid this, change the value of `fromProperties` to something unique, such as adding your name to the "Drivers License" string. + +::: + +## Get CType + +Copy the following to create a `CType` on the chain: + + + {GenerateCtype} + + +The `ensureStoredCType` function takes the Attester's account, DID, and a callback to sign the function and checks if the CType is already on chain. +It uses the `verifyStored` method to pass the CType to the KILT blockchain and make the check. +If it does not exist, it stores it on chain, using the `toChain` method to encode the CType into a unique hash and the `add` method to create a new CType from the given unique hash and associate it with the Attester. +The function then uses the `authorizeTx` to authorize the transaction and `signAndSubmitTx` to sign and submit the transaction containing the new CType. + +:::warning + +Remember, an account must have the required amount of tokens to pay the transaction fee and deposit. + +::: + +## Run + + + + + Run the `attester/generateCtype.ts` file. + + ```bash + yarn ts-node attester/generateCtype.ts + ``` + + + + + Run the `attester/generateCtype.js` file. + + ```bash + node attester/generateCtype.js + ``` + + + + +Before you can attest Credentials, you need a Claimer to request it diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/_category_.json b/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/_category_.json new file mode 100644 index 000000000..6c31a6f8e --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "๐Ÿข Attester", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/index.md b/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/index.md new file mode 100644 index 000000000..5da9f6d70 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/04_attester/index.md @@ -0,0 +1,59 @@ +--- +id: attester +title: ๐Ÿข Attester +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This section of the workshop covers creating the Attester code. The steps are the following: + +1. [Create an account](./01_account.md) to pay for all transactions and storage deposits. +2. [Create a DID](./02_did.md), which is the identity used to create attestations. + + While you can always switch the KILT account and pay deposits and fees with any account you like, your DID stays the same and is the way Claimers identify and trust you. + +1. Before you can attest claims, [you need a CType](./03_ctype.md) that describes and gives context to what you attest. +2. Once you have a way to pay fees and deposits, have an identity, and a CType, [you can create attestations](../06_attestation.md). + +## Folder Structure + +Create the following files in the `attester` folder. +These folders mimic an Attester service. + + + + + ```bash + โ””โ”€ kilt-rocks/ # project + โ””โ”€ attester/ # all attester code + โ”œโ”€ attestCredential.ts # issues attestations + โ”œโ”€ ctypeSchema.ts # create a local CType definition + โ”œโ”€ generateAccount.ts # functions for setting up and loading the attester's account + โ”œโ”€ generateCtype.ts # register the CType on chain + โ”œโ”€ generateDid.ts # registers the attester's on-chain DID + โ””โ”€ generateKeypairs.ts # setup the keys for the attester's DID + ``` + ```bash + cd attester && touch attestCredential.ts ctypeSchema.ts generateAccount.ts generateCtype.ts generateDid.ts generateKeypairs.ts && cd .. + ``` + + + + ```bash + โ””โ”€ kilt-rocks/ # project + โ””โ”€ attester/ # all attester code + โ”œโ”€ attestCredential.js # issues attestations + โ”œโ”€ ctypeSchema.js # create a local CType definition + โ”œโ”€ generateAccount.js # functions for setting up and loading the attester's account + โ”œโ”€ generateCtype.js # register the CType on chain + โ”œโ”€ generateDid.js # registers the attester's on-chain DID + โ””โ”€ generateKeypairs.js # setup the keys for the attester's DID + ``` + + ```bash + cd attester && touch attestCredential.js ctypeSchema.js generateAccount.js generateCtype.js generateDid.js generateKeypairs.js && cd .. + ``` + + + diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/01_did.md b/versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/01_did.md new file mode 100644 index 000000000..e6abbde43 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/01_did.md @@ -0,0 +1,75 @@ +--- +id: did +title: DID +--- + +import CodeBlock from '@theme/CodeBlock'; +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import GenerateKeypairs from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/claimer/generateKeypairs.ts'; +import GenerateLightDid from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/claimer/generateLightDid.ts'; + +This section covers creating a light DID using the account you created for the Claimer. + +Since a light DID is not registered on the blockchain, you don't need funds to create one. + +:::info + +Remember, light DIDs can do the following: + +- Sign attestation requests and presentation with the authentication keys +- Encrypt messages with the encryption keys + +Read the [DID documentation](../../../develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md) to learn more about DIDs and the difference between their light and full versions. + +::: + +## Generate Keys + +Like the Attester, the Claimer must also set up the DID keys. + + + {GenerateKeypairs} + + +The code above is similar to the `generateKeyAgreement` function used in the Attester section but simpler, as the Claimer only needs an authentication key and an encryption key. + +Both the keys are derived from the same seed, but they could also have two different seeds. + +## Generate Light DID + +With the `keypairs` generated, you can create the light DID. +Because it's off-chain you can create the DID object every time, but you still need to save the mnemonic to the `.env` file with a different variable name. + + + {GenerateLightDid} + + +The Claimer doesn't have an `account`, as the Claimer doesn't need to hold funds. + +The `generateKeypairs` function takes the `mnemonic` value and generates the `authentication` and `keyAgreement` keys. + +The `createLightDidDocument` method takes these two values and generates the light DID. + +## Run + + + + + ```bash + yarn ts-node ./claimer/generateLightDid.ts + ``` + + + + + ```bash + node ./claimer/generateLightDid.js + ``` + + + + +Well done - You successfully generated a light DID! diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/02_request.md b/versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/02_request.md new file mode 100644 index 000000000..8dbc992ff --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/02_request.md @@ -0,0 +1,73 @@ +--- +id: request +title: Request an Attestation +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import CreateClaim from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/claimer/createClaim.ts'; +import GenerateCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/claimer/generateCredential.ts'; + +This section covers creating a `Claim` and a `Credential`. + +KILT is a premissionless system. +Anyone or anything can claim something and attest to it. +But an attested credential only has value if the Verifier of the credential _trusts_ the Attester of the credential. + + +## Create Credential + +Use the previously created `light DID`, `ctype`, and Claimer provided `content` to generate the `Claim` object. + +A claim consists of attributes that we claim to be true about us. + + + {CreateClaim} + + +The `fromCTypeAndClaimContents` function takes the `lightDid`, `ctype`, and `content` values and generates a `Claim` object. + +## Receive attestation for claim + +Since you want to receive an attestation for those claims, build a `Credential` in the `generateCredential` function below. + +The credential contains all necessary information so the Attester can attest it. + + + {GenerateCredential} + + + +The `main` function takes the Claimer mnemonic and generates the light DID following the steps outlined in the [DID section](./01_did.md). +It then calls the `generateCredential` function using the supplied claim attributes. +It then uses the `createClaim` method from the previous step to create the `Claim` object and the `Kilt.Credential.fromClaim` method takes the claim and returns the `Credential` object. + +When Attesters issue `Attestations`, they are written to the chain, which requires a deposit. +Each new `Credential` is unique. +During testing, you can store and reuse credentials into `./claimer/_credential.json` to avoid multiple attestations. + +You can share this credential with others following the workshop to see how they get denied from fraudulent senders. + +## Run + + + + + ```bash + yarn ts-node claimer/generateCredential.ts + ``` + + + + + ```bash + node claimer/generateCredential.js + ``` + + + + +OK, you've made a claim as a Claimer and created a credential from it. +The next step is to finish the Attester and get the credential attested! diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/_category_.json b/versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/_category_.json new file mode 100644 index 000000000..5656d275e --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "๐Ÿ‘ค Claimer", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/index.md b/versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/index.md new file mode 100644 index 000000000..0c9431ac7 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/05_claimer/index.md @@ -0,0 +1,76 @@ +--- +id: claimer +title: ๐Ÿ‘ค Claimer +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This section covers the steps undertaken by the Claimer. + +Here's an overview: + +1. [Create a DID](./01_did.md), which is the identity used to interact with Attesters and Verifiers. +2. Create a claim, request an attestation, and generate a credential using the attestation for our claim. +3. Present the claim to a Verifier. + +## What is a Claimer? + +Claimers are a crucial part of the Self-Sovereign Identity system. + +A Claimer is an individual or institution that makes a claim or statement about their identity or abilities. +They can use their identity credentials to prove these claims, and third-party institutions verify them. + +Anyone can be a Claimer. +All you need to do is complete a CType and create a claim. +Then, you can send these claims to Attesters for verification. + +They store their identity credentials in their digital wallets, so they decide which information to provide to which service. +They have full control over their data and decide which data to share, where, and how. + +You don't need to create a DID on the chain, meaning you are entirely independent! + +Claimers can use their accounts without needing a chain connection. + + +## Folder Structure + +Create the following files in the Claimer folder. +This folders serves to mimic a Claimer's perspective. + + + + + ```bash + โ””โ”€ kilt-rocks/ # project + โ””โ”€ claimer/ # all claimer code + โ”œโ”€ createClaim.ts # creates a claim + โ”œโ”€ createPresentation.ts # creates a presentation for verifiers + โ”œโ”€ generateCredential.ts # create the credential object that is sent to the attester for attestation + โ”œโ”€ generateKeypairs.ts # create keypairs for the light DID + โ””โ”€ generateLightDid.ts # create the light DID for the claimer + ``` + + ```bash + cd claimer && touch createClaim.ts createPresentation.ts generateCredential.ts generateKeypairs.ts generateLightDid.ts && cd .. + ``` + + + + + ```bash + โ””โ”€ kilt-rocks/ # project + โ””โ”€ claimer/ # all claimer code + โ”œโ”€ createClaim.js # creates a claim + โ”œโ”€ createPresentation.js # creates a presentation for verifiers + โ”œโ”€ generateCredential.js # create the credential object that is sent to the attester for attestation + โ”œโ”€ generateKeypairs.js # create keypairs for the light DID + โ””โ”€ generateLightDid.js # create the light DID for the claimer + ``` + + ```bash + cd claimer && touch createClaim.js createPresentation.js generateCredential.js generateKeypairs.js generateLightDid.js && cd .. + ``` + + + diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/06_attestation.md b/versioned_docs/version-1.0.0/develop/03_workshop/06_attestation.md new file mode 100644 index 000000000..a433f6110 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/06_attestation.md @@ -0,0 +1,55 @@ +--- +id: attestation +title: ๐Ÿงพ Attestation +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import AttestCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/attester/attestCredential.ts'; + +This section covers how the Attester receives and processes a `Credential` and how you can: + +- Attest or deny it +- Store the attestation information on the chain + +## Attest a Credential + + + {AttestCredential} + + +The `attestCredential` function loads the account and DID of the Attester and issues an attestation for the credential received from the Claimer. +The credential is valid from the time an Attester attests it on chain until the time it is revoked. + +In the `attestingFlow` function, the Claimer generates the demo credential and sends it to the Attester. +The Attester checks the attributes and either attests or denies the attestation if the attributes are invalid. +Once the attestation is written on the chain, the Attester can share all or part of the attested credentials with verifiers. + +## Run + +Run the code from the command line: + + + + + ```bash + yarn ts-node attester/attestCredential.ts + ``` + + + + + ```bash + node attester/attestCredential.js + ``` + + + + +## Summary + +Your job as an Attester is complete. You've attested a credential and written the attestation hash onto the chain. + +Let's move on to set up the Verifier! diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/07_verification.md b/versioned_docs/version-1.0.0/develop/03_workshop/07_verification.md new file mode 100644 index 000000000..e0a154733 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/07_verification.md @@ -0,0 +1,72 @@ +--- +id: verification +title: ๐Ÿค Verification +--- + +import CodeBlock from '@theme/CodeBlock'; +import TsJsBlock from '@site/src/components/TsJsBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +import Verify from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/verify.ts'; +import CreatePresentation from '!!raw-loader!@site/code_examples/sdk_examples/src/workshop/claimer/createPresentation.ts'; + +In this section, you play the role of a Verifier that does the following: + +1. Take a `Presentation` object supplied by a Claimer +2. Verify that its data is correct +3. Verify that the attestation is valid, i.e., its hash exists on-chain and the attestation has not been revoked +4. Verify that the Claimer sending the `Credential` owns it + +:::info Presentation object + +The Claimer uses a Credential to create the `Presentation` object. +Unlike the credential, a `Presentation` can hide some attributes that are not required by the Verifier and can contain a claimer-signed challenge. +A `Presentation` also contains a proof that the Claimer owns the credential. + +::: + +## Create Presentation + +A Claimer needs to send more than a credential, as they also need to prove ownership of the credential. +A Claimer does this by creating a presentation and signing the Verifier's challenge. + + + {CreatePresentation} + + +The `createPresentation` method returns a presentation, taking the credential, a callback to sign data, and the Verifier's challenge as input. + +## Verify + +The verification code exposes the `getChallenge` method which returns a random and unique challenge for the Claimer to sign. +This unique challenge is used to prove ownership. + + + {Verify} + + +The `verifyPresentation` method performs the actual verification, taking a presentation and the Claimer's challenge as input. + +## Run + +Run the code from the command line: + + + + + ```bash + yarn ts-node verify.ts + ``` + + + + + ```bash + node verify.js + ``` + + + + +That's it! All done :-) \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/08_done.md b/versioned_docs/version-1.0.0/develop/03_workshop/08_done.md new file mode 100644 index 000000000..ff6558e53 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/08_done.md @@ -0,0 +1,25 @@ +--- +id: done +title: ๐Ÿš€ Done +--- + +## Congrats! + +Well done! +You now understand the main actors in KILT, the `Claimers`, `Attesters` and `Verifiers`. + +You have also learned how to: + +- create accounts +- create light and full DIDs +- create claims and attestation requests +- process requests and attest credentials +- generate and sign credential presentations +- receive and verify presentations + +## Resources + +Here are some resources to help you continue your journey in the KILT ecosystem: + +- [Discord](https://discord.gg/5VZnPdTZMy) - DAO-inspired, outcome-focused community +- [Element](https://matrix.to/#/%23kilt-general:matrix.org) - Technical, Governance, Treasury discussion diff --git a/versioned_docs/version-1.0.0/develop/03_workshop/_category_.json b/versioned_docs/version-1.0.0/develop/03_workshop/_category_.json new file mode 100644 index 000000000..65d6b088b --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/03_workshop/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Workshop", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/04_specifications.md b/versioned_docs/version-1.0.0/develop/04_specifications.md new file mode 100644 index 000000000..b36bed2b5 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/04_specifications.md @@ -0,0 +1,28 @@ +--- +id: specifications +title: Technical Specifications +--- + +:::note +This section is a WIP. +The end goal is for it to host all KILT specifications. +::: + +List of core specifications KILT has defined in an effort to standardize APIs and data structures across applications: + +- [KILT DID Method (GitHub repo)][kilt-did-method] +- [KiltPublishedCredentialCollectionV1 Service Type (GitHub repo)][kilt-published-credential-collection-v1] +- [Asset DID Method (GitHub repo)][asset-did-method] +- [KiltTransferAssetRecipientV1 Service Type (GitHub repo)][kilt-transfer-asset-receipient-v1] + +List of extensions to the core KILT protocol that standardize communication with the core KILT components (e.g., API for wallets to present credentials): + +- [Wallet Credential API (GitHub repo)][kilt-wallet-credential-api] +- [Wallet DIDSign API (GitHub repo)][kilt-wallet-didsign-api] + +[kilt-did-method]: https://github.com/KILTprotocol/spec-kilt-did +[kilt-published-credential-collection-v1]: https://github.com/KILTprotocol/spec-KiltPublishedCredentialCollectionV1 +[asset-did-method]: https://github.com/KILTprotocol/spec-asset-did +[kilt-transfer-asset-receipient-v1]: https://github.com/KILTprotocol/spec-KiltTransferAssetRecipientV1 +[kilt-wallet-credential-api]: https://github.com/KILTprotocol/spec-ext-credential-api +[kilt-wallet-didsign-api]: https://github.com/KILTprotocol/spec-ext-didsign-api diff --git a/versioned_docs/version-1.0.0/develop/05_builtonkilt.md b/versioned_docs/version-1.0.0/develop/05_builtonkilt.md new file mode 100644 index 000000000..e03487106 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/05_builtonkilt.md @@ -0,0 +1,78 @@ +--- +id: builtonkilt +title: Built on KILT +--- + +import ThemedImage from '@theme/ThemedImage'; +import LogoText from '@site/src/components/LogoText'; + +This section contains a non-exhaustive list of apps, wallets and websites that are built on KILT. +If you are not on the list and want to be added, you are welcome to [open a PR](https://github.com/KILTprotocol/docs/edit/master/docs/develop/05_builtonkilt.md). + +## Wallets + +Wallets are the gateway to Web3. +They store private information like secret keys for KILT DIDs and credentials. +Each time a website needs to access some information about the visitor, the wallet first asks its ownerโ€™s permission to share the requested information. + + + + Sporran is the first wallet to support the KILT protocol. + It is maintained by _BOTLabs Trusted Entity B.T.E GmbH_ and it is [open source](https://github.com/BTE-Trusted-Entity/sporran-extension). + + +## Web Apps + +Decentralized applications have already been built that use the functions of the wallet. + + + Help secure the KILT Spiritnet! + On Stakeboard you can influence who is allowed to build blocks on Spiritnet by delegating KILT tokens to a collator you trust. + + +--- + + + w3n.id is a website that helps you claim and search web3names. + Learn more about KILT web3names in our [concepts section](../concepts/03_web3names.md). + + +--- + + + DIDsign provides a decentralized way to sign any file directly in your browser using your KILT DID. + Your data stays locally on your device and is never transferred or held in a centralized place. + + +--- + + + Get your first KILT credential today! + SocialKYC issues credentials that prove ownership of several social profiles, including email addresses, and Telegram, Twitter and GitHub accounts, with more being continuously added. + It's free to use, and credentials expire after one year. + diff --git a/versioned_docs/version-1.0.0/develop/06_contribute.md b/versioned_docs/version-1.0.0/develop/06_contribute.md new file mode 100644 index 000000000..63430b580 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/06_contribute.md @@ -0,0 +1,101 @@ +--- +id: contribute +title: Contribution Guidelines +--- + +As a decentralized network, KILT depends on the support of its community. +There are many ways to contribute to KILT Protocol and the products and services built on it. +The following guide is to **help builders and contributors** find the resources needed to take action and work under the guidance of the core developers. + +If you are interested in contributing but unsure how to begin, start in our [Clan KILT Discord](https://discord.gg/7uyfMXh6AT) channel. +The developers active there, which include the team that originally developed KILT and the wider KILT community, can: + +- Provide feedback on proposals or ideas +- Discuss possible use cases and feature requests +- Make suggestions for non-technical contributions, including events, writing, or business models +- Answer questions about the protocol, services and products + + +## Feature Requests + +A feature request may be used to change the KILT Protocol and its services by adding new features or changing/removing existing ones. + + +A feature request is a meaningful way for anyone to contribute following the guidelines below: + + - Begin a discussion with the community to ensure most see that the proposed feature adds real and meaningful value to KILT Protocol, supporting its goals + - Open an Issue on the corresponding repository + - Give your Pull Request a clear title + - Provide a written outline of the feature request for discussion + +After discussion, if the community agrees that the change should be implemented, the proposer may also submit a Treasury proposal to support the work. +The guidelines of how to do that are presented in the next section. + +## Treasury Proposals + +A Treasury proposal is a request to receive funds from the Treasury pool. +The proposal should begin with a clear title, a written outline of the idea, and a discussion about implementation or deliverables as outlined above for feature requests. +The proposal should be for something that changes or adds value to KILT in a meaningful way. + +:::info +In general, a Treasury proposal spend occurs after completing all outlined deliverables and not before. +Thus, it is recommended to open multiple consecutive milestone-based proposals rather than one large proposal to fund contributions. +::: + +In addition you should: + +- Explain any milestones that have already been achieved +- Outline what needs to be done for the proposal to be completed + +The proposal should then be discussed with the community (including, for example, the KILT Technical Committee, governance, or relevant project team) using community channels such as [Discord](https://discord.gg/7uyfMXh6AT) or [Polkassembly](https://kilt.polkassembly.network/discussions). +If the community is not in agreement with the proposal, it is unlikely that it would be approved by governance. +See the [guide to creating a proposal](../participate/03_treasury_proposal.md) for additional details. + +## Tips + +Tips are a more agile and lightweight process to receive rewards for contributing to the KILT Protocol. +Even though the funds also come from the Treasury, the procedure is more straightforward. +The major difference compared to Treasury proposals is that for tips, determining the bounty amount is part of the course of tipping. +In other words, the final tip amount is not clear beforehand and the group of pre-determined stakeholders comes to consensus on how much should be paid. +Eventually, the median of proposed tips will be awarded from the Treasury. +Currently, the tippers include all Council members and other core code contributors. + +Both proposals and tips are similar in the sense that there must be someone (called the _Finder_) to open the tipping process by providing a reason in the form of a URL or an explanation on [Polkassembly](https://kilt.polkassembly.network/). +In contrast to proposals, tips do not require an extensive document; a URL to the pull request or the blog post suffices. +If the Finder is part of the group that decides about the bounty award, no deposit needs to be made. +Moreover, the beneficiary will receive the entire tip without any deductions. +Otherwise, a small deposit, which depends on the length of the message explaining the reason for the tip, needs to be reserved. +The deposit will be released after the tipping process has finished. +Additionally, the Finder also receives a minor Finder's fee of 20% which is subtracted from the final tip amount. + +Therefore, **even if you are not a contributor, you can open a tipping process for someone else and receive a smaller portion of their potential reward**. +Of course, you can also suggest potential tip candidates to the Council, which would then tip if they are deemed worthy. + +## Bug Reports + +We try our best, but bugs are an everyday reality with all software and are bound to happen. +We can't fix bugs we don't notice, so your potential findings give us the best possibility of keeping the project running smoothly and securely. + +If you are unsure if a bug is a bug, it is best to open an issue and report it anyway. +The active developers will evaluate it and help to figure out the issue. + +It is helpful to check if a report has already been filed in the related project. +Search the issues board for possible phrases that match the description of the bug. +It's possible you may not find an issue, but it's better to file a duplicated bug than not report one. + +Once you begin reporting the bug, write a descriptive title so that if others find the same issue they can either add to your findings or know that the bug has already been reported. +A bug report should be as detailed as possible, including steps to reproduce, screenshots, error reports, or code snippets. +The more details you provide, the easier it is to fix the issue. + +## Pull Requests + +Pull Requests (PR) are an integral part of contributions to evolve KILT. +GitHub itself has some [excellent documentation](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests) on using the Pull Request feature. +KILT uses the "[fork and pull](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/getting-started/about-collaborative-development-models)" model, where contributors push changes to their personal fork and create Pull Requests to bring those changes into the original source repository. + +Before starting a PR, itโ€™s best to contact other active developers and discuss the proposed changes. +Open an issue or directly contact some of the developers on [Discord](https://discord.gg/7uyfMXh6AT) to kick off the discussion and present the proposal. +Once approved, contributors can open a PR for review. +The PR will be reviewed and, if accepted, merged into the corresponding repository. + +The following section is inspired by the Rust Programming Language [Bug Report](https://rustc-dev-guide.rust-lang.org/contributing.html) contribution guide. diff --git a/versioned_docs/version-1.0.0/develop/07_dApp/01_welcome.md b/versioned_docs/version-1.0.0/develop/07_dApp/01_welcome.md new file mode 100644 index 000000000..8f04305cc --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/07_dApp/01_welcome.md @@ -0,0 +1,13 @@ +--- +id: welcome +title: Overview +--- + +This section expands on the [Credential API Specification](https://github.com/KILTprotocol/spec-ext-credential-api) and includes code examples to help you build a decentralized application (dapp). + +This documentation assumes that you already have a browser extension capable of exposing the credential API to your dapp. +We suggest using Sporran: + +- [Sporran Full Version](https://github.com/BTE-Trusted-Entity/sporran-extension) +- [Sporran Test Version for Peregrine](https://github.com/BTE-Trusted-Entity/sporran-extension/releases) +- [Sporran Lite (Credentials only)](https://github.com/BTE-Trusted-Entity/sporran-extension/tree/sporran-lite) diff --git a/versioned_docs/version-1.0.0/develop/07_dApp/02_well-known-did-config.md b/versioned_docs/version-1.0.0/develop/07_dApp/02_well-known-did-config.md new file mode 100644 index 000000000..825387701 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/07_dApp/02_well-known-did-config.md @@ -0,0 +1,110 @@ +--- +id: well-known-did-config +title: Well-Known DID Configuration +--- + + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DomainLinkageCtype from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/01_domain_linkage_ctype.ts'; +import DomainLinkageClaim from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/02_domain_linkage_claim.ts'; +import SignPresentation from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/03_sign_presentation.ts'; +import AttestCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/04_attest_credential.ts'; +import FormatCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/05_format_credential.ts'; + +:::danger This is a working draft + +The KILT support of the *Well-Known DID Configuration* uses unpublished specifications and will change in the future. + +::: + +The *Well-Known DID Configuration* is implemented as a security measure when setting up the communication session between the dapp and extension. +It ensures that the DID the browser extension is communicating to is linked to the domain that is visited by the browser. +This rule is currently enforced by the KILT Wallet reference implementation (Sporran Extension), but might be relaxed in the future. +The implementation is based on the [*Well-Known DID Configuration*][well-known-spec] specified by the Decentralized Identity Foundation. + +Once a communication session between a dapp and an extension is opened, the extension will query `/.well-known/did-configuration.json`. +This JSON-file must contain a credential presentation that conforms to the [Domain Linkage CType][CType-Domain-Linkage]. + +## Set up the Well-Known DID Configuration + +For the *Well-Known DID Configuration* you need to go through the following steps: + +0. Create a full DID + * You will need the `assertionMethodKey` a.k.a. `attestationKey` for signing the credential + * The `authenticationKey` is required for signing the transaction +1. Create a claim +2. Attest the claim +3. Create a presentation +4. Host the presentation on your website at `https:///.well-known/did-configuration.json` + +### Create a DID + +Your dapp needs a DID to identify itself to the extension. +If your dapp does not have a DID yet, follow the [*create a full DID* guide][create-full-did]. +Make sure to create the DID with an `assertionMethodKey` so that you are able to issue attestations. + +### Making the claim + +After you get a DID, you can make a claim about that DID. +The claim has to be based on the [Domain Linkage CType][CType-Domain-Linkage], whose definition you can get from the linked GitHub repository, or fetch from the blockchain using the CType's id: + + + {DomainLinkageCtype} + + +The credential is built from the CType, claim contents, and your dapp's unique DID: + + + {DomainLinkageClaim} + + +The credential isn't attested yet and is therefore not valid yet. + +### Self-attesting the credential + +A valid credential requires an attestation. +Since the website wants to link itself to the DID just created, it has to self-attest the domain linkage credential, i.e., write the credential attestation on chain using the same DID it is trying to link to. + +In order to attest the credential we go through the following steps: + +1. calculating the claim hash +2. creating the attest transaction +3. authorizing the transaction with your DID +4. paying for the transaction with a KILT account and submitting it to the chain + + + {AttestCredential} + + +If you want to learn more about attestations you can refer to our [concept guide][concept-attestations] or the [cookbook][cookbook-attestations]. + +### Presenting the credential + +To use the newly attested credential, we need to derive a presentation from it to host on the dapp website. + + + {SignPresentation} + + +The Well-Known DID Configuration specification requires a verifiable credential. +For now we have to manually convert our KILT credential into the required format. + + + {FormatCredential} + + +### Host the Presentation + +Now that you generated a presentation, you need to host it in your web app, so that the extension can query the presentation. +The extension will make an HTTP GET request to the following URI, and your dapp must respond with the presentation. + +`/.well-known/did-configuration.json` + +How the file is hosted depends on your project setup and is out of scope for this guide. + +[concept-attestations]: ../../concepts/05_credentials/04_attestation.md +[cookbook-attestations]: ../01_sdk/02_cookbook/04_claiming/03_attestation_creation.md +[create-full-did]: ../01_sdk/02_cookbook/01_dids/02_full_did_creation.md +[well-known-spec]: https://identity.foundation/specs/did-configuration/ +[CType-Domain-Linkage]: https://github.com/KILTprotocol/ctype-index/tree/main/ctypes/0x9d271c790775ee831352291f01c5d04c7979713a5896dcf5e81708184cc5c643 diff --git a/versioned_docs/version-1.0.0/develop/07_dApp/03_session.md b/versioned_docs/version-1.0.0/develop/07_dApp/03_session.md new file mode 100644 index 000000000..12b04afce --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/07_dApp/03_session.md @@ -0,0 +1,59 @@ +--- +id: session +title: Setting Up the Communication Session +--- + +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import DappIntroduction from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/06_dapp_introduction.ts'; +import SessionCheck from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/dapp/07_session_check.ts'; + +The first step in creating your dapp is to set up the communication session. +The purpose of the session is to pass encrypted messages back and forth between your dapp and the extension. + +## Dapp Indicates Credential API Support + +In order to indicate its support of the extension's API, the dapp creates the `window.kilt` object as soon as possible. +To indicate the API version that the dapp supports, we also create the properties `window.kilt.meta.versions.credentials`. +Since `meta` is not an extension, this property is not enumerable. +For example: + +```html + + + +``` + +## Dapp Introduces Itself + +The dapp introduces itself to the extension with its name, encryption key URI, and a challenge. +A copy of the challenge should be stored on the server side. +For example: + + + {DappIntroduction} + + +At this point the extension has received the introduction of the dapp and returned a new session along with the encrypted challenge. + +## Dapp checks the session values + +The extension has provided the session along with an encrypted challenge. +The dapp decrypts the challenge and verifies that it matches the original challenge. +This should happen on the server side: + + + {SessionCheck} + + +That's it! The communication session has been securely established and you're ready to start sending and receiving messages. diff --git a/versioned_docs/version-1.0.0/develop/07_dApp/04_verifier.md b/versioned_docs/version-1.0.0/develop/07_dApp/04_verifier.md new file mode 100644 index 000000000..1f44af1c6 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/07_dApp/04_verifier.md @@ -0,0 +1,84 @@ +--- +id: dapp-verifier +title: Verifying a Credential +--- + +import TsJsSnippet from '@site/src/components/TsJsSnippet'; +import TsJsBlock from '@site/src/components/TsJsBlock'; + +import EmailCtype from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/verifier/01_email_ctype.ts'; +import GenerateChallenge from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/verifier/02_generate_challenge.ts'; +import CreateRequestCredentialMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/verifier/03_create_request_credential_message.ts'; +import EncryptRequestCredentialMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/verifier/04_encrypt_request_credential_message.ts'; +import DecryptCredentialMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/dapp/verifier/05_verify_credential_message.ts'; + +This section demonstrates how to build a basic verifier according to the [Credential API Specification](https://github.com/KILTprotocol/spec-ext-credential-api). +Before continuing, please make sure you have already set up the [communication session](03_session.md) and [Well-Known DID Configuration](02_well-known-did-config.md). + +This guide explains specifically how a web server can request a credential presentation from one of its visitors (the claimer). +After the browser extension verified the Well-Known DID Configuration and the encrypted communication channel between the extension and the server was established, the web server can request the credential presentation. +This is a two step process. + +First the server sends a message to the extension that request the presentation of a credential. +Since we don't want to see just any credential, but expect specific content, we also require that the credential conforms to a specific [CType](../../concepts/05_credentials/02_ctypes.md). +When the extension receives the request, it will prompt the user to select a credential that should be presented to the server. +The user can also choose to reject this request and not to show any presentation. + +The second step is to verify the received credential. +After the user chooses the credential, the extension will pass a response to the website which contains the credential presentation. +The server of that website needs to ensure that this presentation is actually valid. + +## Request a Credential Presentation + +Before the website can request a credential, it needs the type of credential (CType) that it wants to request. +In this guide the website requests an email address that is owned by the DID. +For that it uses the Email CType. +You can search through existing CTypes in the [CType Index](https://github.com/KILTprotocol/ctype-index). + + + {EmailCtype} + + +After settled on a CType, the server can build the request for the visitor. +Since we want to ensure that the presentation of the credential is fresh, the server first has to create a random challenge. +The presentation must include this challenge and since it's random, the presentation must be created and signed from scratch. +This ensures that it's not possible to record a presentation and just send this, pretending to be the owner of the DID. +The challenge can be generated using the polkadot crypto utilities: + + + {GenerateChallenge} + + +With the challenge the server can construct the `request-credential` message. +The request is sent to the light DID (`claimerSessionDid`) that is used to encrypt the messages (see [Session](03_session.md) for more information). + + + {CreateRequestCredentialMessage} + + +:::note Privacy + +The credential itself doesn't need to be issued to this DID since the light DID is only used to encrypt the messages. +We don't use the full DID of the claimer to establish the encrypted communication, so that the claimer first can ensure the origin of the `request-credential` message. + +::: + +After the server has built the message object, it must encrypt the message for the claimer. +Once the message is encrypted the server can pass on the message to the extension. + + + {EncryptRequestCredentialMessage} + + +## Verify the Presentation + +After sending the `request-credential` message to the extension, the verifier listens for a message of type `submit-credential` in response. + +After the response from the extension is received, forwarded to the server and decrypted, the verifier must check that it has the expected CType and that it contains a valid credential. +Since everyone can run an attestation service, you need to make sure that you also verify that the attester is trusted. + + + {DecryptCredentialMessage} + + +That's it! Your verifier has successfully requested and verified a credential. diff --git a/versioned_docs/version-1.0.0/develop/07_dApp/_category_.json b/versioned_docs/version-1.0.0/develop/07_dApp/_category_.json new file mode 100644 index 000000000..235e97018 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/07_dApp/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "DApp", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/08_opendid/01_overview.md b/versioned_docs/version-1.0.0/develop/08_opendid/01_overview.md new file mode 100644 index 000000000..235e4223d --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/08_opendid/01_overview.md @@ -0,0 +1,40 @@ +--- +id: what-is-opendid +title: Overview +--- + +[OpenDID](https://github.com/KILTprotocol/opendid) is an OpenID Provider implementation capable of authenticating users through their [Decentralized Identifier (DID)](../../concepts/02_did.md) and Verifiable Credentials. + +It follows the [OpenID Connect 1.0 Specification](https://openid.net/specs/openid-connect-core-1_0.html#Introduction) and acts as a bridge between the decentralized identity world and the centralized authentication world supporting both the implicit and Authorization Code Flow. + +A major use of OpenDID is Single Sign-On (SSO), which allows users to use the same DID and credentials to sign into multiple platforms and web services. For instance, by adding a "Sign in with KILT" button to a webpage. + +Although integrating that functionality into a webpage is relatively simple, configuring and running OpenDID is more involved. + +:::info + +To learn more about the flow of OpenDID, see the [OpenDID Flow](./02_opendid_flow.md) documentation. + +::: + +## Project container structure + +The project consist of multiple parts that supplement and interact with each other all shipped as Docker containers and released to Docker Hub. + +### opendid-setup container + +The OpenDID Service needs configuration to run, which you can apply using this +container. +For example, it requires a DID to establish a session with an identity wallet. +This container creates a DID and the necessary configuration by providing an account with enough funds. + +Learn more in the [run setup container documentation](./03_opendid_service.md#run-setup-container). + +### kiltprotocol/opendid container + +This container [runs the OpenDID Service](./03_opendid_service.md#run-the-service), both the OpenDID front and back end. +This container requires the configuration file created from the `opendid-setup` container. + +### kiltprotocol/opendid-demo + +This container is a [web app demo](./05_demo_project.md), including front and back end services to demonstrate the use of OpenDID. \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/08_opendid/02_opendid_flow.md b/versioned_docs/version-1.0.0/develop/08_opendid/02_opendid_flow.md new file mode 100644 index 000000000..5a1046ce7 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/08_opendid/02_opendid_flow.md @@ -0,0 +1,74 @@ +--- +id: flow +title: OpenDID Flow +--- + +This guide explains the internal workings of OpenDID. +Understanding this flow is helpful for setting up and configuring an OpenDID Service but less important if you only need to integrate it in an application. + +OpenDID includes interactions between multiple apps to authenticate and authorize users. +Common use cases include the following: + +- Web app front end (app that includes the login button, for example, the demo app) +- Web app back end +- OpenDID front end +- OpenDID back end +- Identity wallet that follows [the Credential API spec](https://github.com/KILTprotocol/spec-ext-credential-api) (typically a browser extension, for example, [Sporran](https://www.sporran.org/)) + +The following steps outline the interactions necessary to implement [the implicit flow](https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth): + +1. The user clicks the login button on the _web app front end_. +2. The _web app front end_ redirects the user to the _OpenDID front end_. +3. The user chooses what wallet to authenticate with. +4. The _OpenDID back end_ establishes a secure session with the _identity wallet_. +5. The _OpenDID back end_ optionally requests a credential that implements a specific CType. +6. The _identity wallet_ provides the _OpenDID back end_ with the requested credential, after authenticating the DID holder. +7. The _OpenDID back end_ returns a `id_token` as a JSON web token (JWT) to the _OpenDID front end_. +8. _OpenDID front end_ redirects the user back to a specific `redirect_url` on the _web app front end_ including the `id_token`. +9. The _web app front end_ detects the `id_token` and sends it to the _web app back end_. +10. The _web app back end_ verifies the `id_token` and ensures the validity of the credential. + +The following sequence diagram summarizes the flow: + +```mermaid +sequenceDiagram + +participant AB as WebApp Backend +participant AF as WebApp Frontend +participant OF as OpenDID Frontend +participant OB as OpenDID Backend +participant IW as Identity Wallet + +AF->>OF: (1, 2) Authorize (redirect_uri: /callback) +OF->>OF: (3) Pick Identity Wallet +critical (4) Key Exchange +OF->>OB: GET Challenge +OB-->>OF: Challenge +OF->>IW: Start Session +IW-->>OF: Encrypted Challenge +OF->>OB: POST Challenge +OB-->>OF: OK +end + +critical Authenticate +OF->>OB: (5) GET Credential Requirements +OB-->>OF: Credential Requirements +OF->>IW: (6) Request Credential +IW->>IW: Authenticate User +IW->>OF: Credential +OF->>OB: POST Credential +OB->>OB: Verify Credential +OB->>OF: (7) `id_token`) +end + +OF->>AF: redirect to /callback with `id_token` +AF->>AB: (8) `id_token` +AB->>AB: (9) verify `id_token` +AB->>AF: (10) Access granted. + +``` + +:::info +Although this example describes the implicit flow, [the authorization code flow](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth) is similar. +Instead of returning an `id_token` directly, the OpenDID service instead returns a `code` to exchange for an `id_token` using the `token` endpoint. +::: diff --git a/versioned_docs/version-1.0.0/develop/08_opendid/03_opendid_service.md b/versioned_docs/version-1.0.0/develop/08_opendid/03_opendid_service.md new file mode 100644 index 000000000..311f3fc60 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/08_opendid/03_opendid_service.md @@ -0,0 +1,115 @@ +--- +id: opendid_service +title: Run OpenDID Service +--- + +## Configuration + +Running the OpenDID service requires some configuration and a KILT DID. +The DID establishes a secure session with an identity wallet using a key agreement key of type `X25519KeyAgreementKey2019` included in the DID Document generated by the setup container. + +OpenDID serves a [well-known DID configuration](https://identity.foundation/.well-known/resources/did-configuration/), which the identity wallet uses to ensure that the domain is linked to the specified DID. + +### Run setup container + +Before running the `opendid-setup` container, set two environment variables: + +1. `SEED` to provide an account with funds (minimum of 3 KILT) for the DID generation. + + ```bash + export SEED="dont try this seed its completely made up for this nice example" + ``` + +2. `ENDPOINT` + + Set to "spiritnet" if the account is on the spiritnet production network. + + ```bash + export ENDPOINT="spiritnet" + ``` + + Set to "peregrine" if the account is on the peregrine test network. + + ```bash + export ENDPOINT="peregrine" + ``` + + Then run the setup with the following command: + + ```bash + docker run --rm -it -e "ENDPOINT=${ENDPOINT}" -v $(pwd):/data docker.io/kiltprotocol/opendid-setup:latest "${SEED}" + ``` + +The command generates a set of new mnemonics and then derives a DID from them and generates multiple files into the current directory: + +1. `config.yaml` The configuration file used by the OpenDID service. + + :::warning + You only need the `config.yaml` to run the OpenDID service. + This file includes the generated mnemonic and secret keys and you should protect it from unauthorized access. + ::: + +2. `did-secrets.json` This file contains the public and secret keys in the DID Document. + + :::warning + Keep a secure backup of this file as it contains all the secret keys. + ::: + +3. `did-document.json` contains the DID Document generated by this setup. + +The container generates sensible defaults in the `config.yaml` file, but here are some values you might want to change: + +- Set `production` to true, this only allows secure connections. +- Set the `WellKnownDid` > `origin`, which should match the host running the OpenDID service. +- Set the keys used for JWT issuance in the `jwt` section. +- The `client` section, including: + + - The client ID as a key (The default is: `example-client`). + - The `requirements` section, including: + + - What CTypes are required for authentication. + - The trusted attesters as an address (The default is for the [SocialKYC attester](https://socialkyc.io/)). + + :::note info + + The generated default `config.yaml` requires an [email credential](https://test.ctypehub.galaniprojects.de/ctype/kilt:ctype:0x3291bb126e33b4862d421bfaa1d2f272e6cdfc4f96658988fbcffea8914bd9ac) issued by an attester. + + ::: + + - What `redirect_url`s the service accepts (The default is `http://localhost:1606/callback.html` for the demo project). + - The `clientSecret` is optional but recommended. If you use the authorization code flow, the `token` endpoint requires it. + +## Run the service + +When you've made changes to the `config.yaml` file, you can run the OpenDID service. + +1. Specify the runtime through the `RUNTIME` environment variable: + + Set to `"spiritnet"` for production KILT + + ```bash + export RUNTIME="spiritnet" + ``` + + Set to `"peregrine"` for the KILT test net. + + ```bash + export RUNTIME="peregrine" + ``` + +2. Run the `docker.io/kiltprotocol/opendid` docker image. + + ```bash + docker run -d --rm \ + -v $(pwd)/config.yaml:/app/config.yaml \ + -v $(pwd)/checks:/app/checks \ + -e "RUNTIME=${RUNTIME}" \ + -p 3001:3001 \ + docker.io/kiltprotocol/opendid:latest + ``` + +3. Open the login page at _http://localhost:3001_. + +## Next steps + +With configuration in place and a service running, next you need to [integrate OpenDID into an application](./04_integrate_opendid.md) so that a user can use the login page. diff --git a/versioned_docs/version-1.0.0/develop/08_opendid/04_integrate_opendid.md b/versioned_docs/version-1.0.0/develop/08_opendid/04_integrate_opendid.md new file mode 100644 index 000000000..a0518be0b --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/08_opendid/04_integrate_opendid.md @@ -0,0 +1,126 @@ +--- +id: integrate_opendid +title: Integrate OpenDID +--- + +OpenDID follows the [OpenID Connect 1.0 Specification](https://openid.net/specs/openid-connect-core-1_0.html#Introduction) and implements both the [implicit flow](https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowSteps) +and the [authorization code flow](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth). +Read the [demo project guide](05_demo_project.md) for an example of integrating OpenDID. + +## Authorization code flow + +Initiate the flow by redirecting to the **GET** `/api/v1/authorize` endpoint on the OpenDID service and setting the following query URL-encoded parameters: + +- `response_type`: set value to `code` to indicate Authorization Code Flow. +- `client_id`: The client ID set in the `config.yaml` file. +- `redirect_uri`: OpenDID redirects to this URL after authentication. +- `scope`: set value to `openid`. +- `state`: set to a secure random number. +- `nonce`: optional value, set to a secure random number. + +**Example**: + +``` +GET /api/v1/authorize? + response_type=code& + client_id=example-client& + redirect_uri=http://localhost:1606/callback.html& + scope=openid& + state=rkw49cbvd4azu5dsln1xbl& + nonce=vedur4om49ei8w91jt7wt HTTP/1.1 +``` + +After successful authentication, the OpenDID service redirects back to the provided `redirect_uri` with `code` and `state` query parameters. + +**Example**: + +``` +/callback.html? + code=lwDS1ZpQBwR4Vdm53_L8bWpUJ1mx9A0mA_-86dubTqzqzwGazx1RyLX4Z_qf& + state=rkw49cbvd4azu5dsln1xbl +``` + +You can retrieve the `id_token` by calling the **POST** `/api/v1/token` and providing the following values in the form serialization: + +- `code`: code value returned from `authorize`. +- `grant_type`: set value to `authorization_code`. +- `redirect_uri`: the same `redirect_uri` used in `authorize`. +- `client_id`: the client ID set in the `config.yaml` file. +- `client_secret`: the client secret value set in the `config.yaml` file. + +**Example**: + +``` +POST /api/v1/token HTTP/1.1 +Content-Type: application/x-www-form-urlencoded + +code=lwDS1ZpQBwR4Vdm53_L8bWpUJ1mx9A0mA_-86dubTqzqzwGazx1RyLX4Z_qf& +grant_type=authorization_code& +redirect_uri=http%3A%2F%2Flocalhost%3A1606%2Fcallback.html& +client_id=example-client& +client_secret=insecure_client_secret +``` + +The OpenDID service returns the `id_token` in the response body serialized as a JSON object. + +```json +{ + "access_token": "SsFhhSBMWsLeDMxVUVGreKARNwYxMZtGFfBr0-ZiH6iondSmwPRvQDqkG6Fh", + "token_type": "bearer", + "refresh_token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkaWQ6a2lsdDo0b0VkNENVV3RwbkxUVnZENVBFd2lMUmlqMWdzQmprS1JMbVpES2lCOEdqN2I2V0wiLCJ3M24iOiJjdXN0b20iLCJleHAiOjE3MTY4MTYwNjQsImlhdCI6MTcxNjgxNTQ2NCwiaXNzIjoiZGlkOmtpbHQ6NHJzQkE3dEQ1S1E4TDlXSGpGallRdUhrTWtha2NmSGRDNUNhUVVjVXh5VWpEVkhBIiwiYXVkIjoiYXV0aGVudGljYXRpb24iLCJwcm8iOnsiRW1haWwiOiJhYmR1bEBraWx0LmlvIn0sIm5vbmNlIjoidmVkdXI0b200OWVpOHc5MWp0N3d0In0.yOmE_9jWKcAu8LpjVx7IsFyOOvlKbgo2oC4Imf-qrLY", + "id_token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkaWQ6a2lsdDo0b0VkNENVV3RwbkxUVnZENVBFd2lMUmlqMWdzQmprS1JMbVpES2lCOEdqN2I2V0wiLCJ3M24iOiJjdXN0b20iLCJleHAiOjE3MTY4MTU1MjQsImlhdCI6MTcxNjgxNTQ2NCwiaXNzIjoiZGlkOmtpbHQ6NHJzQkE3dEQ1S1E4TDlXSGpGallRdUhrTWtha2NmSGRDNUNhUVVjVXh5VWpEVkhBIiwiYXVkIjoiYXBwbGljYXRpb24iLCJwcm8iOnsiRW1haWwiOiJhYmR1bEBraWx0LmlvIn0sIm5vbmNlIjoidmVkdXI0b200OWVpOHc5MWp0N3d0In0.YlRE9EGnSExQCb5m2iy4__58PZJlZdCZMsSvsuW4oj8" +} +``` + +:::note +In full-stack applications, calling the `token` endpoint is usually done through the back end to improve security. +::: + +The `id_token` is a bearer JSON web token (JWT) signed by the JWT key-pair specified in the `config.yaml` file of the OpenDID service. +You must verify this using the JWT public key, for example, by the back end of the Web app. + +## Implicit flow + +Initiate the flow by redirecting to the **GET** `/api/v1/authorize` endpoint on the OpenDID Service and setting the following query parameters: + +- `response_type`: set value to `id_token` to indicate Implicit Flow. +- `client_id`: The client ID set in the config.yaml file. +- `redirect_uri`: OpenDID redirects to this URL after authentication. +- `scope`: set value to `openid`. +- `state`: set to a secure random number. +- `nonce`: optional value, set to a secure random number. + +**Example**: + +``` +GET /api/v1/authorize? + response_type=id_token& + client_id=example-client& + redirect_uri=http://localhost:1606/callback.html& + scope=openid& + state=o0fl4c9gwylymzw5f4ik& + nonce=ia7sa06ungxdfzaqphk2 HTTP/1.1 +``` + +After successful authentication, OpenDID redirects back to the provided `redirect_uri` with `id_token` and `state` +**fragment components**. + +**Example**: + +``` +/callback.html# + id_token=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkaWQ6a2lsdDo0b0VkNENVV3RwbkxUVnZENVBFd2lMUmlqMWdzQmprS1JMbVpES2lCOEdqN2I2V0wiLCJ3M24iOiJjdXN0b20iLCJleHAiOjE3MTY4ODQ5MDYsImlhdCI6MTcxNjg4NDg0NiwiaXNzIjoiZGlkOmtpbHQ6NHJzQkE3dEQ1S1E4TDlXSGpGallRdUhrTWtha2NmSGRDNUNhUVVjVXh5VWpEVkhBIiwiYXVkIjoiYXBwbGljYXRpb24iLCJwcm8iOnsiRW1haWwiOiJhYmR1bEBraWx0LmlvIn0sIm5vbmNlIjoiOTFzN2ZnZDZvcjR3c2NkdGVtcXQifQ.xTy3Oyc5e-vlP10mGy0f9GqNU4LV97s77s-l7w5EwF0& + refresh_token=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkaWQ6a2lsdDo0b0VkNENVV3RwbkxUVnZENVBFd2lMUmlqMWdzQmprS1JMbVpES2lCOEdqN2I2V0wiLCJ3M24iOiJjdXN0b20iLCJleHAiOjE3MTY4ODU0NDYsImlhdCI6MTcxNjg4NDg0NiwiaXNzIjoiZGlkOmtpbHQ6NHJzQkE3dEQ1S1E4TDlXSGpGallRdUhrTWtha2NmSGRDNUNhUVVjVXh5VWpEVkhBIiwiYXVkIjoiYXV0aGVudGljYXRpb24iLCJwcm8iOnsiRW1haWwiOiJhYmR1bEBraWx0LmlvIn0sIm5vbmNlIjoiOTFzN2ZnZDZvcjR3c2NkdGVtcXQifQ.87UHGid3OotxO8Wpfuw-1sc5fsQJVt5gc2cqp9dVHiw& + state=nitctpl7nmqcpvob7xthrw& + token_type=bearer +``` + +## Self-Issued OpenID Provider v2 (SIOPv2) + +You can configure OpenDID to be compatible with [SIOPv2](https://openid.net/specs/openid-connect-self-issued-v2-1_0.html). +In this case, you only need a DID for the authorization, and no credentials. +To configure the OpenDID service to allow SIOPv2, it must have a `client` key with an empty requirements +value in the `config.yaml` file. + +Initiate the SIOPv2 flow the same way as the [Implicit Flow](#implicit-flow) with the exception that the `nonce` +value is required. diff --git a/versioned_docs/version-1.0.0/develop/08_opendid/05_demo_project.md b/versioned_docs/version-1.0.0/develop/08_opendid/05_demo_project.md new file mode 100644 index 000000000..a4a334d35 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/08_opendid/05_demo_project.md @@ -0,0 +1,30 @@ +--- +id: demo_project +title: Demo Project +--- + +The example code at [demo-project](https://github.com/KILTprotocol/opendid/tree/main/demo-project) contains a minimal application that uses OpenDID. +It's an [express](https://expressjs.com) application that exposes three things: + +- A login page that handles the dispatching of the user to the OpenDID service. +- A callback page for one of the OpenID Connect flows supported to accept the token. +- A protected resource that only authenticated users can access. + +For the demo application to work you need a running OpenDID Service and an identity wallet that follows [the Credential API spec](https://github.com/KILTprotocol/spec-ext-credential-api) (e.g. [Sporran](https://www.sporran.org/)) with a DID and Credential issued by the required attester specified in the `config.yaml` file (Default is SocialKYC). +If you follow the steps in this section in order, you have all the necessary components for the demo application to run. + +Run the pre-configured demo application with the following command: + +```bash +docker run -d -it --rm \ + --name demo-frontend \ + -p 1606:1606 \ + docker.io/kiltprotocol/opendid-demo +``` + +The demo page runs on _http://localhost:1606_. It pre-fills the Client ID value and offers login buttons to follow the implicit or authorization code flow. + +:::note +You can set the JSON web token (JWT) secret can with the `TOKEN_SECRET` environment variable inside the docker container. It must match +the one specified in the `config.yaml` file to correctly verify the `id_token`. The default is `super-secret-jwt-secret`. +::: diff --git a/versioned_docs/version-1.0.0/develop/08_opendid/06_advanced.md b/versioned_docs/version-1.0.0/develop/08_opendid/06_advanced.md new file mode 100644 index 000000000..ec36cb8bb --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/08_opendid/06_advanced.md @@ -0,0 +1,111 @@ +--- +id: advanced +title: Advanced Usage +--- + +## Use dynamic client management with etcd + +To dynamically create or remove OpenID Connect clients, configure the service to get its configuration from an [etcd cluster](https://etcd.io) by adding the connection parameters for the cluster in the `config.yaml` file. + +```yaml +etcd: + endpoints: ['localhost:2379'] + user: etcd-user + password: my-password + tlsDomainName: my.etcd.cluster.example.com + tlsCaCert: | + -----BEGIN CERTIFICATE----- + + -----END CERTIFICATE----- + tlsClientCert: | + -----BEGIN CERTIFICATE----- + + -----END CERTIFICATE----- + tlsClientKey: | + -----BEGIN RSA PRIVATE KEY----- + + -----END RSA PRIVATE KEY----- +``` + +All fields except `endpoints` are optional. +When everything is set up you can start adding client configurations into the etcd cluster. + +```bash +CLIENT_SPEC=$(cat < remote switches. The reverse is assumed to happen via XCM reserve transfer from the configured remote location, for which the pallet crate provides all the XCM components that are dynamically configured based on the switch pair information stored within each instance of this pallet. +* The sovereign account of the source chain at destination owns the remote assets in the amount that is specified when the switch pair is created. The validation of this requirement is delegated to the source chain governance in the act leading to the creation of the switch pair, as the source chain itself has currently no means of doing that. +* To account for failure on the remote destination, the pallet stores unconfirmed operations in a storage map. The remote chain then sends `Report` messages back to either confirm or revert a transfer. In the meanwhile, the source chain (where this pallet is deployed) assumes the transfer will be successful and updates all related counters tracking the destination state, to then revert them in case of failures. + +## Add the pallet to the runtime + +Add the following line to the runtime `Cargo.toml` dependencies section: + +```toml +pallet-asset-switch = {git = "https://github.com/KILTprotocol/kilt-node.git", branch = "release-1.14.0"} +``` + +The asset switch pallet is available in the KILT node release 1.14.0 and later. + +## Configure the pallet + +The pallet can be added one or more times to the runtime. + +For multiple deployments of the same pallet (e.g., to bridge the local currency to different remote assets), pass runtime configuration to the pallet's `Config` trait. + +```rust,ignore +pub type SwitchPool1 = pallet_asset_switch::Instance1; +impl pallet_asset_switch::Config for Runtime { + // Config +} + +pub type SwitchPool2 = pallet_asset_switch::Instance2; +impl pallet_asset_switch::Config for Runtime { + // Config +} +``` + +If a single instance is required, then use the default instance: + +```rust,ignore +impl pallet_asset_switch::Config for Runtime { + // Config +} +``` + +## The `Config` trait + +As the pallet is generic over the runtime specifics, the `Config` trait requires the following configuration parameters passed to it: + +- `type AccountIdConverter: TryConvert`: Because the `AccountId` type can be anything in the runtime, the converter is responsible for converting such a `AccountId` into a `Junction`, which is then used for some XCM processing. +- `type AssetTransactor: TransactAsset`: This component is used when charging the extrinsic submitter with the XCM fees that the chain will pay at the remote chain. For instance, if the transfer on the remote chain will cost 0.1 DOTs, the `AssetTransactor` might deduct 0.1 DOTs from the user's previously topped up balance on the source chain (more details below). +- `type FeeOrigin: EnsureOrigin`: The origin that can update the XCM fee to be paid for the transfer on the remote chain. +- `type LocalCurrency: MutateFungible`: The chain's local currency. +- `type PauseOrigin: EnsureOrigin`: The origin that can pause a switch pair, e.g., if a vulnerability is found. +- `type RuntimeEvent: From> + IsType<::RuntimeEvent>`: The aggregate `Event` type. +- `type SubmitterOrigin: EnsureOrigin`: The origin that can call the `switch` extrinsic and perform the switch. +- `type SwitchHooks: SwitchHooks`: Any additional runtime-specific logic that can be injected both before and after local tokens are exchanged for the remote assets, and before and after the remote assets are converted into local tokens. +- `type SwitchOrigin: EnsureOrigin`: The origin that can set, resume, and delete a switch pair. +- `type UniversalLocation: Get`: The location of the parachain relative to the global consensus space. +- `type WeightInfo: WeightInfo`: The computed weights of the pallet after benchmarking it. +- `type XcmRouter: SendXcm`: The component responsible for routing XCM messages to the switch pair remote location to perform the remote asset transfer from the chain's sovereign account to the specified beneficiary. + +### Benchmark-only `Config` components + +- `type BenchmarkHelper: BenchmarkHelper`: Helper trait to allow the runtime to set the ground before the benchmark logic is executed. It allows the runtime to return any of the parameters that are used in the extrinsic benchmarks, or `None` if the runtime has no special conditions to fulfil. + +## Storage + +The pallet has a single `SwitchPair` storage value that contains a `Option`. +If unset, no switch pair is configured hence no switch can happen. +When set and its status is `Running`, switches are enabled in both directions. + +Two more storage components, `PendingSwitchConfirmations` and `NextQueryId`, are used for error recovery. +Specifically, the former stores information about transfers executed locally but that have not been confirmed on the remote destination. +Once a transfer either succeeds or fails, the entry is removed from the storage and additional actions are taken as needed, e.g., reverting the transfer locally as well.Th +The latter stores an ever-increasing counter, which wraps around itself when it would overflow, and provides the value the `PendingSwitchConfirmations` storage map uses to keep track of pending confirmations. + +## Events + +The pallet generates the following events: + +- `SwitchPairCreated`: when a new switch pair is created by the required origin, e.g., governance. +- `SwitchPairRemoved`: when a switch pair is removed by the root origin. +- `SwitchPairResumed`: when a switch pair has (re-)enabled local to remote asset switches. +- `SwitchPairPaused`: when a switch pair has been paused. +- `SwitchPairFeeUpdated`: when the XCM fee for the switch transfer has been updated. +- `LocalToRemoteSwitchExecuted`: when a switch of some local tokens for the remote asset has taken place. +- `RemoteToLocalSwitchExecuted`: when a switch of some remote assets for the local tokens has taken place. +- `LocalToRemoteSwitchReverted`: when a switch fails on the remote destination and is reverted on the source chain as well. +- `LocalToRemoteSwitchFinalized`: when a switch is confirmed to have successfully taken place at the remote destination. + +## Calls + +1. `pub fn set_switch_pair(origin: OriginFor, remote_asset_total_supply: u128, remote_asset_id: Box, remote_asset_circulating_supply: u128, remote_reserve_location: Box, remote_asset_ed: u128, remote_xcm_fee: Box) -> DispatchResult`: Set a new switch pair between the local currency and the specified `remote_asset_id` on the `reserve_location`. The specified `total_issuance` includes both the `circulating_supply` (i.e., the remote asset amount that the chain does not control on the `reserve_location`) and the locked supply under the control of the chain's sovereign account on the `reserve_location`. For this reason, the value of `total_issuance` must be at least as large as `circulating_supply`. It is possible for `circulating_supply` to be `0`, in which case it means this chain controls all the `total_issuance` of the remote asset, which can be obtained by locking a corresponding amount of local tokens via the `switch` call below. + + Furthermore, the pallet calculates the account that will hold the local tokens locked in exchange for remote tokens. This account is based on the pallet runtime name as returned by the `PalletInfoAccess` trait and the value of `remote_asset_id`. The generated account must already have a balance of at least `circulating_supply`, ensuring enough local tokens are locked to satisfy all requests to exchange the remote asset for local tokens. The balance of such an account can be increased with a simple transfer after obtaining the to-be-created switch pair pool account by interacting with the [asset-switch runtime API][asset-switch-runtime-api]. + + This requirement can be bypassed with the `force_set_switch_pair` call. Only `SwitchOrigin` can call this, and in most cases it will most likely be a governance-based origin such as the one provided by referenda or collectives with high privileges. +2. `pub fn force_set_switch_pair(origin: OriginFor, remote_asset_total_supply: u128, remote_asset_id: Box, remote_asset_circulating_supply: u128, remote_reserve_location: Box, remote_asset_ed: u128, remote_xcm_fee: Box) -> DispatchResult`: The same as the `set_switch_pair`, but skips the check over the switch pair pool account balance, and requires the `root` origin for the call to be dispatched. +3. `pub fn force_unset_switch_pair(origin: OriginFor) -> DispatchResult`: Forcibly remove a previously-stored switch pair. This operation can only be called by the `root` origin. + + **Any intermediate state, such as local tokens locked in the switch pair pool or remote assets that are not switchable anymore for local tokens, must be taken care of with subsequent governance operations.** +4. `pub fn pause_switch_pair(origin: OriginFor) -> DispatchResult`: Allows the `PauseOrigin` to immediately pause switches in both directions. +5. `pub fn resume_switch_pair(origin: OriginFor) -> DispatchResult`: Allows the `SwitchOrigin` to resume switches in both directions. +6. `pub fn remote_xcm_fee(origin: OriginFor, new: Box) -> DispatchResult`: Allows the `FeeOrigin` to update the required XCM fee to execute the transfer of remote asset on the reserve location from the chain's sovereign account to the beneficiary specified in the `switch` operation. + + For example, if the cost of sending an XCM message containing a `TransferAsset` instruction from the source chain to AssetHub (reserve location) changes from 0.1 DOTs to 0.2 DOTs, the fee will need to be updated accordingly to avoid transfers failing on AssetHub, leaving the whole system in an inconsistent state. Since the pallet refunds any unused assets on the reserve location to the account initiating the switch on the source chain, it is not a big issue to overestimate this value here since no funds will be burnt or unfairly taken from the user during the switch process. +7. `pub fn switch(origin: OriginFor, local_asset_amount: LocalCurrencyBalanceOf, beneficiary: Box) -> DispatchResult`: Allows the `SubmitterOrigin` to perform a switch of some local tokens for the corresponding amount of remote assets on the configured `reserve_location`. The switch will fail on the source chain if any of the following preconditions are not met: + 1. The submitter does not have enough balance to pay for the tx fees on the source chain or to cover the amount of local tokens requested. Hence, the user's local balance must be greater than or equal to the amount of tokens requested in the switch + the cost of executing the extrinsic on the source chain. + 2. No switch pair is set or the switch pair is currently not allowing switches. + 3. There are not enough locked remote assets on the `reserve_location` to cover the switch request. e.g., if the chain sovereign account on the `reserve_location` only controls `10` remote assets, users can only switch up to `10` local tokens. Once the limit is reached, someone needs to perform the reverse operation (remote -> local switch) to free up some remote tokens. + 4. The switch pair `reserve_location` is not reachable from the source chain, because the configured `XcmRouter` returns an error (e.g., there is no XCM channel between the two chains). + 5. The configured `SwitchHooks` returns an error in either the `pre-` or the `post-` switch checks. + 6. The user does not have enough assets to pay for the required remote XCM fees as specified in the switch pair info and as returned by the configured `AssetTransactor`. + +## XCM components + +Because the switch functionality relies on XCM, the pallet provides a few XCM components that should be included in a runtime to enable the whole set of interactions between the source chain and the configured remote reserve location. + +* `AccountId32ToAccountId32JunctionConverter` in [xcm::convert][xcm-convert]: provides an implementation for the pallet's `AccountIdConverter` config component, that converts local `AccountId32`s into a `AccountId32` XCM `Junction`. This works only for chains that use `AccountId32` as their overarching `AccountId` type. +* `MatchesSwitchPairXcmFeeFungibleAsset` in [xcm::match][xcm-match]: provides an implementation of the `MatchesFungibles` that returns the input `Asset` if its ID matches the XCM fee asset ID as configured in the switch pair, if present. If no switch pair is present or if the ID does not match, it returns a [XcmExecutorError::AssetNotHandled][XcmExecutorError::AssetNotHandled], which does not prevent other matchers after it to apply their matching logic. It can be used for the `AssetTransactor` property of the [XcmExecutor::Config][XcmExecutor::Config] and as the `AssetTransactor` component of this pallet in the runtime. +* `UsingComponentsForXcmFeeAsset` in [xcm::trade][xcm-trade]: provides an implementation of `WeightTrader` that allows buying weight using the XCM fee asset configured in the switch pair. That is, if the XCM fee asset is DOT, and users need to send DOTs to this chain in order to pay for XCM fees, this component lets them use those very same DOTs that are being sent to pay for the XCM fees on this chain. Any unused weight is burnt, since this chain's sovereign account already controls the whole amount on the reserve location due to the nature of reserve-based transfers. It can be used for the `Trader` property of the [XcmExecutor::Config][XcmExecutor::Config]. +* `UsingComponentsForSwitchPairRemoteAsset` in [xcm::trade][xcm-trade]: provides an implementation of `WeightTrader` that allows buying weight using the remote asset configured in the switch pair when sending it to this chain to be switched for local tokens. Any unused weight is transferred from the switch pair account to the configured `FeeDestinationAccount`, as those local tokens do not need to back any remote assets because they have been used to pay for XCM fees. It can be used for the `Trader` property of the [XcmExecutor::Config][XcmExecutor::Config]. +* `SwitchPairRemoteAssetTransactor` in [xcm::transact][xcm-transact]: provides an implementation of `TransactAsset::deposit_asset` that matches the asset to be deposited with the remote asset configured in the switch pair '(else it returns [Error::AssetNotFound][Error::AssetNotFound]) and moves as many local tokens from the switch pair account to the specified `who` destination. It also calls into the `SwitchHooks` pre- and post- checks, and generates a `RemoteToLocalSwitchExecuted` if everything is completed successfully. It can be used for the `AssetTransactor` property of the [XcmExecutor::Config][XcmExecutor::Config]. +* `IsSwitchPairXcmFeeAsset` in [xcm::transfer][xcm-transfer]: provides an implementation of `ContainsPair` that returns `true` if the given asset and sender match the stored switch pair XCM fee asset and reserve location respectively. It can be used for the `IsReserve` property of the [XcmExecutor::Config][XcmExecutor::Config]. +* `IsSwitchPairRemoteAsset` in [xcm::transfer][xcm-transfer]: provides an implementation of `ContainsPair` that returns `true` if the given asset and sender match the stored switch pair remote asset and reserve location respectively. It can be used for the `IsReserve` property of the [XcmExecutor::Config][XcmExecutor::Config]. + +The pallet itself implements the [OnResponse trait][on-response-trait], that must be added to runtimes that deploy this pallet to allow for the error-recovery process to take place. +The trait implementation validates the received query response message based on the state of the switch pair, and then performs the required action on the pending transfer info accordingly. + +[asset-switch-runtime-api]: https://github.com/KILTprotocol/kilt-node/tree/master/runtime-api/asset-switch +[xcm-convert]: https://raw.githubusercontent.com/KILTprotocol/kilt-node/master/pallets/pallet-asset-switch/src/xcm/convert/mod.rs +[xcm-match]: https://raw.githubusercontent.com/KILTprotocol/kilt-node/master/pallets/pallet-asset-switch/src/xcm/match/mod.rs +[XcmExecutorError::AssetNotHandled]: https://github.com/paritytech/polkadot-sdk/blob/33324fe01c5b1f341687cef2aa6e767f6acf40f3/polkadot/xcm/xcm-executor/src/traits/token_matching.rs#L54 +[XcmExecutor::Config]: https://github.com/paritytech/polkadot-sdk/blob/33324fe01c5b1f341687cef2aa6e767f6acf40f3/polkadot/xcm/xcm-executor/src/config.rs#L31 +[xcm-trade]: https://raw.githubusercontent.com/KILTprotocol/kilt-node/master/pallets/pallet-asset-switch/src/xcm/trade/mod.rs +[Error::AssetNotFound]: https://github.com/paritytech/polkadot-sdk/blob/e5791a56dcc35e308a80985cc3b6b7f2ed1eb6ec/polkadot/xcm/src/v3/traits.rs#L68 +[xcm-transact]: https://raw.githubusercontent.com/KILTprotocol/kilt-node/master/pallets/pallet-asset-switch/src/xcm/transact/mod.rs +[xcm-transfer]: https://raw.githubusercontent.com/KILTprotocol/kilt-node/master/pallets/pallet-asset-switch/src/xcm/transfer/mod.rs +[on-response-trait]: https://github.com/paritytech/polkadot-sdk/blob/33324fe01c5b1f341687cef2aa6e767f6acf40f3/polkadot/xcm/xcm-executor/src/traits/on_response.rs#L29 diff --git a/versioned_docs/version-1.0.0/develop/09_polarpath/_category_.json b/versioned_docs/version-1.0.0/develop/09_polarpath/_category_.json new file mode 100644 index 000000000..e617cba37 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/09_polarpath/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Polar path", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/develop/_category_.json b/versioned_docs/version-1.0.0/develop/_category_.json new file mode 100644 index 000000000..84922e6c0 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Develop", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/01_overview.md b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/01_overview.md new file mode 100644 index 000000000..319e47579 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/01_overview.md @@ -0,0 +1,46 @@ +--- +id: overview +title: Overview +--- + +Collators are the most important members of the network as they not only maintain the state by running a KILT full node, but are also allowed to change it by building state transition proofs and sharing them with the Relay Chain validators. +Generally speaking, the latter finalize the proposed block if and only if it represents a valid state transition. + +It is important to note that elusive collators can never get invalid blocks finalized thanks to the design security umbrella provided by the Relay Chain. +Thus, the most harm dishonest collators can do is to slow down or halt the network. +As long as at least one honest collator exists, the parachain is secured and fully operative. +However, the block time would be slower than with a full set of honest and functioning collator nodes. + +If you want to join the KILT network as a collator, you have to run a full node of the blockchain and set up your session keys. +You are also required to hold a minimum amount of self-staked tokens to qualify for a collator seat. +Once you have finished the mandatory steps described throughout the following sections, you can be added to the candidate pool. +The candidate pool is sorted first by the total staking amount including delegations. +If the pool is full and the new candidate has the exact same stake amount as the last member of the pool (by total stake), the blockchain favors the candidate that has been in the pool longest. +Thus, only the collators with the highest total stake are periodically selected to be eligible block authors. + +:::info +You can find more information about collators and the Relay Chain-parachain-interaction in the [**official Polkadot Wiki**](https://wiki.polkadot.network/docs/learn-collator). +::: + +## Roadmap + +We will guide you through the steps to become a collator. +First, we will discuss the hardware requirements and how you could test the performance of your node. +Then, we go over a few configuration options and show you how to set up and start a KILT collator, including how to generate your sessions keys and join the pool of collator candidates. + +:::info +In case you are already collating, you could check out the advanced section. +There you will learn how to [**monitor**](../02_advanced_collator_section/04_monitoring.md) or [**benchmark**](../02_advanced_collator_section/06_benchmarking.md) your node, [**adjust your stake**](../02_advanced_collator_section/01_adjust_stake.md), [**fix problems**](../06_troubleshooting.md) or [**leave the network**](../02_advanced_collator_section/02_exit.md). +::: + +## Join the Community + +As a collator you are required to keep track of updates and changes to configuration. +You should also be accessible in case there is an issue with your node, as this affects not only your and your delegator's rewards, but also the entire network negatively. +We recommend joining the [KILT Community Discord server](https://discord.gg/hX4pc8rdHS) and following (at least) the **collators** and **staking** channels. +There, you will receive announcements about future updates and potential mandatory client upgrades. +Moreover, the channels serve as a discussion hub for collators and delegators. + +After joining Discord, feel free to send a DM to [`Dudley | KILT protocol#6222`](https://discordapp.com/users/687952993156726784) or [`William | KILT Protocol#4433`](https://discordapp.com/users/w3n;williamfreude#4433) to introduce yourself. +Of course, you can also directly announce yourself in one of the two channels mentioned above. +This way, the community knows who to contact in case there are any issues with your node. diff --git a/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/02_hardware_requirements.md b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/02_hardware_requirements.md new file mode 100644 index 000000000..c590b8349 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/02_hardware_requirements.md @@ -0,0 +1,16 @@ +--- +id: hardware-requirements +title: Minimum Hardware Requirements +--- + +The KILT blockchain extrinsic weights were calculated using the following hardware: + +- **OS** - Ubuntu 20.04.2 +- **CPU** - AMD Ryzen 7 1700X +- **Storage** - A NVMe solid-state drive. Should be reasonably-sized to deal with blockchain growth. Starting around 250GB will be okay for the next year of the KILT parachain and Polkadot Relay Chain, but it will mostly likely grow after that and will have to be re-evaluated on a regular basis. +- **Memory** - 16GB + +Although the aforementioned hardware is by no means the minimum spec required, the new node *is recommended* to be as close as possible to these capabilities in all the categories. +Having more performant hardware reduces the probability that the node will not be able to produce and propose a valid block on time during the allocated block production slot, missing out on the collating rewards. + +You can measure the performance of the new hardware by benchmarking it using [the steps described in the benchmarking section](../02_advanced_collator_section/06_benchmarking.md). diff --git a/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/03_setup_node.md b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/03_setup_node.md new file mode 100644 index 000000000..f029d5870 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/03_setup_node.md @@ -0,0 +1,183 @@ +--- +id: setup-node +title: Set Up a Node +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import StartNodeDocker from './_03_start_node_docker.mdx'; +import StartNodeBinary from './_03_start_node_binary.mdx'; + +There are several ways to build and run a collator node. +Here, we show both how to use a Docker image and how to compile the source code directly from [our chain repository](https://github.com/KILTprotocol/kilt-node). + +There are currently two different runtimes (i.e., two different parachain environments) that a KILT collator can be part of: + +- **Spiritnet**: the official public network, which contains only stable and thoroughly-tested features. +- **Peregrine**: the public test network whose runtime is as close to that of Spiritnet as possible. It can be used to try things out before executing them on the production Spiritnet chain, which involves spending tokens that have real monetary value. + +Each runtime has its own benchmark measurements. + +:::info +The remainder of this guide explaining how to set up and run a collator is mainly for the official **Spiritnet** parachain. +However, we recommend trying out the setup on our Peregrine testnet first. +Hence, at each step where it is applicable, we indicate what differs between the Peregrine and Spiritnet configuration for the collator node to join either network. +::: + +## Configuration + +Running a collator requires a few configuration parameters. +Some of the parameters might appear twice in the command to start the collator, because a parachain collator actually runs two blockchains. +The parameters that are listed before the `--` are related to the parachain node itself (the KILT blockchain), whereas the parameters following the `--` are related to the Relay Chain, e.g., Kusama or Polkadot. + +The following is a description of some of the parameters that can be set when spinning up a parachain collator node. + +### RPC and WS Endpoints + +As a collator, you need to link your session keys to your collator account. +These session keys can be generated by calling an RPC endpoint that the collator optionally exposes. +Exposing the RPC endpoint can be done using the following parameters: + +``` +--rpc-port=9944 +--rpc-cors=all +--rpc-methods=unsafe +--unsafe-rpc-external // ONLY for Docker-based setups +``` + +Exposing the RPC endpoint of a collator does not imply that it becomes accessible via the PolkadotJS Apps interface, because this requires a WebSocket to connect to the node. + +By default, the WebSocket port used by the node is configured to be `9944`, but it can be changed by specifying a different value with `--rpc-port=`. + +Connecting from a remote host to either the collator RPC endpoint or WS endpoint requires explicitly exposing the endpoint to the public with the `--rpc-external` option. + +:::danger + +Be aware that it is highly discouraged to publicly expose an RPC endpoint, especially if it allows the execution of unsafe RPC calls! +You should be the only one able to call the RPC endpoint. +For a secure setup, follow the instructions in the previous section about [generating the session keys](./04_session_keys.md). +::: + +### WASM Runtime Execution + +A KILT collator node should use the `--execution=wasm` parameter for both the Relay Chain and parachain collation. +The alternative to WASM runtime execution is native runtime execution, which might be faster but can, in some cases, deviate from the WASM execution logic and result in a different state. +When this happens, the collator node will crash and will stop synchronizing with the network and stop producing blocks. +Since the WASM runtime logic is part of the blockchain state itself and hence represents the single source of truth, all nodes should execute the WASM version of the runtime logic. + +### Specify the Right Chainspec + +The `--chain` parameter indicates which blockchain the KILT collator node will join. +This parameter must be specified for both the parachain **and** the Relay Chain, since both chains are, as a matter of fact, separate blockchains. +The KILT parachain accepts an additional parameter to select the environment to use for the WASM runtime execution. +This can either be `peregrine` or `spiritnet`. + +Hence, to start a collator node for the Spiritnet network, the parameter would be `--chain=spiritnet`. +Unfortunately, there is no hardcoded chain spec for the Peregrine network, so the full path of the chainspec file must be provided `--chain=/node/dev-specs/kilt-parachain/peregrine-kilt.json`. +Please refer to the [KILT node repository](https://github.com/KILTprotocol/kilt-node/blob/master/chainspecs/peregrine/peregrine-paseo.json) or the [Docker image](https://hub.docker.com/r/kiltprotocol/kilt-node/tags) for more information. + +### Specify the Blockchain Storage Path + +The `--base-path` parameter specifies where all the persistent files must be stored. +By default, the session keys will also be stored in the *base path*, but we recommend separating them from the other files. +This makes sure that the keyfiles are not accidentally lost or published when the blockchain database is either backed up or restored. +You can configure where to store the session keys using the `--keystore-path` option. +Since the collator will collate only for the parachain, there is no need to add this to the relaychain part of the command. + +## Obtain the Node Executable + + + + +In order to build the KILT full node executable, you need to have [rustup and Rust installed](https://www.rust-lang.org/tools/install). + +After cloning the repository, you can build the executable by running the `cargo build` command below from the root directory. + +```bash +# Clone the repository +git clone https://github.com/KILTprotocol/kilt-node.git +# Check out master branch +git checkout master +# Build the executable from source enabling all the optimizations with --release. +cargo build --release -p kilt-parachain +``` + +:::info +You must not use the default `develop` branch to build the executable. +Instead, the [latest release](https://github.com/KILTprotocol/kilt-node/releases) from `master` should be used. +::: + +The compiled executable can be found in `./target/release/kilt-parachain` after the build process completes successfully. + + + + +Simply pull the [latest Docker image](https://hub.docker.com/r/kiltprotocol/kilt-node/tags): + +```bash +docker pull kiltprotocol/kilt-node:latest +``` + + + + +## Start the Node + + + + + +In either case, if the node needs to be reachable via PolkadotJS Apps, the `--rpc-external` flag must be added to the collator options, before the `--` divider. + + + + + +In either case, if the node needs to be reachable via PolkadotJS Apps, the `--rpc-external` flag must be added to the collator options, before the `--` divider, and the WS port must be exposed from the container with an additional `-p 9944:9944` parameter. +Make sure that you only expose the websocket port publicly if you are not running a collator. + +In addition to the websocket, you need to expose the ports for p2p connections. +In the the command above these are `30333` for the parachain and `30334` for the relaychain. +Make sure you configure your firewall in a way that allows incoming and outgoing connections to these ports. + +The Docker command will map the database files for the Relay Chain and parachain as well as the keystore directory to `~/data` on the host system using the flag `-v $HOME/data:/data`. +That way the blockchain database files are not lost when and if the Docker container is removed and can be mounted back on the next containers. + +The Docker container runs as an user with id 1000 and will try to access the mapped volume and the files it contains. +If the files are not owned by a user with id 1000, this will result in an error. +If that is the case, run `sudo chown -R 1000:1000 $HOME/data` to give the container access. + + + + +## Sync the Blockchain State + +Before a collator can author blocks, the node needs to fully sync up with both the parachain and the Relay Chain. +Depending on the size of the blockchain states, it may take a number of hours to few days for the node to catch up. +More details can be found on the [Polkadot network docs](https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#synchronize-chain-data). + +:::note Example of node sync: + +```Example of node sync +2021-06-17 02:34:34 ๐Ÿ” Discovered new external address for our node: /ip4/100.102.231.64/tcp/30333/ws/p2p/12D3KooWLE7ivpuXJQpFVP4fuuutAqEsk8nrNEpuR3tddqnXgLPB +2021-06-17 02:34:36 โš™๏ธ Syncing 409.2 bps, target=#8062689 (5 peers), best: #3477 (0x63adโ€ฆe046), finalized #3072 (0x0e4cโ€ฆf587), โฌ‡ 153.2kiB/s โฌ† 12.9kiB/s +2021-06-17 02:34:37 ๐Ÿ” Discovered new external address for our node: /ip4/100.111.175.0/tcp/30333/ws/p2p/12D3KooWLE7ivpuXJQpFVP4fuuutAqEsk8nrNEpuR3tddqnXgLPB +2021-06-17 02:34:38 ๐Ÿ” Discovered new external address for our node: /ip4/100.100.176.0/tcp/30333/ws/p2p/12D3KooWLE7ivpuXJQpFVP4fuuutAqEsk8nrNEpuR3tddqnXgLPB +2021-06-17 02:34:41 โš™๏ธ Syncing 386.2 bps, target=#8062690 (7 peers), best: #5409 (0x1d76โ€ฆ8c3d), finalized #5121 (0x8ad1โ€ฆb6dc), โฌ‡ 96.1kiB/s โฌ† 10.9kiB/s +2021-06-17 02:34:46 โš™๏ธ Syncing 394.8 bps, target=#8062691 (11 peers), best: #7383 (0x0689โ€ฆ6f1e), finalized #7168 (0x72a9โ€ฆ8d8c), โฌ‡ 352.9kiB/s โฌ† 5.1kiB/s +2021-06-17 02:34:51 โš™๏ธ Syncing 347.0 bps, target=#8062692 (12 peers), best: #9118 (0x66fcโ€ฆcce3), finalized #8704 (0x14c9โ€ฆ705e), โฌ‡ 62.7kiB/s โฌ† 1.7kiB/s +``` + +::: diff --git a/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/04_session_keys.md b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/04_session_keys.md new file mode 100644 index 000000000..b061db105 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/04_session_keys.md @@ -0,0 +1,124 @@ +--- +id: session-keys +title: Set and Rotate Session Keys +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +As a collator, you need to link your session keys to your collator account. +Once linked, the keys are used to identify your collator node. +Your collator address will receive the permit to build blocks, but the session keys pass this permit to your node. +To check whether the account has already some session keys set, the RPC functions `author > hasKey(publicKey, keyType)` and `author > hasSessionKeys(sessionKeys)` can be called. + +![](/img/chain/author-hasKey.png) + +:::info +The session keys associate a collator node with an account on the blockchain. +They are hot keys that must be kept online. +It is recommended to change them throughout sessions. +::: + +## Generate New Session Keys {#generating-session-keys} + +:::warning + +Make sure that no unauthorized party is able to access the RPC endpoint of the collator. +Use SSH forwarding for the RPC port when needing to perform some RPC operations on the node with + +``` +ssh -L 127.0.0.1:9944:127.0.0.1:9944 @ +``` +::: + +There are three ways to create the session keys. +We recommend using the curl command on the same host that the node is running or from a host that has an active SSH tunnel with it. +This way there is no need to add the `--unsafe-rpc-external` argument to the node. +Nevertheless, the session keys can also be rotated using the PolkadotJS Apps interface or by directly storing the new key in the node's keystore. + + + + + +A collator can use the following command to rotate the session key. + +```bash +curl -H "Content-Type: application/json" -d '{"id":1, "jsonrpc":"2.0", "method": "author_rotateKeys", "params":[]}' http://localhost:9944 +``` + +The answer should look like the JSON object below. +The `result` key is the HEX-encoded public part of the newly created session key. + +``` +{"jsonrpc":"2.0","result":"0xda3861a45e0197f3ca145c2c209f9126e5053fas503e459af4255cf8011d51010","id":1} +``` + + + + +In order to use the PolkadotJS Apps UI, the node WebSocket endpoint must be reachable. +This can be done either by publicly exposing it with the `--rpc-external` flag, which is discouraged, or by setting up an SSH tunnel for the WebSocket endpoint with `ssh -L 127.0.0.1:9944:127.0.0.1:9944 @`. +If the latter option is chosen, there is no need to have a separate SSH tunnel for RPC traffic as all the RPC operations can be performed directly from the now-accessible PolkadotJS Apps interface. + +![](/img/chain/chain-menu.png) + +![](/img/chain/chain-selection.png) + +After connecting to the node, select `Developer -> RPC calls -> author -> rotateKeys()` from the menu. +This will generate a new session key which replaces the existing one. + +![](/img/chain/author-rotateKeys.png) + + + + +A keypair can be created using the [subkey tool](https://substrate.dev/docs/en/knowledgebase/integrate/subkey) by following the steps in the tool's official documentation. +The generated private and public keys can then be saved within the keystore folder of the collator node to be used as session keys. + +``` +โฏ subkey generate -n kilt +Secret phrase `very secure private key you should not use the example private key` is account: + Secret seed: 0xcafe97b4b8f0adc1adeb3feef30bf2e5b9d49ddd897f268c8027c850DeadBEEF + Public key (hex): 0xda3861a45e0197f3ca145c2c209f9126e5053fas503e459af4255cf8011d51010 + Account ID: 0xda3861a45e0197f3ca145c2c209f9126e5053asdg03e459af4255cf8011d51010 + SS58 Address: 4srC1aowD94H9UH9xsnfv7XV6oHU6dhCymKYZHWKsdddaP29 +``` + +The name of the file must be the *public* key prepended with `61757261` (HEX representation of `aura`) and without the `0x` prefix, while the content of the file has to be the secret phrase. + +![](/img/chain/session-key-file.png) + +For instance, with the keypair generated in the example, the session key file would be stored at the path `./keystores/61757261da3861a45e0197f3ca145c2c209f9126e5053fas503e459af4255cf8011d51010`. + + + + + +:::info +The rotation of the session key should be done periodically to ensure that your collator can remain secure and safe from attacks. +You can find more information about session keys in the [Substrate Documentation](https://docs.substrate.io/v3/concepts/session-keys/#generation-and-use). +::: + +Once a new session key is generated, you must then link that key to your collator account in order to receive rewards for producing new blocks.. +This operation is performed by submitting a signed extrinsic to the blockchain. + +For Spiritnet, the endpoint is [wss://spiritnet.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkilt-rpc.dwellir.com#/explorer), while for Peregrine it is [wss://peregrine.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine-stg.kilt.io#/explorer). + +`Developer -> Extrinsics -> Submission` + +1. Select your collator KILT address as the extrinsic submitter (the *using the selected account* field) +2. Set up the following extrinsic: `session -> setKeys(keys, proof)` + - `keys` -> the public session key (`0xda3861a45e0197f3ca145c2c209f9126e5053fas503e459af4255cf8011d51010` in the example above) + - `proof` -> the proof of ownership. It can be set to `0x00` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/session-setKeys.png) + +Once the extrinsic is executed, you will have linked the new session key to your account and can start receiving rewards for producing new blocks. +However, the new session key does not become effective immediately but with the start of the next session. diff --git a/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/05_join_collators.md b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/05_join_collators.md new file mode 100644 index 000000000..a47b46e64 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/05_join_collators.md @@ -0,0 +1,62 @@ +--- +id: join +title: Join the Collator Candidate Pool +--- + +import StakingTxDisclaimer from '../_disclaimer_staking_tx.md'; + +Before a collator can author blocks, the node needs to fully sync up with both the KILT parachain and the Polkadot Relay Chain. +Depending on the size of the blockchain states, it may take from a number of hours to few days for the node to fully synchronize. +More details can be found on the [Polkadot network docs](https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#synchronize-chain-data). + +After you have finished with the setup, you can finally tell the chain that you are ready to collate and join the pool of candidates. + +:::warning +These steps should be followed only once your collator node has successfully [**linked a session key to its address**](./04_session_keys.md) and synced the parachain and relaychain states by following the previous steps. +::: + +## Minimum Token Requirement + +The maximum number of **active** collators is currently (2022-05-05) 16 on Peregrine and 30 on Spiritnet. + +In order to become a collator, you must stake +- at least *10,000 KILT* tokens and +- at most *200,000 KILT* tokens. + +## Execute the Joining Transaction + +The collator must call an extrinsic `parachainStaking -> joinCandidates(stake)` with the desired stake to join the candidate pool. + + + +![](/img/chain/parachainStaking-joinCandidates.png) + +1. Select your collator KILT address as the extrinsic submitter (the *using the selected account* field) +2. Select the following extrinsic: `parachainStaking -> joinCandidates(stake)` +3. Insert the staked KILT amount for your collator (any value between `10,000,000,000,000,000,000` and `20,000,000,000,000,000,0000`) +4. Sign and submit the extrinsic (the *Submit Transaction* button) + +:::info +A recent change in the blockchain metadata resulted in a change in the UI regarding how balances are shown. +In the current version of PolkadotJS Apps, specifying 1 KILT requires adding 15 trailing `0`s. +So, for instance, 1 KILT needs to be written as `1,000,000,000,000,000`, while 10,000 KILT would be written as `10,000,000,000,000,000,000`. +::: + +## Check Your Position in the Collators Queue + +As a collator candidate you can check the current top candidates to see their position and the required staked amount to become an active collator, i.e., to start authoring new blocks. + +![](/img/chain/parachainStaking-topCandidates1.png) + +In Polkadot JS ([wss://spiritnet.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkilt-rpc.dwellir.com#/explorer), or [wss://peregrine.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine-stg.kilt.io#/explorer)) go to `Developer -> Chain state -> Storage` + +1. Selected state query: `parachainStaking -> topCandidates(): ParachainStakingSetOrderedSet` +2. Execute the query by pressing the "+" button on the right side + +Now, you should see a window which lists collators (the *owner* field) ordered by their total stake (the *amount* field) from greatest to lowest. + +![](/img/chain/parachainStaking-topCandidates2.png) + +If a collator has enough self-stake and delegator stake it will be selected to collate. +The last address in the list will be the least staked candidate. +A time period of two sessions must pass before the selected collator will be authoring blocks, e.g., after the remainder of the current session and the entire next one. diff --git a/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/_03_start_node_binary.mdx b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/_03_start_node_binary.mdx new file mode 100644 index 000000000..58dde2037 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/_03_start_node_binary.mdx @@ -0,0 +1,61 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import styles from '@site/src/pages/styles.module.css'; + +Please select your target network: + +
+ + + To join the Spiritnet network, run: + + ```bash= + ./target/release/kilt-parachain \ + --chain=spiritnet \ + --runtime=spiritnet \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-methods=unsafe \ + --name="name of collator" \ + --execution=wasm \ + --listen-addr=/ip4/0.0.0.0/tcp/30333 \ + --base-path=$HOME/data/parachain \ + --keystore-path=$HOME/data/keystore \ + --collator \ + -- \ + --chain=polkadot \ + --listen-addr=/ip4/0.0.0.0/tcp/30334 \ + --base-path=$HOME/data/relay \ + --execution=wasm + ``` + + + + To join the Peregrinenetwork, run: + + ```bash= + ./target/release/kilt-parachain \ + --chain=./dev-specs/kilt-parachain/peregrine-kilt.json \ + --runtime=peregrine \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-methods=unsafe \ + --name="name of collator" \ + --execution=wasm \ + --listen-addr=/ip4/0.0.0.0/tcp/30333 \ + --base-path=$HOME/data/parachain \ + --keystore-path=$HOME/data/keystore \ + --collator \ + -- \ + --chain=./dev-specs/kilt-parachain/peregrine-relay.json \ + --listen-addr=/ip4/0.0.0.0/tcp/30334 \ + --base-path=$HOME/data/relay \ + --execution=wasm + ``` + + + +
diff --git a/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/_03_start_node_docker.mdx b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/_03_start_node_docker.mdx new file mode 100644 index 000000000..ec0966252 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/_03_start_node_docker.mdx @@ -0,0 +1,65 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import styles from '@site/src/pages/styles.module.css'; + +Please select your target network: + +
+ + + + To start the **Spiritnet** collator container, run: + ```bash= + docker run -p 127.0.0.1:9944:9944 -p 30333:30333 -p 30334:30334 \ + -v ~/data:/data kiltprotocol/kilt-node:latest \ + --chain=spiritnet \ + --runtime=spiritnet \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-methods=unsafe \ + --unsafe-rpc-external \ + --name="name of collator" \ + --execution=wasm \ + --listen-addr=/ip4/0.0.0.0/tcp/30333 \ + --base-path=/data/parachain \ + --keystore-path=/data/keystore \ + --collator \ + -- \ + --chain=polkadot \ + --listen-addr=/ip4/0.0.0.0/tcp/30334 \ + --base-path=/data/relay \ + --execution=wasm + ``` + + + + + To start the **Peregrine** Collator container, run: + ```bash= + docker run -p 127.0.0.1:9944:9944 -p 30333:30333 -p 30334:30334 \ + -v ~/data:/data kiltprotocol/kilt-node:latest \ + --chain=/node/dev-specs/kilt-parachain/peregrine-kilt.json \ + --runtime=peregrine \ + --rpc-port=9944 \ + --rpc-cors=all \ + --rpc-methods=unsafe \ + --unsafe-rpc-external \ + --name="name of collator" \ + --execution=wasm \ + --listen-addr=/ip4/0.0.0.0/tcp/30333 \ + --base-path=/data/parachain \ + --keystore-path=/data/keystore \ + --collator \ + -- \ + --chain=/node/dev-specs/kilt-parachain/peregrine-relay.json \ + --listen-addr=/ip4/0.0.0.0/tcp/30334 \ + --base-path=/data/relay \ + --execution=wasm + ``` + + + +
diff --git a/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/_category_.json b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/_category_.json new file mode 100644 index 000000000..c35bfb041 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/01_become_a_collator/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Become a Collator", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/01_adjust_stake.md b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/01_adjust_stake.md new file mode 100644 index 000000000..c9bf1cc63 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/01_adjust_stake.md @@ -0,0 +1,41 @@ +--- +id: adjust-stake +title: Adjust Your Own Stake +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import StakingTxDisclaimer from '../_disclaimer_staking_tx.md'; + +A collator can increase or decrease their stake, always within the limits of the minimum and maximum allowed stake amounts. +The corresponding extrinsics for these operations are `parachainStaking -> candidateStakeMore(more)` and `parachainStaking -> candidateStakeLess(less)`. + + + + + + +![](/img/chain/parachainStaking-candidateStakeMore.png) + +1. Select your collator KILT address as the extrinsic submitter (the *using the selected account* field) +2. Select the extrinsic: `parachainStaking -> collatorStakeMore` +3. Choose the stake amount that you want to add or remove from your current stake (the *more* field). +You can add up to the maximum of 200,000 KILT and your maximum available balance. +4. Sign and submit the extrinsic (the *Submit Transaction* button) + + + + +![](/img/chain/parachainStaking-candidateStakeLess.png) + +1. Select the collators's KILT address as the extrinsic submitter (the *using the selected account* field) +2. Select the extrinsic: `parachainStaking -> collatorStakeLess` +3. Choose the desired stake amount which you want to remove from your current stake (the *less* field). +You can reduce down to minimum collator amount (10,000 KILT), e.g., any value up to the difference of your current stake and the minimum will be accepted. +4. Sign and submit the extrinsic (the *Submit Transaction* button) + + + \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/02_exit.md b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/02_exit.md new file mode 100644 index 000000000..8d2e6c6c0 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/02_exit.md @@ -0,0 +1,65 @@ +--- +id: exit +title: Leave the Collator Candidate Pool +--- + +import StakingTxDisclaimer from '../_disclaimer_staking_tx.md'; + +If you intend to stop collating or stop being a collator candidate, you have to go through three stages until your staked tokens are unlocked and your collator state is purged from the chain. + +:::info +Unfortunately, exiting is not a simple process for security reasons. +Since a picture paints a thousand words, you can find a visualization of this process in the following [**lifecycle section**](./03_collator_lifecycle.md). +::: + +## Initiate the Exit Request + +First, signal your intent by calling `parachainStaking -> initLeaveCandidates`. +You will then be removed from the `CandidatePool` and your state switches from `Active` to `Leaving(leaveRound)`, where `leaveRound` reflects the number of sessions that have to elapse before you can definitely leave the set of collators. +You still need to stay online and build blocks for the current and next sessions. +Since each session lasts 2 hours, **the maximum amount of time you will need to wait is 4 hours**. +Of course, you will continue to receive rewards for the blocks your collating node will author. +A leaving candidate cannot be selected as an active collator for the sessions from this point on. +Moreover, you cannot receive new delegations and existing delegations cannot be adjusted. +However, delegations can still be revoked. + + + +![](/img/chain/parachainStaking-initLeaveCandidates.png) + +1. Select your collator KILT address as the extrinsic submitter (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> initLeaveCandidates` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +## Execute the Exit Request + +Once the current and next sessions have elapsed (which can take at most 4 hours), you can call `executeLeaveCandidate` to remove all of your `Candidate` associated storage. +You should be certain that you wish to leave as there is no turning back afterwards. +If you wish to become a candidate at a later stage, you will have to apply again and will not have your former delegations. + +![](/img/chain/parachainStaking-executeLeaveCandidates.png) + +1. Select one of your KILT addresses with sufficient funds to pay for the transaction fee (~5 milli KILT) as the extrinsic submitter (the *using the selected account* field) +_NOTE: Of course, you can chose your collator account._ +2. Select the appropriate extrinsic: `parachainStaking -> executeLeaveCandidates` +3. Select the `Id` option (the *MultiAddress (LookupSource) field*) +4. Select the collator account (the *Id: AccountId* field) +5. Sign and submit the extrinsic (the *Submit Transaction* button) + +## Cancel the Exit Request + +You still have not completed your exit request, you can still cancel it by calling `cancelLeaveCandidates`, which will succeed if the `CandidatePool` is not already full. +Upon interruption of your exit procedure, your state switches back to `Active` and you maintain all the previous delegations, since everything has remained untouched in the meantime. +Moreover, if you are one of the top staked candidates, you will automatically become a collator again at the end of the second round from this point, which can take as long as 4 hours in the worst case. + +![](/img/chain/parachainStaking-cancelLeaveCandidates.png) + +1. Select your collator KILT address as the extrinsic submitter (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> cancelLeaveCandidates` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +## Unlock Your Stake + +If you have executed the exit request you cannot immediately unlock your previously staked tokens. +There is a delay of 7 days in block time before you can free them by calling `unlockUnstaked`. +See [here](../05_unlock_unstaked.md) for a step-by-step tutorial. diff --git a/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/03_collator_lifecycle.md b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/03_collator_lifecycle.md new file mode 100644 index 000000000..e9f1911d9 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/03_collator_lifecycle.md @@ -0,0 +1,44 @@ +--- +id: lifecycle +title: Lifecycle of a Collator +--- + +The following diagram visualizes the full lifecycle of a collator from owning free KILT to joining the collator candidate pool, initiating the exit, waiting for the stake to be unlockable and eventually unlocking their bond. +It summarizes the previous [exit](./02_exit.md) section. + +
+ +```mermaid +flowchart TD + A["Hold (at least) 10K KILT"] -->|join_candidates| B(Candidate) + B --->|init_leave_candidates|I("Leaving Candidate\n(locked)") + I ---> G{"2 Sessions (4h)\n passed?"} + I -->|cancel_leave_candidates|B + G -->|no|I + G -->|yes|H("Leaving Candidate\n(unlocked)") + H -->|execute_leave_candidates|J("Locked Balance") + H -->|cancel_leave_candidates|B + J --->K{"At least 7 days\npassed?"} + K -->|yes|L("Balance with expired lock") + K -->|no|J + L -->|unlock_unstaked|A + + %% style assignment + A:::unstakedFreeKilt + B:::activeCollator + I:::leavingLocked + G:::leavingLocked + H:::leavingUnlocked + J:::leavingUnlocked + K:::leavingUnlocked + L:::stakedReleasableKilt + + %% style definition + classDef leavingLocked fill:#FFF4BD, stroke:none, color:black; + classDef leavingUnlocked fill:#F1C0B9, stroke:black, stroke-width:1px, color:black; + classDef unstakedFreeKilt fill:#85D2D0, stroke:black, stroke-width:1px, color:black; + classDef activeCollator fill:#94C973, stroke:#333, stroke-width:2px, color:black; + classDef stakedReleasableKilt fill:#F37970, stroke:black, color:black; +``` + +
diff --git a/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/04_monitoring.md b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/04_monitoring.md new file mode 100644 index 000000000..89052ec0b --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/04_monitoring.md @@ -0,0 +1,59 @@ +--- +id: monitoring +title: Set Up Node Monitoring +--- + +It would be ideal if the host being monitored is not the host monitoring, i.e., if the monitoring process does not run on the same host as the collator process. +However, in cases of limited resources, the two can also co-exist on the same host. + +The monitoring process collects two types of metrics: **Node Exporter metrics** and **blockchain metrics**. +The monitoring infrastructure can either be run as a local grafana cluster or as a [cloud-based solution](https://grafana.com/products/cloud/). + +:::info +For cloud-based solutions, the prometheus process must be publicly accessible, e.g., via a reverse proxy. +::: + +## What Will Be Installed + +The Docker compose setup creates and deploys up to four containers, all of which are optional: + +- **Node Exporter**: collects metrics from the host machine including CPU, memory, and storage usage, and network traffic statistics +- **Prometheus**: stores the metrics collected by Node Exporter and collects additional metrics from the blockchain node +- **Grafana**: shows the collected metrics in a customizable dashboard and can be configured to send alerts when certain conditions are met +- **Collator**: the collator node itself, which runs one of the available KILT runtimes + +## Installation +Install the latest version of docker-compose from the [official docker-compose installation guide](https://docs.docker.com/compose/install/), then: + +1. Clone the [entire KILT chain repo](https://github.com/KILTprotocol/docs) or download only the [monitoring template](https://github.com/KILTprotocol/docs/tree/master/collator). +2. Change directory to the above with ```cd docs/collator``` +3. Edit the `.env` file and insert your desired grafana admin user and password +4. Depending on the installation type either: + - run `docker-compose up -d` to install only Node Exporter and prometheus or + - run `docker-compose up --profile grafana -d` to install Node Exporter, prometheus and grafana or + - run `docker-compose --profile collator --profile grafana up -d` to install Node Exporter, prometheus, grafana **and** a Collator node + +5. Secure the endpoints: + 1. Install nginx with certbot ```sudo apt install nginx certbot python3-certbot-nginx``` + 2. If ufw is enabled, allow Nginx Full: ```sudo ufw allow 'Nginx Full'``` + 3. Generate an SSL certificate: ```sudo certbot --nginx -d ${DOMAIN_OF_SERVER_NAME}``` + 4. Enable certificate renewal by editing the crontab list ```crontab -e``` and appending ```0 5 * * * /usr/bin/certbot renew --quiet``` + 5. Reload nginx after replacing the default nginx file with prometheus endpoint (if grafana cloud is chosen) or grafana endpoint (if grafana installed) by adding the following config snippet to `/etc/nginx/sites-enabled/default` + ``` + location / { + proxy_pass http://localhost:9090/; #proxy_pass http://localhost:3000/; + } + ``` + 6. Enable basic authentication by replacing the default password in `prometheus.yml` using ``` htpasswd -nBC 10 "" | tr -d ':\n' ``` + +## Testing the Configuration +The configuration can be checked by visiting `https://localhost:3000` and authenticating with the username and password set in `.env` at step 3. + +## Configuring Alert Notification Channel +Choose any of the supported notification channels and follow the [grafana documentation](https://grafana.com/docs/grafana/latest/alerting/) to receive alerts and notifications. + +Overall, for monitoring we recommend the following stack: +- Prometheus +- Grafana +- Node exporter +- Nginx \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/05_bootnodes.md b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/05_bootnodes.md new file mode 100644 index 000000000..2790860d7 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/05_bootnodes.md @@ -0,0 +1,40 @@ +--- +id: bootnodes +title: Bootnodes +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +The bootnodes are required to connect to the peer-to-peer network and discover additional peers. +The addresses are included in the chain spec, so there is no need to add them as a parameter to the start command. +For the sake of completeness, the bootnodes are listed below: + + + + + For **Spiritnet**, the parachain bootnodes are: + +``` +--bootnodes=/dns4/hetzner-1.kilt.io/tcp/30333/p2p/12D3KooWKU8ehzuKAzHEMCy4i4kpJtgCFBCYYhqcub4Y1HR8FRoT \ +--bootnodes=/dns4/hetzner-2.kilt.io/tcp/30333/p2p/12D3KooWDJzJ7TRNKvE2DWXMSSsoKR5TgxsnNy3W1eCBPveX6g9i \ +--bootnodes=/dns4/node-6840569230186737664-0.p2p.onfinality.io/tcp/11578/ws/p2p/12D3KooWQapPfoSDxLBnsVZmpRA1yNApXEAEuhexPcFa7fECqpHa \ +--bootnodes=/dns4/node-6840781141641752576-0.p2p.onfinality.io/tcp/28779/ws/p2p/12D3KooWKMCaxjsvaNkYkdQGnPQnkYFouHFdJ3S36aBhV6QTXzaE \ +--bootnodes=/dns4/node-6840781099853901824-0.p2p.onfinality.io/tcp/15360/ws/p2p/12D3KooWLWSE85c5PSsgo62Dy5UM68Sx8p3vnJvtvDVC8QHXFpR +``` + + + + +For **Peregrine**, the parachain bootnodes are: + +``` +--bootnodes=/dns4/eyrie-4.kilt.io/tcp/30371/p2p/12D3KooWALJtiCZzcUPVsCa5f5egGfQyFhPY67kKosDw95bJqK7M +--bootnodes=/dns4/eyrie-5.kilt.io/tcp/30372/p2p/12D3KooWCRgcGtFRsvqxqgysiR6Ah9SAzUNkM12Ef9sy59ZEspSQ +``` + + + diff --git a/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/06_benchmarking.md b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/06_benchmarking.md new file mode 100644 index 000000000..712fbd99f --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/06_benchmarking.md @@ -0,0 +1,40 @@ +--- +id: benchmarking +title: Benchmark Your Collator +--- + +To enable benchmarking, the collator must enable the benchmarking feature from a new build of the `kilt-parachain`. + + + +:::caution Don't use this binary for running the Collator! +```bash= +cargo build --release -p kilt-parachain --features=runtime-benchmarks +``` +::: + +The benchmarks can be run to compare the server's hardware capabilities against the referenced hardware. +At the moment, we have benchmarked the Spiritnet and Peregrine runtimes on an AMD Ryzen 7 1700X with 64GB RAM and an NVMe SSD. +After executing the benchmarks on a server compare the weights to the official KILT weights. +Your weight results should at least be similar to the official ones and the lower yours are, the better. + +The commands executed to benchmark the KILT runtimes can be found in the official benchmark files for both [Spiritnet](https://github.com/KILTprotocol/kilt-node/tree/master/runtimes/spiritnet/src/weights) and [Peregrine](https://github.com/KILTprotocol/kilt-node/tree/master/runtimes/peregrine/src/weights). + +Below is an example of benchmarking for the the `balances` pallet. + +```bash= +./target/release/kilt-parachain \ + benchmark \ + --chain=spiritnet-dev \ + --execution=wasm \ + --wasm-execution=Compiled \ + --heap-pages=4096 \ + --extrinsic=* \ + --pallet=pallet-balances \ + --steps=50 \ + --repeat=20 \ + --output \ + ./runtimes/spiritnet/src/weights/pallet_balances.rs \ + --template \ + ./.maintain/weight-template.hbs +``` \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/_category_.json b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/_category_.json new file mode 100644 index 000000000..c6cc858f8 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/02_advanced_collator_section/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Advanced Collator Section", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/01_overview.md b/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/01_overview.md new file mode 100644 index 000000000..f5b4fed05 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/01_overview.md @@ -0,0 +1,17 @@ +--- +id: overview +title: Overview +--- + +In the [KILT **L**imited **D**elegated **P**roof **o**f **S**take (LDPoS)](https://medium.com/kilt-protocol/the-continuing-evolution-of-kilt-protocol-limited-delegated-proof-of-stake-640403427c48) consensus, delegators play an important role (at least in the infancy of the network) to filter the pool of candidates for honest, trusted and well-performing collators. + +The requirements to become a delegator are much less than [those for collators](../01_become_a_collator/01_overview.md). +You only need to stake a relatively low number of tokens and decide on a collator candidate. +Once the collator you have backed with your stake authors a block and thus receives a reward, you and all the other delegators of this collator also receive a reward. + +The following sections will guide you through the process of becoming a delegator, adjusting your stake, revoking a delegation and unstaking your tokens. + +:::info +The amount of delegators per collator is limited. +Currently, each delegator can only stake to one collator per account; this may change if the community decides to enable multiple delegations per account. +::: diff --git a/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/02_become.md b/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/02_become.md new file mode 100644 index 000000000..4fbd67484 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/02_become.md @@ -0,0 +1,102 @@ +--- +id: join +title: Become a Delegator +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import StakingTxDisclaimer from '../_disclaimer_staking_tx.md'; + +In contrast to the rather difficult [path to become a collator candidate](../01_become_a_collator/01_overview.md), joining the delegator pool is rather simple. +Anyone can delegate to a collator candidate by staking a minimum of 20 KILT and calling `parachainStaking -> joinDelegators`. + + + +![](/img/chain/parachainStaking-joinDelegators.png) + +1. Select the KILT address you want to delegate from as the extrinsic submitter (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> joinDelegators` +3. Select the `Id` option (the *MultiAddress (LookupSource) field*) +4. Select the collator account (the *Id: AccountId* field) +5. Choose the desired stake amount. +6. Sign and submit the extrinsic (the *Submit Transaction* button) + +:::info +A recent change in the blockchain metadata resulted in a change in the UI regarding how balances are shown. +In the current version of PolkadotJS Apps, specifying 1 KILT requires adding 15 trailing `0`s. +So, for instance, 1 KILT needs to be written as `1,000,000,000,000,000`, while 10,000 KILT would be written as `10,000,000,000,000,000,000`. +::: + + +## Happy Path + +If your chosen collator candidate has at least one empty slot in their delegation pool (out of 35 maximum slots at the time of writing), your delegation will be successful and you immediately start receiving rewards each time the collator you delegated produces a block. + +
+ +```mermaid +flowchart TD + A["Hold at least 20 KILT"] --> |"decide on candidate"| B("Collator Candidate chosen"); + B --> |"call extrinsic joinDelegators"| C{"Can delegate to target? \n Either \n 1. There are empty \n delegations or \n 2. You delegate more \n than another Delegator"}; + C --> |yes| D("Delegating to a Collator Candidate") + D --> |"Collator produces block"| E("Account rewards") + E --> |"claim"| F("Have rewards in wallet") + %% Styles + A:::unstakedFreeKilt + B:::preDelegationCheck + C:::preDelegationCheck + D:::activelyDelegating + E:::activelyDelegating + F:::activelyDelegating + + %% StyleDef + classDef preDelegationCheck fill:#FFF4BD, stroke:none, color:black; + classDef notDelegating fill:#F1C0B9, stroke:black, color:black, stroke-width:1px;; + classDef unstakedFreeKilt fill:#85D2D0, stroke:black, color:black, stroke-width:1px; + classDef activelyDelegating fill:#94C973, stroke:#333, color:black, stroke-width:2px; + classDef preUnlockStaked fill:#F37970, stroke:black, color:black; +``` +
+ +:::info +If your chosen collator fails to produce blocks, neither the collator itself nor their delegators receive rewards. +This can happen if the collator has connectivity issues or are not building blocks fast enough. +::: + +## Unhappy Path + +If the delegation pool of your chosen collator candidate is full, you may still delegate to them if you stake more than the current lowest delegator stake of that pool. +When that happens, + +- The kicked delegator will be replaced by the delegator with a higher delegation (you) immediately +- The kicked delegator's stake is prepared for unstaking as if they revoked the delegation +- A delegator needs to wait 7 days (in block time) to be able to unlock the stake. +Please note that it can take longer in real time as the block times assumes a constant block time of 12s, which is not guaranteed. + +
+ +```mermaid +flowchart TD + A["Hold at least 20 KILT"] --> |"Decide on candidate"| B("Collator candidate chosen"); + B --> |"Call extrinsic joinDelegators"| C{"Can delegate to target? \n Either \n 1. There are empty \n delegations or \n 2. You delegate more \n than another delegator"}; + C --> |no| C2{"Balance locked?\n e.g., previously delegated \n without unlocking?"} + C2 --> |no| A + + %% Styles + A:::unstakedFreeKilt + B:::preDelegationCheck + C:::preDelegationCheck + C2:::notDelegating + + %% StyleDef + classDef preDelegationCheck fill:#FFF4BD, stroke:none, color:black; + classDef notDelegating fill:#F1C0B9, stroke:black, color:black, stroke-width:1px; + classDef unstakedFreeKilt fill:#85D2D0, stroke:black, color:black, stroke-width:1px; +``` +
+ + +:::info +For now, an account can only delegate to one collator at any time! +Moreover, you can only (re-) delegate, e.g., call `parachainStaking -> {joinDelegators, delegateAnotherCandidate}`, once per staking round. +::: diff --git a/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/03_adjust_stake.md b/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/03_adjust_stake.md new file mode 100644 index 000000000..9f67b4a94 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/03_adjust_stake.md @@ -0,0 +1,52 @@ +--- +id: adjust-stake +title: Adjust Your Delegation Stake +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import StakingTxDisclaimer from '../_disclaimer_staking_tx.md'; + +A delegator can increase and decrease their stake by calling either `parachainStaking -> delegatorStakeMore(more)` or `parachainStaking -> delegatorStakeLess(less)`. +Your adjustment becomes effective immediately! +If you increase your stake, you will instantly receive higher rewards for any blocks produced by your collator; if you decreased your delegation amount, the reverse applies and you receive less rewards. + + + + + + +![](/img/chain/parachainStaking-delegatorStakeMore.png) + +1. Select the KILT address you want to delegate from as the extrinsic submitter (the *using the selected account* field) +2. Select the extrinsic: `parachainStaking -> delegatorStakeMore` +3. Select the `Id` option (the *MultiAddress (LookupSource) field*) +4. Select the collator account (the *Id: AccountId* field) +5. Choose the desired amount of stake that you want to add to your current stake. +You can add up to your maximum available balance. +6. Sign and submit the extrinsic (the *Submit Transaction* button) + + + + +![](/img/chain/parachainStaking-delegatorStakeLess.png) + +1. Select the KILT address you want to delegate from as the extrinsic submitter (the *using the selected account* field) +2. Select the extrinsic: `parachainStaking -> delegatorStakeLess` +3. Select the `Id` option (the *MultiAddress (LookupSource) field*) +4. Select the collator account (the *Id: AccountId* field) +5. Choose the desired amount of stake that you want to remove from your current stake. +You can reduce down to the minimum delegation amount (20 KILT), e.g., any value up to the difference of your current stake and the minimum will be accepted. +6. Sign and submit the extrinsic (the *Submit Transaction* button) + + + + +:::caution +You cannot adjust your stake if your Collator candidate is in the leaving state, e.g., they want to stop collating. +However, you can still [**remove**](./04_exit.md) your delegation. +::: + diff --git a/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/04_exit.md b/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/04_exit.md new file mode 100644 index 000000000..f2146c8c0 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/04_exit.md @@ -0,0 +1,21 @@ +--- +id: exit +title: Leave the Set of Delegators +--- + +import StakingTxDisclaimer from '../_disclaimer_staking_tx.md'; + +A Delegator can revoke their delegation by calling `parachainStaking -> leaveDelegators`. +As a result, you won't receive any rewards immediately after the transaction is successfully executed. + +- Your previously delegated amount will be prepared for unstaking. +- You need to wait 7 days (in block time) before you can unlock your unstaked tokens, see the section [Unlock Unstaked](../05_unlock_unstaked.md) for more information. +- Exiting does not count towards the limit of โ€œ1 delegation per roundโ€. + + + +![](/img/chain/parachainStaking-leaveDelegators.png) + +1. Select the KILT address you delegated from as the extrinsic submitter (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> leaveDelegators`. +3. Sign and submit the extrinsic (the *Submit Transaction* button) diff --git a/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/05_delegator_lifecycle.md b/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/05_delegator_lifecycle.md new file mode 100644 index 000000000..05daa00d4 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/05_delegator_lifecycle.md @@ -0,0 +1,55 @@ +--- +id: lifecycle +title: Lifecycle of a Delegator +--- + +The following diagram depicts the full lifecycle of a delegator from owning free KILT to delegating, losing a delegation seat, re-delegating and finally unlocking their stake. + +It provides a summary of the detailed information provided in the preceding sections. + +
+ +```mermaid +flowchart TD + A["Hold at least 20 KILT"] --> |Choose candidate| B("Collator candidate chosen"); + B --> |"Call \n joinDelegators"| C{"Can delegate to target? \n Either \n 1. There are empty \n delegations or \n 2. You delegate more \n than another Delegator"}; + C --> |yes| D("Delegating to a collator candidate") + C --> |no| C2{"Balance locked?\n e.g., previously delegated \n without unlocking?"} + C2 --> |no| A + C2 --> |yes| G + D --> D2("Accumulating rewards \non each block built by \n delegated collator") + D --> |"leave \n Delegators"| E("Not delegating") + D --> |"your Collator \n candidate leaves"| E + E --> E2("Not accumulating \n rewards") + E --> F{"Delegate to \n another candidate?"} + F --> |Yes| B + F --> |No| G("Locked tokens") + G --> |Want to unlock| H{"Waited 7 days?"} + H --> |yes| I("Balance with expired lock") + H --> |no| F + I --> |"Call \n unlockUnstaked"| A + + %% Styles + A:::unstakedFreeKilt + B:::preDelegationCheck + C:::preDelegationCheck + C2:::notDelegating + D:::activelyDelegating + D2:::activelyDelegating + E:::notDelegating + E2:::preUnlockStaked + F:::notDelegating + G:::preUnlockStaked + H:::preUnlockStaked + I:::preUnlockStaked + + %% StyleDef + classDef preDelegationCheck fill:#FFF4BD, color:black, stroke:none; + classDef notDelegating fill:#F1C0B9, color:black, stroke:black, stroke-width:1px;; + classDef unstakedFreeKilt fill:#85D2D0, color:black, stroke:black, stroke-width:1px; + classDef activelyDelegating fill:#94C973, color:black, stroke:#333, stroke-width:2px; + classDef preUnlockStaked fill:#F37970, color:black, stroke:black; +``` + +
+ diff --git a/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/_category_.json b/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/_category_.json new file mode 100644 index 000000000..78f66302c --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/03_delegate/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Delegate", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/participate/01_staking/04_claim_rewards.md b/versioned_docs/version-1.0.0/participate/01_staking/04_claim_rewards.md new file mode 100644 index 000000000..debc20b1b --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/04_claim_rewards.md @@ -0,0 +1,93 @@ +--- +id: claim-rewards +title: Claim Staking Rewards +--- + +import CodeBlock from '@theme/CodeBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import StakingTxDisclaimer from './_disclaimer_staking_tx.md'; +import GetUnclaimedStakingRewards from '!!raw-loader!@site/code_examples/sdk_examples/src/staking/rewards/01_query_staking_rewards.ts'; +import ClaimRewardsCollator from './_04_claim_rewards_collator.mdx'; +import ClaimRewardsDelegator from './_04_claim_rewards_delegator.mdx'; + +Until runtime version 1.7.5 (`spiritnet-10750`), staking rewards were automatically minted. +In 1.8.0 (`spiritnet-10801`) this will change: +Hereafter, the rewards are still accounted to the collators and their delegators in each block. +However, they need to be actively claimed by calling an extrinsic, similar to the pull-based approach on Polkadot. +Since the rewards never expire, one does not need to rush to do so. + +This change improves the scalability of our LDPoS by orders of magnitude because it removes the `Rewarded` events for a collator and all their delegators in each block. +This reduces the number of taxable events from many thousands per year to any number a user might find suitable. +Please check our blogpost for more details. + +## How to check the reward amount + +Unfortunately, the amount of accumulated rewards are not directly stored on the chain but divided into multiple storage entries. +Luckily, you can easily query your current reward status by performing a runtime API call which we created for that specific purpose. +Since this is just a simple query, it does not cost any transaction fees. + + + + +In the Polkadot JS Apps ([wss://spiritnet.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkilt-rpc.dwellir.com#/explorer), or [wss://peregrine.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine-stg.kilt.io#/explorer)) go to `Developer -> Runtime calls`. + +1. Select the `parachainStaking` endpoint. +2. Select the `getUnclaimedStakingRewards(account)` call. +3. Select your KILT address (the *account: AccountId32* field) +4. Submit the runtime call (the *Submit Runtime call* button). You do not need to sign or pay any fees. + +![](/img/chain/parachainStaking-getUnclaimedStakingRewards.png) + + + + + + {GetUnclaimedStakingRewards} + + + + +## How to claim + +In order to move the staking rewards into your wallet, you need to call two different extrinsics: `increment{Collator, Delegator}Rewards` and `claimRewards`. +This can be done sequentially or in a batch. +To save transaction fees, we recommend the latter [batched call](#recommendation-batched-call). + +
+ +```mermaid + +graph TD +Alice("Alice holds free KILT") ---> |"call joinCandidates"| C("Active Collator") +Alice ---> |"call joinDelegators"| D("Active Delegator") +C ---> |"build block"| R +D ---> |"delegated collator \n builds block"| R("Reward counter is \n internally increased") +R ---> |"call increment...Rewards"| R2("Rewards are \n converted into Balance") +R2 ---> |"call claimRewards"| R3("Rewards are moved \n into Alice's wallet") + +``` + +
+ + + + + + + + + + + + + + + + diff --git a/versioned_docs/version-1.0.0/participate/01_staking/05_unlock_unstaked.md b/versioned_docs/version-1.0.0/participate/01_staking/05_unlock_unstaked.md new file mode 100644 index 000000000..5c13ae86a --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/05_unlock_unstaked.md @@ -0,0 +1,48 @@ +--- +id: unlock-unstaked +title: Unlock Unstaked Tokens +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import StakingTxDisclaimer from './_disclaimer_staking_tx.md'; + +Before you can unlock your previously staked tokens, you have to wait 7 days (in block time). + + + +![](/img/chain/parachainStaking-unlockUnstaked.png) + + + + +1. Select any account with enough balance to cover the transaction fee, which is around 0.005 KILT (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> unlockUnstaked(target)` +3. Select the `Id` option (the *MultiAddress (LookupSource) field*) +4. Select your collator's KILT address (the *Id: AccountId* field) +5. Sign and submit the extrinsic (the *Submit Transaction* button) + +:::info +You have unstaked tokens if you have either reduced your stake without increasing it for (at least) same amount afterwards or executing your exit request. +::: + + + + +1. Select any account with enough balance to cover the transaction fee, which is around 0.005 KILT (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> unlockUnstaked(target)` +3. Select the `Id` option (the *MultiAddress (LookupSource) field*) +4. Select the KILT address you delegated from (the *Id: AccountId* field) +5. Sign and submit the extrinsic (the *Submit Transaction* button) + +:::info +Even if you have not exited, reduced or removed your delegation, you can still have unstaked tokens. +This can happen if either of the following events occurred +* You were kicked out of your collator candidate's delegation pool because all current delegators have a higher stake +* Your collator candidate intentionally left the collator pool. +::: + + \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/participate/01_staking/06_troubleshooting.md b/versioned_docs/version-1.0.0/participate/01_staking/06_troubleshooting.md new file mode 100644 index 000000000..02bcd8da6 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/06_troubleshooting.md @@ -0,0 +1,65 @@ +--- +id: troubleshooting +title: Troubleshooting +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + +There are a few things that can be checked to make sure everything is set up correctly. + +If the collator's account is shown next to some of the blocks on any network explorer, e.g., the one offered by PolkadotJS Apps, then the collator is correctly producing blocks and getting rewarded for it. +If the logs print the message that starts with a :gift: emoji, it indicates that the collator setup is correct but that the blocks produced are not included by the Relay Chain. +This typically signals some issues about the node hardware or connectivity. +If not, it might be that the node does not produce and send blocks fast enough. +This can be caused by slow hardware or a slow internet connection. +Also, note that a high bandwidth connection can still be slow if it has a high ping! +Bandwidth and latency do not necessarily come hand in hand. +In this case, it is better to rule out other options before thinking about upgrading the collator's hardware. + +1. Check that the session keys are associated with the validatorId (aka AccountId). +There should be a 32 Byte long public key stored in `session > nextKeys(your AccountId)`. +2. Check that the node has the corresponding private key for the public session key. +Connect to the node and query `author > hasKey(, aura)` to see if it returns `true`. +3. Check that the node is fully synced with the Relay Chain & parachain (best and finalized block number is equal to the one shown in the PolkadotJS Apps ([wss://spiritnet.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkilt-rpc.dwellir.com#/explorer), [wss://peregrine.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine-stg.kilt.io#/explorer)) and on Subscan (only for [Spiritnet](https://spiritnet.subscan.io/)). +4. Check that the collator is among the selected candidates. +Its address should included in the list returned by querying `parachainStaking > topCandidates()`. +5. Check that the `parachainStaking` pallet has registered the collator's address among the authorized authors in the `session`. +Its address should be listed when querying `session > validators()`. + +## Collator Rewards Have Stopped + +If you have stopped receiving rewards, either of the following is true: +1. You were kicked out of the top collator candidate list because your total stake is too low. + See the [section about joining](./01_become_a_collator/05_join_collators.md#check-your-position-in-the-collators-queue) for the necessary steps to retrieve the least staked candidate address in that list. + You can query their stake by going to `Developer -> Chain State` calling `parachainStaking -> candidatePool(address) -> +`. +2. You have connectivity issues, see above for resolution tips. + + + + +## Delegator Rewards Have Stopped + +If you have stopped receiving rewards, either +1. You were kicked out of your collator candidate's delegation pool because all current delegators have a higher stake or +2. Your collator candidate stopped producing blocks, because: + 1. They left the collator candidate pool intentionally so they don't have an associated collator state on-chain henceforth; or + 2. They are not among the top staked candidates (of which there are 30 at the time of writing 2022-05-05); or + 3. They are offline. + +In case of 1. or 2i., your stake will automatically be unstaked and prepared for [unlocking](./05_unlock_unstaked.md). +Otherwise, in case of 2ii. and 2iii., you need to [manually initiate the unlocking period](./03_delegate/04_exit.md) if you don't want to or cannot delegate to another Collator candidate. + + + +### Why Can't I Transfer Unstaked Tokens? + +Staking puts a lock on your tokens which blocks them from being transferred. +You can still use them for participating in Governance. +If your funds are unstaked, you still need to wait 7 days (in block time) to [unlock tokens after unstaking them](./05_unlock_unstaked.md). diff --git a/versioned_docs/version-1.0.0/participate/01_staking/_04_claim_rewards_collator.mdx b/versioned_docs/version-1.0.0/participate/01_staking/_04_claim_rewards_collator.mdx new file mode 100644 index 000000000..e53bbbb1c --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/_04_claim_rewards_collator.mdx @@ -0,0 +1,57 @@ +import CodeBlock from '@theme/CodeBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import ClaimCollatorStakingRewards from '!!raw-loader!@site/code_examples/sdk_examples/src/staking/rewards/02_claim_collator_staking_rewards.ts'; + +
+ + + +### Prepare claiming + +First, you need to convert your _reward points_ into balance. + +1. Select the collator account for which you want to claim the rewards. +It should have enough balance to cover the transaction fee which is around 0.0001 KILT (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> incrementCollatorRewards()` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/parachainStaking-incrementCollatorRewards.png) + +### Claim + +Finally, you can claim your well deserved staking rewards. + +1. Select the collator account for which you want to claim the rewards. +It should have enough balance to cover the transaction fee which is around 0.0001 KILT (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> claimRewards()` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/parachainStaking-claimRewards.png) + +### Recommendation: Batched call + +We recommend to execute both extrinsics in a single batch to save on transaction fees: + +1. Select the collator account for which you want to claim the rewards. +It should have enough balance to cover the transaction fee which is around 0.000112 KILT (the *using the selected account* field) +2. Select the batch extrinsic: `utility -> batch()` +3. Select the reward increment extrinsic: `parachainStaking -> incrementCollatorRewards()` +4. Press the `+` button and add the reward claiming extrinsic: `parachainStaking -> claimRewards()` +5. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/parachainStaking-batch-incrementCollatorRewards-claimRewards.png) + + + + + + {ClaimCollatorStakingRewards} + + + + +
diff --git a/versioned_docs/version-1.0.0/participate/01_staking/_04_claim_rewards_delegator.mdx b/versioned_docs/version-1.0.0/participate/01_staking/_04_claim_rewards_delegator.mdx new file mode 100644 index 000000000..6eea0b592 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/_04_claim_rewards_delegator.mdx @@ -0,0 +1,55 @@ +import CodeBlock from '@theme/CodeBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import ClaimDelegatorStakingRewards from '!!raw-loader!@site/code_examples/sdk_examples/src/staking/rewards/03_claim_delegator_staking_rewards.ts'; + +
+ + + +### Prepare claiming + +First, you need to convert your _reward points_ into balance. + +1. Select the delegator account for which you want to claim the rewards. It should have enough balance to cover the transaction fee which is around 0.0001 KILT (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> incrementDelegatorRewards()` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/parachainStaking-incrementDelegatorRewards.png) + +### Claim + +Finally, you can claim your well deserved staking rewards. + +1. Select the delegator account for which you want to claim the rewards. It should have enough balance to cover the transaction fee which is around 0.0001 KILT (the *using the selected account* field) +2. Select the appropriate extrinsic: `parachainStaking -> claimRewards()` +3. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/parachainStaking-claimRewards.png) + +### Recommendation: Batched call + +We recommend to execute both extrinsics in a single batch to save on transaction fees: + +1. Select the delegator account for which you want to claim the rewards. +It should have enough balance to cover the transaction fee which is around 0.000112 KILT (the *using the selected account* field) +2. Select the batch extrinsic: `utility -> batch()` +3. Select the reward increment extrinsic: `parachainStaking -> incrementDelegatorRewards()` +4. Press the `+` button and add the reward claiming extrinsic: `parachainStaking -> claimRewards()` +5. Sign and submit the extrinsic (the *Submit Transaction* button) + +![](/img/chain/parachainStaking-batch-incrementDelegatorRewards-claimRewards.png) + + + + + + {ClaimDelegatorStakingRewards} + + + + +
diff --git a/versioned_docs/version-1.0.0/participate/01_staking/_category_.json b/versioned_docs/version-1.0.0/participate/01_staking/_category_.json new file mode 100644 index 000000000..0e13eb399 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Staking", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/participate/01_staking/_disclaimer_staking_tx.md b/versioned_docs/version-1.0.0/participate/01_staking/_disclaimer_staking_tx.md new file mode 100644 index 000000000..c8cc3a9ef --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/01_staking/_disclaimer_staking_tx.md @@ -0,0 +1,6 @@ +:::info +You can either execute this transaction in Polkadot JS Apps or the [**KILT Stakeboard**](../../develop/05_builtonkilt.md#web-apps), which serves as an in-house developed Frontend for all KILT staking activity. +Below, we outline the steps for Polkadot JS Apps. +::: + +In the Polkadot JS Apps ([wss://spiritnet.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fkilt-rpc.dwellir.com#/explorer), or [wss://peregrine.kilt.io](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fperegrine-stg.kilt.io#/explorer)) go to `Developer -> Extrinsics -> Submission`. diff --git a/versioned_docs/version-1.0.0/participate/02_governance/01_vote.md b/versioned_docs/version-1.0.0/participate/02_governance/01_vote.md new file mode 100644 index 000000000..87e302201 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/02_governance/01_vote.md @@ -0,0 +1,83 @@ +--- +id: vote +title: Cast a Vote +--- + +1. Go to KILT Spiritnet on [Polkadot.JS](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fspiritnet.api.onfinality.io%2Fpublic-ws#/democracy) + +2. Under the โ€œGovernanceโ€ โ†’ โ€œDemocracyโ€ section you will see active referenda and proposals + +3. Scroll to the referendum you wish to vote on + +4. Click โ€œVoteโ€ + +5. This opens a separate pop-up. + Enter the amount of coins you want to lock (1). + The minimum required to vote is 1 KILT.
+ You can vote with multiplier 0.1 (10% of your voting tokens) and your coins will only get locked for the duration of the vote. + ![](/img/chain/cast-vote.png) + +6. If you wish to increase your voting power by selecting a period of time to lock your coins, click the arrow next to conviction (2). + Choose your conviction in the drop-down menu.
+ :::note + if the referendum is successful, your coins will remain locked for this period; if unsuccessful, your tokens will be unlocked when the referendum has finished. + Also because voting happens transparently on-chain, it requires a small transaction fee (around 0.017 KILT). + Locked tokens or tokens used for staking can be simultaneously used for voting, but a usable, unlocked balance to cover this fee is required. + ::: + +7. Vote โ€œAyeโ€ if you agree with the proposal and โ€œNayโ€ if you disagree. + +8. Click โ€œSign and Submitโ€ in the pop-up. + ![](/img/chain/vote-sign-sporran.png) + +9. Sign the transaction by entering your password (Sporran or Polkadot.JS, depending on where you are connected.) +10. Thatโ€™s it! + +## Backgrounder: Conviction Voting + +Like Polkadot and Kusama, KILT Protocol has conviction voting. +This means if you feel very strongly about a proposal, you can lock up tokens for longer periods to increase your voting power up to a maximum factor of 6. +The longer you lock your tokens, the stronger your vote will be weighted. + +The times range from no lockup to a period of around 224 days, with the lockup time beginning after the voting period ends. +Tokens used for voting will always be locked until the end of the voting period, no matter what conviction you vote with. +Of note: the lock time is based on the standard blocktime of 12 seconds per block and hence may vary due to differences in the real blocktime. + +![](/img/chain/vote-conviction.png) + +If you choose not to lock any tokens, your vote only counts as 10% of the tokens that you commit to the voting (vote value), while the maximum lock up of around 224 days means you can make your vote count for 600% of the vote value. +You can choose to lock all or some of your coins for any range between 0.1x and 6x, with a lockup time as outlined above. + +For example: You have a wallet with 1,001 KILT Coins. +This could include staked or vested coins. + +### Example 1 - Minimum + +* You want to vote but donโ€™t want to lock any coins. +* You enter 1,000 into the โ€œvote valueโ€ +* You choose โ€œ0.1 x voting balance, no lockup periodโ€ +* This gives you a voting power of 100 KILT Coins. +* Note that all your 1,000 coins are locked for the time of the voting period (7 days). + +### Example 2 - Maximum + +* You strongly believe in the referendum and want to vote with your full balance and maximum conviction. +* Choose โ€œ6 x voting balance, locked for 32x enactment (224 days)โ€ +* This will give you a voting power of 6,000 KILT Coins, if you use your full amount, or 6 times the voting power of the amount you chose. + The chosen amount will be locked for a period of around 224 days after the voting period ends (7 days). + +:::note + +Rounded numbers are used as an example only โ€“ make sure that you always leave enough free, usable balance to cover the transaction fees. + +::: + +Conviction voting allows users with a small amount of tokens to increase their voting power, and deters a token holder from creating and voting on a malicious proposal and then leaving the network. + +If the referendum is successful, your voting coins will remain locked for the time specified (which means that you will be unable to transfer them, but they will still be usable for staking during that time); if unsuccessful, your tokens will be unlocked after the referendum has finished. + +KILT also uses an algorithm to adapt the amount of โ€œayeโ€ (yes/agree) votes needed to pass depending on voter turnout: the greater the number of voters, the lower the threshold required to pass. +Therefore, when voter turnout is low a supermajority is generally required; with a high turnout a simple majority is sufficient. + +Before voting on any referendum, you can read more about it and join the discussion in [Polkassembly](https://kilt.polkassembly.network/referenda) (under โ€œDemocracyโ€ โ†’ โ€œReferendaโ€). +Polkassembly is an open source platform for providing information, context and a discussion forum for proposals and referenda in the Polkadot ecosystem. diff --git a/versioned_docs/version-1.0.0/participate/02_governance/02_remove_vote.md b/versioned_docs/version-1.0.0/participate/02_governance/02_remove_vote.md new file mode 100644 index 000000000..44b947cdd --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/02_governance/02_remove_vote.md @@ -0,0 +1,28 @@ +--- +id: remove_vote +title: Remove a Vote +--- + +If you happen to change your mind and want to remove a vote from an open referendum, you have to find the index of the referendum you voted on, remove your vote from that index and unlock your coins that are no longer locked up by this vote. + +## Find the Referendum Index + +1. Go to the [Democracy tab in Polkadot.JS Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fspiritnet.api.onfinality.io%2Fpublic-ws#/democracy) +2. Note the number next to the referendum you voted for + +![](/img/chain/find-referendum-index.png) + +## Remove the Vote +Go to the [Extrinsic tab in Polkadot.JS Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fspiritnet.api.onfinality.io%2Fpublic-ws#/extrinsics) + +1. Select the account you used for voting +1. Select the `democracy` pallet +2. Select the `removeVote` extrinsic +3. Enter the index of the referendum +4. Sign and send the extrinsic + +![](/img/chain/remove-vote.png) + +## Unlock Expired Voting Locks + +Please refer to the "[Unlock coins after lockup expires](./03_unlock_coins.md)" guide. diff --git a/versioned_docs/version-1.0.0/participate/02_governance/03_unlock_coins.md b/versioned_docs/version-1.0.0/participate/02_governance/03_unlock_coins.md new file mode 100644 index 000000000..e5e28ba80 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/02_governance/03_unlock_coins.md @@ -0,0 +1,16 @@ +--- +id: unlock_coins +title: Remove Expired Voting Locks +--- + +After the lockup time has been reached, a transaction is needed to clear the lock. +Of note: this will also require a transaction fee. + +1. Go to KILT Spiritnet on Polkadot.JS +2. Click the three dots on the right of your account. This opens up a pop-up. +3. Click โ€œClear expired democracy locksโ€ + +![](/img/chain/unlock-vote.jpg) + +Confirm the transaction. +This will clear the lock. diff --git a/versioned_docs/version-1.0.0/participate/02_governance/_category_.json b/versioned_docs/version-1.0.0/participate/02_governance/_category_.json new file mode 100644 index 000000000..8be4a0ebf --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/02_governance/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Governance", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_docs/version-1.0.0/participate/03_treasury_proposal.md b/versioned_docs/version-1.0.0/participate/03_treasury_proposal.md new file mode 100644 index 000000000..3935a6e74 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/03_treasury_proposal.md @@ -0,0 +1,157 @@ +--- +id: treasury-proposal +title: Open a Treasury Proposal +--- + +Complete these steps to create a well-formed Treasury proposal. + +## Discuss + +The first step in applying for a Treasury grant is either to join the community in the [Discord Treasury Channel](https://discord.gg/nUpqDfQ6kJ) to brainstorm the scope of your proposal intention or immediately open a discussion on [Polkassembly](https://kilt.polkassembly.network/discussions). +This will help you get valuable community feedback throughout the process. +It also gives Council members an open and transparent way to measure community sentiment. + +## DID Sign + +The proposed document must be DID signed. +This requires a DID that must be associated with the proposal. +Therefore, it requires the proposer to have a DID. +The signature provides integrity and accountability about the submitter, which can give more confidence to the community and council. + +The DID Signature should be done via the [DIDSign](https://didsign.io/) dApp. +The DIDSign doesn't have a database, nor store any data by the user. +The following guide explains [how to create a signature using a DID with DIDSign](https://kilt-protocol.org/files/How-to-Guide-DIDsign.pdf). + +Once the document has been signed, the signature must be made publicly available for verification. +Depending on the services and software used, accessing the storage may require different instructions, e.g., on IPFS or as a GitHub gist or cloud provider. +The document should be made publicly available as well as the signature. + +## Example on IPFS + +An example of how to do this via IPFS using Google Drive. +Have a document ready for the proposal or discussion phase. + +1. Make the document publicly available to view and download. + +2. Sign the PDF version of the Document in the [DIDSign](https://didsign.io/). + +3. Download the zip file and upload it to IPFS. + +4. Following the instructions of the IPFS, pin the signature to IPFS and make it publicly available. One solution for doing is [web3 storage](https://web3.storage/). + +5. After the documents and signature have been uploaded to IPFS, add their URL to the proposal or discussion page for verification. + +Please include how to verify and download the necessary documents. +The following is an example done by BOTLabs GmbH. + +```md + +The current version of the proposal document has been digitally signed with one of the DIDs that BOTLabs GmbH controls. To verify the signature: + +1. Download the PDF version of the Google Document linked above. + +2. Download the DID signature of the file from IPFS, with CID QmRcYyPcCKGDQno2m5qBSZq7dftoZKuwraF9C9M96rXR36 (e.g., ipfs.io). + +3. Visit didsign.io, and upload both the PDF file and the downloaded signature. The signature should verify correctly and link to the KILT tx in which the timestamp was generated. +``` + +The example may change depending on the method of storing and creation of the document. + +If during the discussion the document is edited it will require a new upload and should be updated accordingly. + +## Deposit + +A deposit of 5% of the amount requested is required in order to submit a proposal. +If the proposal is denied, you will lose this amount and it will go to the Treasury to fund other projects. +This is why it is essential to engage with the community and show how the proposed work adds value to the network. + +## Create Proposal + +To maximize your chances of success, create a full proposal document with as much information as possible to communicate the value of your work and what it will add to the networkโ€™s growth and success. +Check out our Treasury proposal template or Polkassemblyโ€™s [proposal document #6](https://docs.google.com/document/d/1K0ScDodCxzgoqHSp-62rW0JLvBpMRgH97R37OoqYH-0) as examples to help guide your process. + +Multiple types of proposals can be created covering building and infrastructure, outreach and hackathons, or [educational content](04_content_creation_guidelines.md) such as videos, blogs and translations. + +Once your proposal document is complete, upload it so that itโ€™s accessible to the Council for review. +Donโ€™t forget to link it when completing the Polkassembly information! + +## Submit Proposal + +When you have feedback from the community and are satisfied with your proposal, head to [Polkadot.JS apps](https://polkadot.js.org/apps/?rpc=wss://spiritnet.api.onfinality.io/public-ws#/treasury) + +Scroll to the โ€œ+ Submit Proposalโ€ button and click. +Complete the form: + +* Submit with Account: this is the account that will make the 5% deposit +* Beneficiary: this is the account that will receive Treasury funding if successful +* Value: this is the full amount of KILT being requested +* Click submit to complete the proposal + +## Polkassembly Details + +Click the [Polkassembly](https://kilt.polkassembly.network/discussions) link to the right of the proposal on Polkadot.JS and connect with the account that you used to submit the proposal in order to be able to edit the proposal details. + +Enter the following information: + +* Title: a title for your project +* Purpose: whatโ€™s your motivation behind the effort +* Description: a short summary about you, the project and the need for what you are proposing +* Full Proposal: link to the full proposal +* Proposal Amount: the amount requested in USD +* KILT Rate: the current rate of exchange in USD +* Amount Requested: the total amount of KILT requested +* Beneficiary: the beneficiary address +* Period: intended date of delivery if applicable +* Contact: email or social handle (please specify social network) +* Engage +* Share your proposal in our channels to generate support from community and showcase your project (Discord, Telegram, Element, Twitter) + +Click [here](https://www.kilt.io/treasury/overview/) to get an overview of the Treasury. +Or click [here](https://www.kilt.io/treasury/content-creation/) to see the guidelines for content creation. + +## Illustration + +The following diagram depicts the flow of a Treasury proposal from having an idea to receiving the funds in the beneficiary address. +While all nodes with yellow background represent off-chain processes, the remaining ones involve on-chain activity. + +
+ +```mermaid +flowchart TD + %% nodes + Proposer --> |"Share contribution idea"|Discuss("Polkassembly: \n kilt.polkassembly.network") + Discuss --> |"Gather feedback"|Community + Discuss --> |"Come to agreement about \n scope and financial objective"|Council + Community --> |"Supports proposal"|Propose("Propose to chain") + Council --> |"Approves pre-proposal"|Propose + Propose --> |"reserve 5% of \n demanded amount \n"|Deposit + Propose --> |"On Polkassembly, \n provide details in"|Document("Proposal document") + Propose ----> |"Select address"|Beneficiary + Document --> |"Start work"|Deliverables + Deliverables --> |"Complete work"|Council_Review{"Council review"} + Council_Review ----> Council_Approval("Council approval") + Council_Review -...-> Council_Rejection("Council rejection") + Council_Approval ----> |"Receive requested \n funds from Treasury"|Beneficiary + Council_Approval ----> |Unreserve deposit|Deposit + Council_Rejection -.-> |"Slash deposit \n to Treasury"|Deposit + + %% class mapping + Proposer:::ofchain + Discuss:::ofchain + Community:::ofchain + Council:::ofchain + Propose:::onchain + Document:::ofchain + Deliverables:::ofchain + Council_Review:::ofchain + Council_Approval:::onchain + Deposit:::onchain + Council_Rejection:::onchain + Beneficiary:::onchain + + %% styling classes + classDef ofchain fill:#FFF4BD, stroke:black, stroke-width:1px, color:black; + classDef onchain fill:#85D2D0, stroke:black, stroke-width:1px, color:black; +``` + +
diff --git a/versioned_docs/version-1.0.0/participate/04_content_creation_guidelines.md b/versioned_docs/version-1.0.0/participate/04_content_creation_guidelines.md new file mode 100644 index 000000000..4824e8651 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/04_content_creation_guidelines.md @@ -0,0 +1,47 @@ +--- +id: content-creation-guidelines +title: Content Creation Guidelines +--- + +Content created should be unique in substance, reach, or delivery. +Copying or quickly iterating existing works are less likely to result in a successful proposal. +If providing translations, they must be done accurately by a native or expert speaker (i.e. no translation tools). +Content must be accessible and open source. +Any images used must be Creative Commons licensed. +Content should contain no harmful language or explicit content, or false or misleading information. + +Start your proposal with the following steps: + +## Title + +Give your project a title. + +## About You + +**General**: Tell the community about yourself and your team if applicable, outlining your interest and motivation in submitting the proposal. Mention any experience you have in the subject matter. + +**Profile**: Share links to your platforms and social networks. + +**Contact**: Add your contact email or social handles so the Council can reach out with questions and/or verify your authorship. + +## Purpose + +Explain your vision and motivation. +Whatโ€™s driving you to create content and whatโ€™s the intended outcome? + +## Description + +**Overview**: Describe the project in detail. Whatโ€™s the focus of the content series? (Technical / High-level, Technical / Education). + +**Platforms**: What platform will the content be published on? Where will it live? Whatโ€™s the format? Whatโ€™s your demographic / audience reach? + +**Work**: If the content has already been created, provide links to all works under consideration. If itโ€™s for future-facing content, provide links and evidence of related work. + +**Schedule**: Give an overview of the intended release schedule for the content. + +## Financial + +How much do you need? +Break down the costs. +Price it in terms of USD, and relate it to the current price of the KILT Coin at the time of the proposal. +Note the beneficiary address here. \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/participate/05_propose_tip.md b/versioned_docs/version-1.0.0/participate/05_propose_tip.md new file mode 100644 index 000000000..84196c2c7 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/05_propose_tip.md @@ -0,0 +1,87 @@ +--- +id: treasury-tip +title: Treasury Tips +--- + +Similar to [opening a Treasury proposal](./03_treasury_proposal.md), anyone can start a tipping process. + +You can expect success if the tip is based on a meaningful contribution. +The variety of potential contributions is vast, read the [KILT Contribution guide](../develop/06_contribute.md) for a high level description of tips and the differences to Treasury proposals. + +This document covers the necessary steps from requesting a tip to receiving it. + +## Lifecycle of a tipping process + +Anyone can propose a tip, including for someone else, the **Beneficiary**. +In this case, you, the **Finder**, need to put down a **minor deposit**, which depends on the length in characters of the reason for the tip. +Overall, you should expect to provide **between 0.05 to 0.2 KILT** as a deposit. +For example, if you provide a URL that includes 60 characters, the deposit would be around 0.07 KILT. + +After making a tip proposal, the set of tippers, elected by the KILT Council, come to consensus on how much to pay. +Every member of this stakeholder group, the **Tippers**, can submit an appropriate amount. +Eventually, the median of all tips is taken as the final amount. + +Once at least half of the Tippers have declared their tip, the ending phase starts. +After 24 hours have passed, the tip is automatically closed and paid from the Treasury. +However, other Tippers can still submit their suitable amount and thus influence the final amount of the tip. +After payout, the original deposit is returned to the Finder. +The Tippers will not approve the proposal and pay it out until at least half the tippers have voted with `Aye`. At any point before the tip is approved, the Finder can cancel the tip proposal and get back their deposit. + +:::note No Finder's fees +While tipping allows a configurable percentage of the final tip to go to the original Finder, the current KILT configuration has set this fee to 0, meaning that the Finder's will not get rewarded for successful tips. +::: + +```mermaid +flowchart TD + %% Alice + Alice(("Alice \n (Finder or Tipper)")):::Finder --> Alice_Finder{Is Finder?}:::Finder + Alice_Finder -.-> |Yes| Alice_Finder_Deposit(reserve deposit):::Finder + Alice ----> |"Provide tipping reason (URL/Polkassembly) and set target"|Beneficiary(("Bob \n (Beneficiary)")):::Beneficiary + + %% Tipping Start + Beneficiary --> Tip_1_Start("Wait for tips"):::process + Tip_1_Start --> Tip_2_Threshold{"More than 50% \n of Tippers tipped?"}:::process + Tip_2_Threshold:::process --> |No| Tip_1_Start + + %% Tipping End + Tip_2_Threshold --> |Yes| Tip_3_End{{Start of Ending phase}} + Tip_3_End:::processEnd --> Tip_4_Wait(Wait for blocks to pass) + Tip_4_Wait:::processEnd --> Tip_5_Blocks{"TipCountdown: \n Sufficient number \n of blocks passed?"} + Tip_5_Blocks:::processEnd --> |No| Tip_4_Wait + + %% Tipping close + Tip_5_Blocks --> |Yes| Tip_6_Close(Trigger closing of tipping process):::Payment + Tip_6_Close -.-> |"Unreserve Deposit \n (only if Finder)"| Alice_Finder_Deposit + Tip_6_Close --> Payout_1("Final tip amount = median of received tips"):::Payment + + %% Treasury + Payout_1 --> Payout_2{Is there a Finder's fee?}:::Payment + Payout_2 --> |Yes| Payout_3(Reduce final tip amount by Finder's fee):::Payment + Payout_2 --> |No| Payout_4[("๐Ÿ’ฐ Treasury")]:::Payment + Payout_3 --> Payout_4{{"Ready to pay out"}} + Payout_4 --> Treasury[("๐Ÿ’ฐ Wait for Spending Period \n of Treasury to end")]:::Payment + Treasury ==> |"Receive tip"| Beneficiary + Treasury -.-> |"Pay out Finder's fee"| Alice + + %% classes + classDef Finder fill:#fff4bd,stroke:none; + classDef process fill:#c7fff9,stroke:black; + classDef processEnd fill:#6be6d8,stroke:black; + classDef Beneficiary fill:#7cd27c,stroke:#333,stroke-width:0px; + classDef Payment fill:#ff9393,stroke:black; +``` + +## Proposing a tip + +Proposing a tip much is simpler than opening a Treasury proposal. + +![A screenshot showing the Treasury options from the Governance menu](@site/static/img/chain/tipping-navigation.png) + +From [polkadot.js.org/apps](https://polkadot.js.org/apps), open _Governance > Treasury > Tips_ and click the _+ Propose tip_ button. + +![A screenshot showing selecting the tip request dialog](@site/static/img/chain/tipping-extrinsic.png) + +1. Select your account as the extrinsic submitter in the _submit with account_ field +2. Provide the address to receive the tip in the _beneficiary_ field +3. Provide a reason in the _tip reason_ field. This can either be some **descriptive words or a URL**. The _tip reason_ field should point to the contribution(s), e.g., the GitHub pull request, blog posts, translations or videos among other things. The tipping process will fail if the reason is not recognizable. +4. Sign and submit the extrinsic with the _Propose tip_ button \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/participate/_category_.json b/versioned_docs/version-1.0.0/participate/_category_.json new file mode 100644 index 000000000..7ce6ec21a --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Participate", + "collapsible": true, + "collapsed": true +} diff --git a/versioned_sidebars/version-0.35.0-sidebars.json b/versioned_sidebars/version-0.35.0-sidebars.json new file mode 100644 index 000000000..7d1cf79e5 --- /dev/null +++ b/versioned_sidebars/version-0.35.0-sidebars.json @@ -0,0 +1,55 @@ +{ + "concepts": [ + { + "type": "autogenerated", + "dirName": "concepts" + } + ], + "staking": [ + { + "type": "autogenerated", + "dirName": "participate/01_staking" + } + ], + "governance": [ + { + "type": "autogenerated", + "dirName": "participate/02_governance" + } + ], + "chain": [ + { + "type": "autogenerated", + "dirName": "develop/02_chain" + } + ], + "workshop": [ + { + "type": "autogenerated", + "dirName": "develop/03_workshop" + } + ], + "dApp": [ + { + "type": "autogenerated", + "dirName": "develop/07_dApp" + } + ], + "opendid": [ + { + "type": "autogenerated", + "dirName": "develop/08_opendid" + } + ], + "sdk": [ + { + "type": "autogenerated", + "dirName": "develop/01_sdk" + }, + { + "type": "link", + "label": "API Documentation", + "href": "https://kiltprotocol.github.io/sdk-js/index.html" + } + ] +} diff --git a/versioned_sidebars/version-1.0.0-sidebars.json b/versioned_sidebars/version-1.0.0-sidebars.json new file mode 100644 index 000000000..7d1cf79e5 --- /dev/null +++ b/versioned_sidebars/version-1.0.0-sidebars.json @@ -0,0 +1,55 @@ +{ + "concepts": [ + { + "type": "autogenerated", + "dirName": "concepts" + } + ], + "staking": [ + { + "type": "autogenerated", + "dirName": "participate/01_staking" + } + ], + "governance": [ + { + "type": "autogenerated", + "dirName": "participate/02_governance" + } + ], + "chain": [ + { + "type": "autogenerated", + "dirName": "develop/02_chain" + } + ], + "workshop": [ + { + "type": "autogenerated", + "dirName": "develop/03_workshop" + } + ], + "dApp": [ + { + "type": "autogenerated", + "dirName": "develop/07_dApp" + } + ], + "opendid": [ + { + "type": "autogenerated", + "dirName": "develop/08_opendid" + } + ], + "sdk": [ + { + "type": "autogenerated", + "dirName": "develop/01_sdk" + }, + { + "type": "link", + "label": "API Documentation", + "href": "https://kiltprotocol.github.io/sdk-js/index.html" + } + ] +} diff --git a/versions.json b/versions.json new file mode 100644 index 000000000..e2278f21c --- /dev/null +++ b/versions.json @@ -0,0 +1,4 @@ +[ + "1.0.0", + "0.35.0" +] From a2db69f178b2b4e8495fb01d39c4ca64d174bfa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aybars=20G=C3=B6ktu=C4=9F=20Ayan?= Date: Mon, 27 Jan 2025 23:45:19 +0300 Subject: [PATCH 2/3] feat: versioning & under construction --- .../02_cookbook/01_dids/00_generate_keys.md | 57 +------------ .../01_dids/01_light_did_creation.md | 30 +------ .../01_dids/02_full_did_creation.md | 30 ++----- .../02_cookbook/01_dids/03_full_did_update.md | 13 ++- .../02_cookbook/01_dids/04_did_query.md | 16 +--- .../02_cookbook/01_dids/05_full_did_delete.md | 23 +----- .../02_cookbook/01_dids/06_full_did_tx.md | 53 ++---------- .../02_cookbook/01_dids/07_did_signature.md | 19 +---- .../02_cookbook/01_dids/08_did_export.md | 17 ++-- .../02_cookbook/02_web3names/01_claim.md | 15 ++-- .../02_web3names/02_credential_query.md | 17 ++-- .../02_cookbook/02_web3names/03_release.md | 44 ++-------- .../02_cookbook/02_web3names/04_query.md | 20 ++--- .../02_cookbook/03_account_linking/01_link.md | 81 +------------------ .../03_account_linking/02_account_name.md | 23 ++---- .../03_account_linking/03_unlink.md | 26 ++---- .../04_claiming/01_ctype_creation.md | 38 +-------- .../04_claiming/02_attestation_request.md | 17 ++-- .../04_claiming/03_attestation_creation.md | 17 ++-- .../04_claiming/04_presentation_creation.md | 20 +---- .../05_presentation_verification.md | 21 +---- .../04_claiming/06_credential_revocation.md | 22 ++--- .../01_credential_issuance.md | 38 +-------- .../02_credential_retrieval.md | 62 +------------- .../03_credential_revocation.md | 59 ++------------ .../02_cookbook/06_messaging/01_messaging.md | 51 ++---------- .../06_messaging/02_replay_protection.md | 39 ++------- 27 files changed, 125 insertions(+), 743 deletions(-) diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/00_generate_keys.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/00_generate_keys.md index 1553de1f2..9d83844a1 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/00_generate_keys.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/00_generate_keys.md @@ -3,61 +3,12 @@ id: key-generation title: Generate DID keys --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import GenerateKeys from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/00_generate_did_keys.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -Creating a Decentralized Identifier (DID) on the KILT network involves generating keying material for authentication and encryption. -This guide shows how to create a set of key pairs suitable for generating a KILT DID. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -Before proceeding, it's important to note that this example assumes the usage of the `@kiltprotocol/sdk-js` library along with the `@polkadot/util-crypto` library for cryptographic operations. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -Additionally, it's important to securely store keys and the mnemonic seed phrase. -For production use, ensure that private keys are encrypted and stored safely, while also creating a backup of the mnemonic seed phrase. - -## Derivation paths - -The code example below derives different types of keys from a single account using derivation paths. - -A derivation path is a way to derive a new key from a parent key and is a sequence of indices separated by a delimiter. -The most common delimiter is `/` (forward slash). - -KILT uses the same derivation paths as the underlying Polkadot libraries, using soft and hard key derivation. - -## Soft derivation - -A soft derivation allows someone to potentially figure out the initial account's private key if they know the derived account's private key. -It is also possible to determine that different accounts generated from the same seed are linked to that seed. - -A `/` (single slash) indicates a soft derivation path. -For example, `deal rice sunny now boss cluster team use wreck electric wing deliver/0` is a soft derivation path. - -## Hard derivation - -A hard derivation path does not allow someone to do either of these. -Even if you know a derived private key, it's not possible to figure out the private key of the root address, and it's impossible to prove that the first account is linked with the second. - -A `//` (double slash) indicates a hard derivation path. -For example, `deal rice sunny now boss cluster team use wreck electric wing deliver//0` is a hard derivation path. - -## Creating new accounts from a seed - -This approach allows you to generate various key pairs for authentication, key agreement, assertion methods, and capability delegation from one mnemonic seed phrase. - -To create another account using the same seed, change the number at the end of the string. For example, `/1`, `/2`, and `/3` create different derived accounts. - -Using derivation paths simplifies key management, ensuring that a single mnemonic seed serves as the basis for multiple keys associated with a DID. -This method improves efficiency while maintaining security. -However, it's essential to handle and store private keys securely to prevent unauthorized access and ensure the overall integrity and privacy of the decentralized identity system. - -Below is an example code snippet illustrating the key pair generation for a KILT DID: - - - {GenerateKeys} - - -:::info -This example doesn't show how to store the keys. -It is recommended to store the keys in a secure manner, e.g. only storing the private keys encrypted on disk. -The mnemonic seed phrase can be used to regenerate the keys, so it is recommended to also store the mnemonic in a secure manner and create a backup of it. ::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md index 01c59ac8b..6669db543 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/01_light_did_creation.md @@ -3,34 +3,12 @@ id: light-did-creation title: Create a Light DID --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import LightDidSimple from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/01_light_did_simple.ts'; -import LightDidComplete from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/02_light_did_complete.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -The creation of a light DID requires the generation of some keying material for keys that are to be used for authentication and encryption. -For the sake of ease of use, the example snippets below show how to use keys generated with a `Keyring`, provided also by the `@polkadot/api` library, to generate key pairs that are kept in memory and disappear at the end of the program execution, unless saved to some persistent storage. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -The following is an example of how to create a light DID after creating an authentication keypair. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ - - {LightDidSimple} - - -For cases in which an encryption key and some services also need to be added to a light DID: - - - {LightDidComplete} - - -:::info -In KILT, light DIDs are meant to be used in one of two cases: - -1. As *ephemeral, one-time identifiers* when establishing new communication channels with untrusted parties. -2. As an *entrypoint into the KILT ecosystem*, i.e., to obtain one's first credentials and get acquainted with KILT. - -As such, light DIDs do not support updates of any sort, but they retain the same identifier until they are upgraded to full DIDs. -They are not intended for use in complex and/or high-security use cases. -In those situations, a full DID should be used. -Visit the [next section](./02_full_did_creation.md) to see how to create and manage full DIDs. ::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/02_full_did_creation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/02_full_did_creation.md index 389e8e940..4e460ce13 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/02_full_did_creation.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/02_full_did_creation.md @@ -3,32 +3,12 @@ id: full-did-creation title: Create a Full DID --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import FullDidSimple from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/04_full_did_simple.ts'; -import FullDidComplete from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/05_full_did_complete.ts'; -import LightDidMigrate from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/03_light_did_migrate.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -The following is an example of how to create and write on the blockchain a full DID that specifies only an authentication key. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ - - {FullDidSimple} - +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -If additional keys or services are to be specified, they can be passed as parameters to the creation transaction. - - - {FullDidComplete} - - -## Upgrade a Light DID to a Full DID - -Another way to obtain a full DID is by upgrading a previously-created light DID. -KILT supports this operation in a way that does not invalidate any credentials that had been issued to the light DID before being upgraded. - -The following code shows how to migrate a light DID to a full DID. -Credentials, presentations, and verifications remain unchanged and remain valid. - - - {LightDidMigrate} - +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/03_full_did_update.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/03_full_did_update.md index 688385841..2a5673347 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/03_full_did_update.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/03_full_did_update.md @@ -3,13 +3,12 @@ id: full-did-update title: Update a Full DID keys and service endpoints --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import FullDidUpdate from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/07_full_did_update.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -Once anchored to the KILT blockchain, a full DID can be updated. -For instance, the following snippet shows how to use the `authorizeBatch` function to update the authentication key, remove an old service *and* add a new one for a full DID in the same transaction. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ - - {FullDidUpdate} - +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ + +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/04_did_query.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/04_did_query.md index 99f68590b..8706b0395 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/04_did_query.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/04_did_query.md @@ -3,20 +3,12 @@ id: did-query title: Resolve a DID --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import DidQuery from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/06_did_query.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -Querying the state of a DID is called **resolution**. -The entity that queries the DID Document for a given DID, i.e., resolves it, is called a **resolver**. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -The KILT SDK provides such a resolver to use with KILT DIDs, as the snippet below shows: +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ - - {DidQuery} - - -:::note -The DID resolver can resolve both light and full DIDs. -For a more in-depth explanation about the KILT DID method and resolution, refer to our [specification](https://github.com/KILTprotocol/spec-kilt-did). ::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/05_full_did_delete.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/05_full_did_delete.md index 4e4232956..2d28b4dd1 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/05_full_did_delete.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/05_full_did_delete.md @@ -3,27 +3,12 @@ id: full-did-delete title: Delete a Full DID --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import FullDidDelete from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/11_full_did_delete.ts'; -import FullDidDepositReclaim from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/13_full_did_deposit_reclaim.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -Once a DID is no longer needed, it is recommended to deactivate it by removing it from the KILT blockchain. -The following snippet shows how to do it: +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ - - {FullDidDelete} - +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -:::warning -Please note that once deleted, a full DID becomes unusable and cannot be re-created anymore. -This means that all credentials obtained with that DID are no longer valid and must be obtained with a different DID if needed. ::: - -## Claim back a DID deposit - -Claiming back the deposit of a DID is semantically equivalent to deactivating and deleting the DID, with the difference that the extrinsic to claim the deposit can only be called by the deposit owner and does not require a signature by the DID subject: - - - {FullDidDepositReclaim} - \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/06_full_did_tx.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/06_full_did_tx.md index ace83349e..26b07e76f 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/06_full_did_tx.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/06_full_did_tx.md @@ -3,55 +3,12 @@ id: full-did-batch title: Build DID Extrinsics --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import FullDidSignTx from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/09_full_did_tx.ts'; -import FullDidBatch from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/08_full_did_batch.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -DID keys can be used to sign extrinsic. -But not every extrinsic can be signed using a DID. -The Spiritnet blockchain offers two types of extrinsics. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -The first type can only be called using an account. -We call them account extrinsic. -The second callable type are DID extrinsics. -They must be used for all KILT features like creating CTypes, issue attestations, etc. -Since every extrinsic requires fees to be paid, this type needs to be wrapped inside an account extrinsic. -Accounts hold balances and can therefore pay fees and provide deposits. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -This document describes how to sign the DID extrinsics. -The KILT SDK provides two functions for signing DID extrinsics. -The first function signs a single extrinsic while the second one batches multiple extrinsics together. - -## Single extrinsics - -To sign a single extrinsic, you need to provide: - -* the DID that wants to sign the extrinsic (also called *origin* of the extrinsic) - * refer to the [full did creation guide](02_full_did_creation.md) to learn how to create a DID -* [a `SignCallback` that signs the extrinsic](../07_signCallback.md) -* the extrinsic that should be signed and submitted -* and the address of the account that pays for the fees. - - - {FullDidSignTx} - - - -## Batch multiple extrinsics - -Full DIDs can also be used to batch multiple extrinsics that require the signature of the DID. -For instance, a batch could create multiple services with a single submission to the blockchain. -This would save the user the time of generating one additional signature, as multiple extrinsics are batched and signed at once. -The extrinsics are also submitted and executed in the same block. -For more information, see the [official Substrate documentation](https://paritytech.github.io/substrate/master/pallet_utility/pallet/struct.Pallet.html). - -An example of a batch using the `authorizeBatch` is provided below. - - - {FullDidBatch} - - -DIDs have different keys that posses different capabilities. -Each key can only be used to authorize a specific subset of extrinsics. -If extrinsics are batched together that require different DID keys, the `authorizeBatch` function will call the sign callback multiple times. +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/07_did_signature.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/07_did_signature.md index 7c6659fb4..799f7acf8 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/07_did_signature.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/07_did_signature.md @@ -3,23 +3,12 @@ id: did-signature title: Generate and Verify a DID Signature --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import DidSignature from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/10_did_signature.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -In addition to being used to authorize chain operations, both light and full DIDs have off-chain applications. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -One such applications is generating digital signatures. -As a DID can have multiple keys, in addition to the signature data itself, a DID signature contains information about the signer's DID and key used, so that Verifiers have all the information needed to resolve the DID from the KILT blockchain and use the right key to verify the generated signature. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -The snippet below shows how to generate and verify a DID signature using the KILT SDK. - - - {DidSignature} - - -:::note -Notice that the snippet above takes a `DidDocument` instance to generate the signature. -A `DidDocument` can represent either a light or a full DID. -This means that both light and full DIDs can generate signatures, and the KILT SDK implements the right verification logic depending on whether the signer is a light or a full DID. ::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/08_did_export.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/08_did_export.md index 8b53f209d..ab4923072 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/08_did_export.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/01_dids/08_did_export.md @@ -3,19 +3,12 @@ id: did-export title: Exporting a KILT DID --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import DidExport from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/did/12_did_export.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -The DID Document exporter provides the functionality needed to convert an instance of an SDK `DidDocument` object into a document that is compliant with the [W3C specification](https://www.w3.org/TR/did-core/). -This component is required for the KILT plugin for the [DIF Universal Resolver](https://dev.uniresolver.io/). +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -## How to use the exporter +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -The exporter interface and used types are part of the `@kiltprotocol/types` package, while the actual `DidDocumentExporter` is part of the `@kiltprotocol/did` package. -Both types and DID packages are accessible via the top-level `@kiltprotocol/sdk-js` import. -The following shows how to use the exporter to generate a W3C-compliant DID Document from a given `DidDocument`, which can represent either a light or a full DID. - - - {DidExport} - \ No newline at end of file +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/01_claim.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/01_claim.md index 88f687ba8..28b92d654 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/01_claim.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/01_claim.md @@ -3,17 +3,12 @@ id: web3name-claim title: Claim a web3name --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import Claim from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/01_claim.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -A web3name can be claimed if it currently has no owner, using the following snippet as reference. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ - - {Claim} - +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -The claiming process requires the reservation of a deposit that is freed upon web3name release. - -Once claimed, the web3name will start appearing whenever the DID of its owner is resolved, for instance via the [Universal Resolver](https://dev.uniresolver.io/#did:kilt:4pZGzLSybfMsxB1DcpFNYmnqFv5QihbFb1zuSuuATqjRQv2g). -For more information about web3names and DIDs, see the official [KILT DID Specification](https://github.com/KILTprotocol/spec-kilt-did/blob/main/README.md). +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/02_credential_query.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/02_credential_query.md index 9213f6810..067869f81 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/02_credential_query.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/02_credential_query.md @@ -3,19 +3,12 @@ id: credential-query title: Query Public Credentials for a web3name --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import QueryNameCredentials from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/03_query_name_credentials.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -web3names are linked to KILT DIDs, and KILT DIDs can define services to expose additional service/information. -One of the possible endpoint types is the [`KiltPublishedCredentialCollectionV1`][kilt-published-credential-collection-v1-type] type. -The type defines the structure to make KILT credentials public and accessible to anyone. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -Because of the relationship between web3names and DIDs, it is possible, given a certain web3name, to retrieve all public credentials that the DID subject identified by that web3name has made available. -Below is a code snippet showing how to do that using the KILT SDK, and how to perform the needed security checks/validation as recommended by the [specification][kilt-published-credential-collection-v1-type]. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ - - {QueryNameCredentials} - - -[kilt-published-credential-collection-v1-type]: https://github.com/KILTprotocol/spec-KiltPublishedCredentialCollectionV1/blob/main/README.md +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/03_release.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/03_release.md index a22050964..6d4467e41 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/03_release.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/03_release.md @@ -3,46 +3,12 @@ id: web3name-release title: Release a web3name --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import Release from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/04_release.ts'; -import ReclaimDeposit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/05_reclaim_deposit.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -If a web3name is no longer needed, either the DID owner or the deposit payer can release it, with deposit being released and returned to the original payer. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -## Releasing a Web3name by the DID Owner +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -In the case of the DID owner willing to release the web3name, the following snippet provides a reference implementation on how to achieve that. - - - {Release} - - -In the code above, the `releaseWeb3Name` function takes the following parameters: - -* **did**: The DID URI of the owner. -* **submitterAccount**: The keyring pair of the submitter. -* **signCallback**: The sign extrinsic callback function. This function is used to sign the extrinsic, read more that in [the SignCallback section](../07_signCallback.md). - -The function `releaseWeb3Name` uses the KILT SDK to create a *web3name release transaction* using `api.tx.web3Names.releaseByOwner`. -It then authorizes the transaction using the `Kilt.Did.authorizeTx` method and submits the authorized transaction to the blockchain using `Kilt.Blockchain.signAndSubmitTx`. -This process ensures that the release transaction is signed by the DID owner. - - -## Reclaiming a Web3name Deposit by the Deposit Payer - -If the web3name is being released by the deposit payer, the signature of the DID owner is not required; a regular signed extrinsic can be submitted to the KILT blockchain, as shown below. - - - {ReclaimDeposit} - - -In the code above, the `reclaimWeb3NameDeposit` function takes the following parameters: - -* **submitterAddress**: The keyring pair of the submitter. -* **web3Name**: The web3name for which the deposit is to be reclaimed. - -The function creates a web3name deposit reclaim transaction using `api.tx.web3Names.reclaimDeposit` and submits the signed transaction to the blockchain using `Kilt.Blockchain.signAndSubmitTx`. -Since the web3name is being released by the deposit payer, the signature of the DID owner is not required. - -By using these code examples, you can easily release or reclaim the deposit of a web3name, depending on the scenario and the role of the entity initiating the release. +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/04_query.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/04_query.md index 8112e5886..2bed71937 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/04_query.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/02_web3names/04_query.md @@ -3,22 +3,12 @@ id: web3name-query title: Resolve a web3name --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import QueryDid from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/web3names/02_query_did_name.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -A web3name can be resolved in a similar manner to [how a DID is resolved](../01_dids/04_did_query.md). -Resolving the web3name will provide the same information as resolving a DID does. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -To query and retrieve the DID document associated with a web3name, you can use the following code example: - - - - {QueryDid} - - -In the code example above, the `queryDidDocument` function takes a web3Name parameter, which represents the web3name to be resolved. -It internally uses the `api.call.did.queryByWeb3Name` method to query the information of the provided web3name from the blockchain. - -The function then decodes the result using `Kilt.Did.linkedInfoFromChain` to extract the associated DID document and any other linked blockchain accounts. Finally, it returns the resolved DID document. +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/01_link.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/01_link.md index db6735186..674e6f3c6 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/01_link.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/01_link.md @@ -3,85 +3,12 @@ id: account-link title: Link an Account to a KILT DID --- -import TsJsBlock from '@site/src/components/TsJsBlock'; -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +:::caution Under Construction ๐Ÿšจ -import SubAccLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/01_sub_link.ts'; -import EthAccLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/01_eth_link.ts'; -import EthWeb3AccLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/01_eth_link_web3js.ts'; -import EthMetamaskAccLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/01_eth_link_metamask.ts'; -import SenderLink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/02_sender_link.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -Sometimes there is the need to link a DID to an account publicly. -The link makes it possible to lookup a DID for an account. -The other directions is also possible. -With a DID you can lookup a list of linked account. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -Linking accounts can be useful when your account should have an identity. -E.g. as a collator, you might want to provide some public information so that delegator can better decide who earned their stake. - -An account can be linked to a DID in one of two ways. -Either the account that sends the transaction links itself to the DID, or the sender is unrelated to the DID and a third account is linked. -In the latter case, a challenge needs to be signed using the third account, to prove ownership. - -The second option is useful in cases where the account that should be linked doesn't own KILT tokens and the transaction is paid for by a third party. -This option also allows to link account schemes that are not native to the Spiritnet Blockchain. -Right now the only other address scheme supported are ethereum accounts. - -:::warning Don't use linked accounts for asset transfers - -Don't use these linked accounts for asset transfers. -Since these accounts are not limited to KILT accounts, but can be used on any chain, the recipient might not be able to access the transferred asset on other chains. -When a link to an account on a different Polkadot chain is created, this account might only be usable on this specific chain. - -If you want transfer assets to a DID have a look at [the asset transfer service](https://github.com/KILTprotocol/spec-KiltTransferAssetRecipientV1). +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ ::: - -## Linking the sender to a DID - -Link the sender of the transaction to the DID. -The sender will provide the deposit and pay the fees. -They will also be linked to the DID. - - - {SenderLink} - - -## Linking an account to a DID - -Link another account to the DID. -The sender will provide the deposit and pay the fees, but will not be linked to the DID in any way. -The account that should be linked must sign a challenge to prove that the account agrees to be linked. - -The proof contains the DID that the account will be linked to and an expiration date (in terms of blocks), to prevent replay attacks. -The proof will only be valid up until the blocknumber is reached. - -With this option you can link addresses that are supported by the Spiritnet blockchain (Sr25519, Ed25519, Ecdsa), but also ethereum addresses. - - - - - {SubAccLink} - - - - - {EthAccLink} - - - - - {EthWeb3AccLink} - - - - Refer to the Metamask documentation for further information. - - {EthMetamaskAccLink} - - - diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/02_account_name.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/02_account_name.md index ed7357fb6..ba5185fd5 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/02_account_name.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/02_account_name.md @@ -3,25 +3,12 @@ id: account-name title: Query the web3name of an Account --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import AccountWeb3NameQuery from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/03_account_web3name_query.ts'; -import AccountWeb3NameQueryNoSDK from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/04_account_web3name_query_no_sdk.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -For accounts that have been linked to DIDs that have claimed a web3name, the linking feature opens the way to a host of possibilities, e.g., showing the web3name of a collator's account on the [KILT Stakeboard][kilt-stakeboard]. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -This section shows how to perform the `account -> web3name` querying both with and without the support of the KILT SDK. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -## Query an Account's web3name with the KILT SDK - - - {AccountWeb3NameQuery} - - -## Query an Account's web3name without the KILT SDK - - - {AccountWeb3NameQueryNoSDK} - - -[kilt-stakeboard]: https://stakeboard.kilt.io/ +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/03_unlink.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/03_unlink.md index 08711f178..dca3bd12d 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/03_unlink.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/03_account_linking/03_unlink.md @@ -3,28 +3,12 @@ id: account-unlink title: Unlink an Account From a KILT DID --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import DidUnlink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/05_did_unlink.ts'; -import AccountUnlink from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/06_account_unlink.ts'; -import ReclaimDeposit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/linking/07_reclaim_deposit.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -Similar to the way a new account to DID link is created, removing a link can happen in one of three ways: +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -1. The DID owner submits a transaction indicating which account to unlink: +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ - - {DidUnlink} - - -2. The linked account submits a transaction indicating that the link with the DID should be removed: - - - {AccountUnlink} - - -3. The deposit payer submits a transaction indicating that they want to reclaim their deposit, which in turn removes the existing link between the specified account and DID: - - - {ReclaimDeposit} - \ No newline at end of file +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md index 12d3aba54..7c63e719d 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/01_ctype_creation.md @@ -3,42 +3,12 @@ id: ctype-creation title: Create a CType --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import CreateCType from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/01_create_ctype.ts'; -import FetchCType from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/02_fetch_ctype.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -Every KILT credential has to conform to a CType. -A CType describes which properties a credential has and what type these properties have. -CTypes must be registered on the Spiritnet blockchain. -To learn more about CTypes, see the [CType concept section](../../../../concepts/05_credentials/02_ctypes.md). +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -The creation of a CType in KILT involves two steps: the definition of a CType and the anchoring of its hash on the KILT blockchain. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -:::info DID required -The creator of a CType is required to have a full DID with an attestation key. -To see how to manage DIDs, please refer to the [DID section](../01_dids/03_full_did_update.md). ::: - -:::info CTypes are unique -The creation of a new CType requires the CType hash to be unique. -Before writing a new CType, Attesters should check whether there is already an existing CType which matches their requirements. - -Visit our [CType index repository](https://github.com/KILTprotocol/ctype-index) for a non-exhaustive list of existing CTypes. -::: - -The following snippets show how to create a CType: - - - {CreateCType} - - - -## Retrieve a CType from its ID - -CTypes can be queried directly from any KILT archive nodes. -The following example shows how to query a CType using the SDK: - - - {FetchCType} - diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md index bd602126f..b01a2eb7c 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/02_attestation_request.md @@ -2,20 +2,13 @@ id: attestation-request title: Request an Attestation --- -import TsJsBlock from '@site/src/components/TsJsBlock'; -import RequestAttestation from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/03_request_attestation.ts'; +:::caution Under Construction ๐Ÿšจ -To obtain credentials, Claimers have to request an attestation for a set of claims from an Attester. -The resulting object is a `Credential`, which can be created following the snippet below. +**We are currently documenting version 1.0!** ๐Ÿ”จ -This process does not involve any interaction with the KILT blockchain, but is simply a communication channel where the Claimer and the Attester can communicate. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ - - {RequestAttestation} - +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -:::note -The structure of the claims must respect the schema defined in the specified CType. -Attesters (and Verifiers) will reject claims that fail to verify correctly. -::: \ No newline at end of file +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md index 1a53d3755..f7f44acfc 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/03_attestation_creation.md @@ -3,19 +3,12 @@ id: attestation-creation title: Attest a Claim (Issue a Credential) --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import CreateAttestation from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/04_create_attestation.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -Once an Attester has received a to-be-attested `Credential` from a Claimer, they will typically verify the information in the claim. -If the claims correspond to truth, the Attester will proceed by attesting the root hash of the credential on the KILT blockchain, timestamping the attestation operation. -A deposit is reserved from the balance of the KILT account submitting the creation transaction, which is returned if and when the attestation is removed from the chain. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -:::info -An Attester is required to have a full DID with an attestation key. -To see how to manage DIDs, please refer to the [DID section](../01_dids/03_full_did_update.md). -::: +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ - - {CreateAttestation} - \ No newline at end of file +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md index facd14d49..afc004f15 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/04_presentation_creation.md @@ -3,24 +3,12 @@ id: presentation-creation title: Present a Credential --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import CreatePresentation from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/05_create_presentation.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -With a valid credential, Claimers can now go to Verifiers to request some service upon providing proof of validity of a certain credential. -The process of presenting one or more credentials to a Verifier is called `Presentation`. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -This step, similar to the [attestation request](./02_attestation_request.md), requires that a communication channel exist between the Claimer and the Verifier so that information about the presentation can be shared. -To verify the revocation status of the presented credential(s), a Verifier must be able to interact with a KILT full node. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -:::info -KILT supports selective disclosure of claims when creating presentations. -This means that given a credential, it is possible for the Claimer to reveal only a subset of its claims, depending on the requirements set by the Verifier. -Check the snippet below to see how that is done using the KILT SDK. ::: - -The Claimer can generate a presentation starting from a credential, optionally specifying the fields to reveal and a presentation challenge, which is useful to prove freshness of the generated presentation. - - - {CreatePresentation} - \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md index 480cc236d..de8d56fb9 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/05_presentation_verification.md @@ -3,25 +3,12 @@ id: presentation-verification title: Verify a Credential or a Presentation --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import VerifyPresentation from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/06_verify_presentation.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -Whether a presentation involves selective disclosure or a whole credential is not technically relevant to Verifiers. -This is because in KILT a presentation **is** a credential. -This means that the logic for Verifiers does not change depending on the case, thus verifying a presentation is as easy as calling one SDK function, like the following code snippet: +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ - - {VerifyPresentation} - +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -:::warning Check if the presenter is the credential subject -Verifying a presentation provides proof that all the information is correct and authentic, and that the credential has not been revoked. -Verifiers still need to match the subject of the credential to the entity that is presenting it. -One way of achieving this is by asking the Claimer to include a challenge in the presentation signature, as shown in the snippet above. -Without a challenge, Verifiers must implement other measures to be certain about the identity of the presenter. ::: - -:::warning Evaluation of the attester's trust is up to the Verifiers -Verifiers must also have a registry of attesters they trust, and verify that the issuer of the credential they are verifying belongs to such list and, where necessary, whether it is still in operation or not, i.e., whether its DID still exists or has been deleted. -::: \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/06_credential_revocation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/06_credential_revocation.md index da6ff398b..d0056df12 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/06_credential_revocation.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/04_claiming/06_credential_revocation.md @@ -3,24 +3,12 @@ id: attestation-removal title: Revoke a Credential --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import RevokeCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/07_revoke_credential.ts'; -import ReclaimDeposit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/claiming/08_reclaim_attestation_deposit.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -If the conditions that make a credential valid cease to exist, an Attester can revoke and optionally remove their attestation from the KILT blockchain. -This does not automatically delete the credential from the Claimer's wallet, of course, but it makes it impossible for the Claimer to use the credential in the future. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -Since the attestation creation reserved some KILT tokens from the submitter's balance, removing an attestation would return those funds into the payer's pockets. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ - - {RevokeCredential} - - -## Claim Back an Attestation Deposit - -Claiming back the deposit of an attestation is semantically equivalent to revoking and removing the attestation, with the difference that the extrinsic to claim the deposit can only be called by the deposit owner and does not require the Attester's signature: - - - {ReclaimDeposit} - \ No newline at end of file +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/01_credential_issuance.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/01_credential_issuance.md index 2bd743f12..0bbddb3b6 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/01_credential_issuance.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/01_credential_issuance.md @@ -3,42 +3,12 @@ id: public-credential-issuance title: Credential Issuance --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import CreateCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/01_create_credential.ts'; -import IssueCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/02_issue_credential.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -As for traditional KILT credentials, public credentials also have their structure defined by a [CType][ctypes-link], although CTypes that can be used to represent information about assets would probably differ from the ones used to represent information about people. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -As mentioned in the section about credentials, the creation of a CType in KILT involves two steps: the definition of a CType and the anchoring of its hash on the KILT blockchain. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -We will not cover the creation of a CType, please refer to the [CType creation](../04_claiming/01_ctype_creation.md) - -## Create and Issue the Credential - -Using the existing CType, the new public credential object can be created with the actual content, and then written to the chain for the rest of the KILT users (and beyond) to consume. - -Creating a public credential is as simple as creating an object that conforms to the required structure of the CType: - - - {CreateCredential} - - -:::note -The creation of the credential object does not require any interaction with the blockchain per se. -This also means that, until the object is written to the blockchain (see below), it cannot be used/retrieved/verified by anyone else, so it is, by all means, not existing. ::: - -Once the credential object is created, it must be written to the blockchain for other people to be able to use it. - - - {IssueCredential} - - -:::info Credential has to be CBOR-encoded! -Given a public credential object, the SDK internally CBOR-encodes it before firing the extrinsic to the blockchain! -This is to save space on credentials that actually benefit from CBOR compression (e.g., if they contain a lot of binary information). -Hence, creating public credentials without the SDK requires the credential to be CBOR-encoded! -::: - -[ctypes-link]: ../../../../concepts/05_credentials/02_ctypes.md diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/02_credential_retrieval.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/02_credential_retrieval.md index 925becd7f..c74933692 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/02_credential_retrieval.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/02_credential_retrieval.md @@ -3,66 +3,12 @@ id: public-credential-retrieval title: Retrieve Public Credentials --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import RetrieveCredentialbyId from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/03_retrieve_credential_by_id.ts'; -import RetrieveCredentialsbySubject from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/04_retrieve_credentials_by_subject.ts'; -import VerifyCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/05_verify_credential.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -Public credentials have their best capability in the fact that they are, indeed, public by design. -This means that once issued, anyone who has access to an archive or full node for the KILT blockchain can retrieve them, making them very decentralized in nature. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -The KILT SDK exposes different ways to fetch public credentials. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -## Retrieve a Credential by its Identifier - -Some use cases might involve the communication of just the ID of one or more public credentials, e.g., to offload the retrieval of the full credential to the receiver, and save some communication bandwidth. - -The KILT SDK accounts for this use case, and makes it very easy to query a public credential given its ID: - - - {RetrieveCredentialbyId} - - -If a credential with the provided ID cannot be found, then the ID is invalid and should be treated as such by the received. - -## Retrieve All Credentials for an Asset - -Other use cases might work differently: given an asset identified by an [AssetDID][asset-did-concept], a user might want to retrieve all the credentials that have been issued to that asset. - -The KILT SDK makes also this use case very easy: - - - {RetrieveCredentialsbySubject} - - -## Verify a Public Credential - -A third class of use cases might involve users exchanging whole public credentials, for instance when showing some sort of proof. - -This case is also supported by the KILT SDK, and relies on an important feature of public credentials: **the identifier (ID) of a public credential is generated from its content and from the KILT DID of its attester**. -This means that even a minimal change in the content of a public credential object before being shared with other parties, will result in those parties deriving a different identifier from the credential, which will then lead to an error during the verification process. - -Verifying a public credential is shown in the following snippet: - - - {VerifyCredential} - - -What the `verifyCredential` function does internally is the following: - -1. Derive the credential identifier from the provided content and attester information. -2. Fetch the actual credential from the blockchain, as shown in the [section above](#retrieve-a-credential-by-its-identifier), failing if the credential does not exist. -3. [OPTIONAL] Verify that the credential structure matches what the optionally-provided CType defines. -4. Verify that the rest of the fields in the provided credential (i.e., revocation status, identifier, creation block number) match the retrieved credential. - -If all the tests above pass, the credential is considered valid! โœ… - -:::info How are public credentials stored on the blockchain? -Because public credentials need to be public and accessible by everyone, their full content needs to be somehow stored on the blockchain. -Nevertheless, the credential itself is not stored as part of the blockchain database. -Rather, the block number in which the extrinsic is submitted is stored inside the blockchain database, and serves as a "pointer" to the block containing the whole information, that clients (including the SDK) can use. -This represents a very good tradeoff between **security** - because the blockchain itself dictates what the creation block number is for any given public credential - and **storage efficiency** - since the full credential is stored off-chain, accessible via any KILT archive node or indexing service. ::: - -[asset-did-concept]: ../../../../concepts/04_asset_dids.md diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/03_credential_revocation.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/03_credential_revocation.md index 23f9a79f9..9d9c1f12a 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/03_credential_revocation.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/05_public_credentials/03_credential_revocation.md @@ -3,61 +3,12 @@ id: public-credential-revocation title: Revoke (and remove) Public Credentials --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import RevokeRemoveCredentialById from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/06_revoke_remove_credential_by_id.ts'; -import RevokeCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/07_revoke_remove_credential_by_content.ts'; -import UnrevokeCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/08_unrevoke_credential.ts'; -import ReclaimDeposit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/public_credentials/09_reclaim_deposit.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -Depending on the use cases, some credentials, as with any other type of credential, might need to be temporarily or permanently revoked. +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -The KILT SDK provides different features depending on the needs of the use case. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -## Revoke and Remove a Credential - -As we have seen for [public credential retrieval][credential-retrieval], a credential identifier is sufficient to perform most operations on public credentials. -This is true also for revocation and removal. - -Some use cases might need a revoked credential to remain on chain and marked as revoked, while other use cases might combine together revocation and removal, removing a credential whenever it is to be marked as revoked, fulfilling the same goal of marking the credential as invalid. - -In the former case, the deposit taken at the time when the credential is created is not returned, since the credential is still on chain. -In the latter case, all information about the information is cleared, hence the deposit is returned to its original payer. - - - {RevokeRemoveCredentialById} - - -Because a credential identifier can also be calculated starting from the credential itself and the information about its attester, it is also possible to revoke (and optionally remove) a credential given the credential itself. - - - {RevokeCredential} - - -## Unrevoke a Credential - -For public credentials that have been revoked but not removed from chain, it is possible to un-revoke them, making them valid again. - -For instance, a driving license can be marked as "suspended" for three years, without being completely invalidated. -At the end of the suspension period, it is enabled again by being unrevoked. - -As for revocation, both the credential ID and the whole credential can be used, since the SDK provides the primitives to always obtain the former from the latter, but here we show how the whole credential can be used to generate and submit an un-revocation transaction. - - - {UnrevokeCredential} - - -## Reclaim the Deposit for a Credential - -All the operations mentioned so far, always require the participation of the public credential attester, who must use their assertion key to sign all operations before they are submitted to the KILT blockchain. - -The only operation that can be submitted directly by someone else, as with other places in the SDK, is the transaction to remove a credential and obtain the initial deposit. - -This is, technically speaking, a different operation compared to the one to remove a credential, albeit the two yield the same result: all traces of the credential are removed from the chain and the deposit is returned to its payer. -The difference between the two is about who is authorized to perform the operation: while credential removal requires a DID signature by the original credential creator (a.k.a. issuer), the deposit claiming operation requires a regular transaction signature by the KILT account that paid the original deposit, with no involvement of the original attester. - - - {ReclaimDeposit} - - -[credential-retrieval]: ./02_credential_retrieval.md \ No newline at end of file +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/01_messaging.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/01_messaging.md index 406b53343..a8dff930a 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/01_messaging.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/01_messaging.md @@ -3,53 +3,12 @@ id: messaging_book title: Generate a Message --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import GenerateRequestCredentialMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/01_generate_request_credential_message.ts'; -import EncryptMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/02_encrypt_message.ts'; -import DecryptMessage from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/03_decrypt_message.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -KILT defines a [unicast](https://en.wikipedia.org/wiki/Unicast) messaging protocol +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -Each of the messages sent is encrypted using the [DID key agreement key](https://www.w3.org/TR/did-core/#key-agreement). -A message consists of the sender's DID URI, the receiver's DID URI, the message type and the body. -There are multiple different message types, each of them with a different structure and containing different information. -In this example we are going to build a `request-credential` message. -The message structure is checked and validated on by the KILT SDK to ensure the users are sending correctly structured messages. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -The following example here will generate a message by constructing the message content. -The message content includes a valid `cTypeHash` and a list of `trusted attesters`. -The message requires a `messageBody`, sender and receiver uri. - - - {GenerateRequestCredentialMessage} - - -## Encryption - -The messages data are encrypted and decrypted using [nacl's](https://github.com/dchest/tweetnacl-js) 'x25519-xsalsa20-poly1305' algorithm, which provides repudiable authenticated encryption based on an x25519 key agreement protocol. -The DID holds keys for the encryption and decryption. -The key is called `KeyAgreement` keys. -They may also be known as encryption keys. - -The content of the object is converted from a serialized string to a byte array, which is passed into the callback function along with the sender's DID and key agreement public key of the receiver. - -The following example here will take a generated message and encrypt the message for the receiver to decrypt later. - - - {EncryptMessage} - - -The encrypted data is converted into a hex string which is known as the ciphertext along with the nonce that was generated during encryption. - -## Decryption - -The decryption takes the encrypted message and decyphers its content. -The following example here will take a encrypted message and decrypt using the private key of the receiver. -Once decrypted, it checks the content is a valid message. -The decrypted data can be used for additional steps. -After decrypting, the receiver may wish to present a credential from the trusted attester list with a given CType. - - - {DecryptMessage} - +::: diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md index 4c5d93b87..24b336264 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/02_cookbook/06_messaging/02_replay_protection.md @@ -3,41 +3,12 @@ id: replay_protection title: Protect Against Replay Attacks --- -import TsJsBlock from '@site/src/components/TsJsBlock'; +:::caution Under Construction ๐Ÿšจ -import DefineRange from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_01.ts'; -import EvaluateMessageTime from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_02.ts'; -import PurgeTimeout from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_03.ts'; +**We are currently documenting version 1.0!** ๐Ÿ”จ -Whenever data travels on a public network, even when encrypted or signed, the communicating parties need to make sure they never accept and process a message more than once to protect against exploits by malicious third parties (so-called replay attacks). -When requesting and submitting credential presentations, vulnerabilities for replay attacks can be prevented by requesting that the Claimer sign a unique piece of data as part of the presentation, as shown in the [Verification Cookbook section](../04_claiming/04_presentation_creation.md). +The documentation for **version 0.35.0** is complete and fully accessible - you can switch to it by selecting `0.35.0` from the version dropdown in the top right corner. ๐ŸŽฏ -However, protection against replay attacks can also happen on the message layer. -To help prevent these types of attacks, KILT messages are timestamped and expose a unique identifier as part of their encrypted content, which therefore cannot be tampered with. -It is good practice to impose limits on an acceptable range for timestamps on incoming messages and to keep a record of the ids of previous submissions, which can be purged after their acceptance range has run out. -This way, any resubmission is either rejected because its id is known to the recipient, or because its timestamp is too old. -Below you can find example code of how this could be implemented. +> Some sections may be incomplete or subject to change as we document the new features. Check back soon for the latest updates! โœจ -1. Define acceptance range and set up a record of past submissions: - - - {DefineRange} - - -2. Check record for each incoming message and update if accepted: - - - {EvaluateMessageTime} - - -3. Purge at regular intervals: - - - {PurgeTimeout} - +::: From 8a4cf5841c34bed7c1af8d484570077d5cfcc619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aybars=20G=C3=B6ktu=C4=9F=20Ayan?= Date: Mon, 3 Feb 2025 14:45:04 +0300 Subject: [PATCH 3/3] feat: quickstart quide v1 ready --- .../core_features/claiming/01_create_ctype.ts | 41 +++++ .../core_features/claiming/02_fetch_ctype.ts | 8 + .../claiming/03_request_attestation.ts | 20 +++ .../claiming/04_create_attestation.ts | 32 ++++ .../claiming/05_create_presentation.ts | 16 ++ .../claiming/06_verify_presentation.ts | 25 +++ .../claiming/07_revoke_credential.ts | 29 +++ .../08_reclaim_attestation_deposit.ts | 16 ++ .../src/v1/core_features/claiming/index.ts | 104 +++++++++++ .../core_features/did/00_generate_did_keys.ts | 27 +++ .../core_features/did/01_light_did_simple.ts | 15 ++ .../did/02_light_did_complete.ts | 28 +++ .../core_features/did/03_light_did_migrate.ts | 26 +++ .../core_features/did/04_full_did_simple.ts | 33 ++++ .../core_features/did/05_full_did_complete.ts | 47 +++++ .../src/v1/core_features/did/06_did_query.ts | 16 ++ .../core_features/did/07_full_did_update.ts | 46 +++++ .../v1/core_features/did/08_full_did_batch.ts | 27 +++ .../v1/core_features/did/09_full_did_tx.ts | 23 +++ .../v1/core_features/did/10_did_signature.ts | 38 ++++ .../core_features/did/11_full_did_delete.ts | 31 ++++ .../src/v1/core_features/did/12_did_export.ts | 28 +++ .../did/13_full_did_deposit_reclaim.ts | 21 +++ .../src/v1/core_features/did/index.ts | 141 +++++++++++++++ .../getting_started/01_print_hello_world.ts | 3 + .../getting_started/02_connect_pere.ts | 10 ++ .../getting_started/02_connect_spirit.ts | 10 ++ .../getting_started/03_fetch_did.ts | 16 ++ .../getting_started/04_fetch_endpoints.ts | 18 ++ .../getting_started/05_fetch_endpoint_data.ts | 14 ++ .../getting_started/06_verify_credential.ts | 16 ++ .../getting_started/07_disconnect.ts | 5 + .../v1/core_features/getting_started/index.ts | 41 +++++ .../src/v1/core_features/index.ts | 134 ++++++++++++++ .../v1/core_features/linking/01_eth_link.ts | 41 +++++ .../linking/01_eth_link_metamask.ts | 65 +++++++ .../linking/01_eth_link_web3js.ts | 55 ++++++ .../v1/core_features/linking/01_sub_link.ts | 41 +++++ .../core_features/linking/02_sender_link.ts | 24 +++ .../linking/03_account_web3name_query.ts | 23 +++ .../04_account_web3name_query_no_sdk.ts | 38 ++++ .../v1/core_features/linking/05_did_unlink.ts | 26 +++ .../linking/06_account_unlink.ts | 12 ++ .../linking/07_reclaim_deposit.ts | 15 ++ .../src/v1/core_features/linking/index.ts | 143 +++++++++++++++ .../01_generate_request_credential_message.ts | 35 ++++ .../messaging/02_encrypt_message.ts | 31 ++++ .../messaging/03_decrypt_message.ts | 38 ++++ .../messaging/_replay_protection_01.ts | 6 + .../messaging/_replay_protection_02.ts | 24 +++ .../messaging/_replay_protection_03.ts | 11 ++ .../src/v1/core_features/messaging/index.ts | 71 ++++++++ .../01_create_credential.ts | 38 ++++ .../public_credentials/02_issue_credential.ts | 26 +++ .../03_retrieve_credential_by_id.ts | 7 + .../04_retrieve_credentials_by_subject.ts | 7 + .../05_verify_credential.ts | 8 + .../06_revoke_remove_credential_by_id.ts | 27 +++ .../07_revoke_remove_credential_by_content.ts | 31 ++++ .../08_unrevoke_credential.ts | 27 +++ .../public_credentials/09_reclaim_deposit.ts | 18 ++ .../core_features/public_credentials/index.ts | 113 ++++++++++++ .../v1/core_features/signCallback/index.ts | 59 ++++++ .../signCallback/useDecryptionCallback.ts | 25 +++ .../signCallback/useEncryptionCallback.ts | 25 +++ .../signCallback/useExtrinsicCallback.ts | 31 ++++ .../signCallback/useSignCallback.ts | 22 +++ .../signCallback/useStoreTxSignCallback.ts | 28 +++ .../core_features/utils/generateKeypairs.ts | 27 +++ .../v1/core_features/utils/getExtrinsic.ts | 20 +++ .../v1/core_features/web3names/01_claim.ts | 22 +++ .../web3names/02_query_did_name.ts | 16 ++ .../web3names/03_query_name_credentials.ts | 82 +++++++++ .../v1/core_features/web3names/04_release.ts | 21 +++ .../web3names/05_reclaim_deposit.ts | 12 ++ .../src/v1/core_features/web3names/index.ts | 78 ++++++++ .../v1/dapp/dapp/01_domain_linkage_ctype.ts | 33 ++++ .../v1/dapp/dapp/02_domain_linkage_claim.ts | 23 +++ .../src/v1/dapp/dapp/03_sign_presentation.ts | 30 ++++ .../src/v1/dapp/dapp/04_attest_credential.ts | 34 ++++ .../src/v1/dapp/dapp/05_format_credential.ts | 58 ++++++ .../src/v1/dapp/dapp/06_dapp_introduction.ts | 44 +++++ .../src/v1/dapp/dapp/07_session_check.ts | 39 ++++ .../sdk_examples/src/v1/dapp/index.ts | 45 +++++ .../src/v1/dapp/verifier/01_email_ctype.ts | 19 ++ .../v1/dapp/verifier/02_generate_challenge.ts | 6 + .../03_create_request_credential_message.ts | 40 +++++ .../04_encrypt_request_credential_message.ts | 58 ++++++ .../verifier/05_verify_credential_message.ts | 71 ++++++++ code_examples/sdk_examples/src/v1/getFunds.ts | 68 +++++++ .../sdk_examples/src/v1/staking/index.ts | 25 +++ .../rewards/01_query_staking_rewards.ts | 10 ++ .../02_claim_collator_staking_rewards.ts | 57 ++++++ .../03_claim_delegator_staking_rewards.ts | 57 ++++++ .../sdk_examples/src/v1/staking/utility.ts | 30 ++++ code_examples/sdk_examples/src/v1/test.ts | 88 +++++++++ .../v1/workshop/attester/attestCredential.ts | 93 ++++++++++ .../src/v1/workshop/attester/ctypeSchema.ts | 13 ++ .../v1/workshop/attester/generateAccount.ts | 34 ++++ .../src/v1/workshop/attester/generateCtype.ts | 77 ++++++++ .../src/v1/workshop/attester/generateDid.ts | 60 +++++++ .../v1/workshop/attester/generateKeypairs.ts | 27 +++ .../src/v1/workshop/claimer/createClaim.ts | 12 ++ .../v1/workshop/claimer/createPresentation.ts | 14 ++ .../v1/workshop/claimer/generateAccount.ts | 17 ++ .../v1/workshop/claimer/generateCredential.ts | 46 +++++ .../v1/workshop/claimer/generateKeypairs.ts | 15 ++ .../v1/workshop/claimer/generateLightDid.ts | 33 ++++ .../sdk_examples/src/v1/workshop/index.ts | 70 ++++++++ .../sdk_examples/src/v1/workshop/verify.ts | 93 ++++++++++ .../develop/01_sdk/01_quickstart.md | 170 +++++++++--------- 111 files changed, 4101 insertions(+), 82 deletions(-) create mode 100644 code_examples/sdk_examples/src/v1/core_features/claiming/01_create_ctype.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/claiming/02_fetch_ctype.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/claiming/03_request_attestation.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/claiming/04_create_attestation.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/claiming/05_create_presentation.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/claiming/06_verify_presentation.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/claiming/07_revoke_credential.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/claiming/08_reclaim_attestation_deposit.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/claiming/index.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/00_generate_did_keys.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/01_light_did_simple.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/02_light_did_complete.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/03_light_did_migrate.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/04_full_did_simple.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/05_full_did_complete.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/06_did_query.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/07_full_did_update.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/08_full_did_batch.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/09_full_did_tx.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/10_did_signature.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/11_full_did_delete.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/12_did_export.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/13_full_did_deposit_reclaim.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/did/index.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/getting_started/01_print_hello_world.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/getting_started/02_connect_pere.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/getting_started/02_connect_spirit.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/getting_started/03_fetch_did.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/getting_started/04_fetch_endpoints.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/getting_started/05_fetch_endpoint_data.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/getting_started/06_verify_credential.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/getting_started/07_disconnect.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/getting_started/index.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/index.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/linking/01_eth_link.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/linking/01_eth_link_metamask.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/linking/01_eth_link_web3js.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/linking/01_sub_link.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/linking/02_sender_link.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/linking/03_account_web3name_query.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/linking/04_account_web3name_query_no_sdk.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/linking/05_did_unlink.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/linking/06_account_unlink.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/linking/07_reclaim_deposit.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/linking/index.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/messaging/01_generate_request_credential_message.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/messaging/02_encrypt_message.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/messaging/03_decrypt_message.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/messaging/_replay_protection_01.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/messaging/_replay_protection_02.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/messaging/_replay_protection_03.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/messaging/index.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/public_credentials/01_create_credential.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/public_credentials/02_issue_credential.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/public_credentials/03_retrieve_credential_by_id.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/public_credentials/04_retrieve_credentials_by_subject.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/public_credentials/05_verify_credential.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/public_credentials/06_revoke_remove_credential_by_id.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/public_credentials/07_revoke_remove_credential_by_content.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/public_credentials/08_unrevoke_credential.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/public_credentials/09_reclaim_deposit.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/public_credentials/index.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/signCallback/index.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/signCallback/useDecryptionCallback.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/signCallback/useEncryptionCallback.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/signCallback/useExtrinsicCallback.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/signCallback/useSignCallback.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/signCallback/useStoreTxSignCallback.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/utils/generateKeypairs.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/utils/getExtrinsic.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/web3names/01_claim.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/web3names/02_query_did_name.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/web3names/03_query_name_credentials.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/web3names/04_release.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/web3names/05_reclaim_deposit.ts create mode 100644 code_examples/sdk_examples/src/v1/core_features/web3names/index.ts create mode 100644 code_examples/sdk_examples/src/v1/dapp/dapp/01_domain_linkage_ctype.ts create mode 100644 code_examples/sdk_examples/src/v1/dapp/dapp/02_domain_linkage_claim.ts create mode 100644 code_examples/sdk_examples/src/v1/dapp/dapp/03_sign_presentation.ts create mode 100644 code_examples/sdk_examples/src/v1/dapp/dapp/04_attest_credential.ts create mode 100644 code_examples/sdk_examples/src/v1/dapp/dapp/05_format_credential.ts create mode 100644 code_examples/sdk_examples/src/v1/dapp/dapp/06_dapp_introduction.ts create mode 100644 code_examples/sdk_examples/src/v1/dapp/dapp/07_session_check.ts create mode 100644 code_examples/sdk_examples/src/v1/dapp/index.ts create mode 100644 code_examples/sdk_examples/src/v1/dapp/verifier/01_email_ctype.ts create mode 100644 code_examples/sdk_examples/src/v1/dapp/verifier/02_generate_challenge.ts create mode 100644 code_examples/sdk_examples/src/v1/dapp/verifier/03_create_request_credential_message.ts create mode 100644 code_examples/sdk_examples/src/v1/dapp/verifier/04_encrypt_request_credential_message.ts create mode 100644 code_examples/sdk_examples/src/v1/dapp/verifier/05_verify_credential_message.ts create mode 100644 code_examples/sdk_examples/src/v1/getFunds.ts create mode 100644 code_examples/sdk_examples/src/v1/staking/index.ts create mode 100644 code_examples/sdk_examples/src/v1/staking/rewards/01_query_staking_rewards.ts create mode 100644 code_examples/sdk_examples/src/v1/staking/rewards/02_claim_collator_staking_rewards.ts create mode 100644 code_examples/sdk_examples/src/v1/staking/rewards/03_claim_delegator_staking_rewards.ts create mode 100644 code_examples/sdk_examples/src/v1/staking/utility.ts create mode 100644 code_examples/sdk_examples/src/v1/test.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/attester/attestCredential.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/attester/ctypeSchema.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/attester/generateAccount.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/attester/generateCtype.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/attester/generateDid.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/attester/generateKeypairs.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/claimer/createClaim.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/claimer/createPresentation.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/claimer/generateAccount.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/claimer/generateCredential.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/claimer/generateKeypairs.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/claimer/generateLightDid.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/index.ts create mode 100644 code_examples/sdk_examples/src/v1/workshop/verify.ts diff --git a/code_examples/sdk_examples/src/v1/core_features/claiming/01_create_ctype.ts b/code_examples/sdk_examples/src/v1/core_features/claiming/01_create_ctype.ts new file mode 100644 index 000000000..f1cad7b53 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/claiming/01_create_ctype.ts @@ -0,0 +1,41 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function createDriversLicenseCType( + creator: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + // Create a new CType definition. + const ctype = Kilt.CType.fromProperties(`Drivers License by ${creator}`, { + name: { + type: 'string' + }, + age: { + type: 'integer' + }, + id: { + type: 'string' + } + }) + + // Generate a creation tx. + const encodedCtype = Kilt.CType.toChain(ctype) + const ctypeCreationTx = api.tx.ctype.add(encodedCtype) + // Sign it with the right DID key. + const authorizedCtypeCreationTx = await Kilt.Did.authorizeTx( + creator, + ctypeCreationTx, + signCallback, + submitterAccount.address + ) + // Submit the creation tx to the KILT blockchain + // using the KILT account specified in the creation operation. + await Kilt.Blockchain.signAndSubmitTx( + authorizedCtypeCreationTx, + submitterAccount + ) + + return ctype +} diff --git a/code_examples/sdk_examples/src/v1/core_features/claiming/02_fetch_ctype.ts b/code_examples/sdk_examples/src/v1/core_features/claiming/02_fetch_ctype.ts new file mode 100644 index 000000000..4839c3103 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/claiming/02_fetch_ctype.ts @@ -0,0 +1,8 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function fetchCType( + ctypeId: Kilt.ICType['$id'] +): Promise { + // Example CType ID: kilt:ctype:0x329a2a5861ea63c250763e5e4c4d4a18fe4470a31e541365c7fb831e5432b940 + return Kilt.CType.fetchFromChain(ctypeId) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/claiming/03_request_attestation.ts b/code_examples/sdk_examples/src/v1/core_features/claiming/03_request_attestation.ts new file mode 100644 index 000000000..50924a851 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/claiming/03_request_attestation.ts @@ -0,0 +1,20 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export function requestAttestation( + claimer: Kilt.DidDocument, + ctype: Kilt.ICType +): Kilt.ICredential { + // The claimer generates the claim they would like to get attested. + const claim = Kilt.Claim.fromCTypeAndClaimContents( + ctype, + { + name: 'Alice', + age: 29, + id: '123456789987654321' + }, + claimer.uri + ) + + const credential = Kilt.Credential.fromClaim(claim) + return credential +} diff --git a/code_examples/sdk_examples/src/v1/core_features/claiming/04_create_attestation.ts b/code_examples/sdk_examples/src/v1/core_features/claiming/04_create_attestation.ts new file mode 100644 index 000000000..a44b4d605 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/claiming/04_create_attestation.ts @@ -0,0 +1,32 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function createAttestation( + attester: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + signCallback: Kilt.SignExtrinsicCallback, + credential: Kilt.ICredential +): Promise { + const api = Kilt.ConfigService.get('api') + + // Create an attestation object and write its root hash on the chain + // using the provided attester's full DID. + const { cTypeHash, claimHash, delegationId } = + Kilt.Attestation.fromCredentialAndDid(credential, attester) + + // Write the attestation info on the chain. + const attestationTx = api.tx.attestation.add( + claimHash, + cTypeHash, + delegationId + ) + const authorizedAttestationTx = await Kilt.Did.authorizeTx( + attester, + attestationTx, + signCallback, + submitterAccount.address + ) + await Kilt.Blockchain.signAndSubmitTx( + authorizedAttestationTx, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/claiming/05_create_presentation.ts b/code_examples/sdk_examples/src/v1/core_features/claiming/05_create_presentation.ts new file mode 100644 index 000000000..2621d37d6 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/claiming/05_create_presentation.ts @@ -0,0 +1,16 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function createPresentation( + credential: Kilt.ICredential, + signCallback: Kilt.SignCallback, + selectedAttributes?: string[], + challenge?: string +): Promise { + // Create a presentation with only the specified fields revealed, if specified. + return Kilt.Credential.createPresentation({ + credential, + signCallback, + selectedAttributes, + challenge + }) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/claiming/06_verify_presentation.ts b/code_examples/sdk_examples/src/v1/core_features/claiming/06_verify_presentation.ts new file mode 100644 index 000000000..2c2662bbf --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/claiming/06_verify_presentation.ts @@ -0,0 +1,25 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function verifyPresentation( + presentation: Kilt.ICredentialPresentation, + { + challenge, + trustedAttesterUris = [] + }: { + challenge?: string + trustedAttesterUris?: Kilt.DidUri[] + } = {} +): Promise { + // Verify the presentation with the provided challenge. + const { revoked, attester } = await Kilt.Credential.verifyPresentation( + presentation, + { challenge } + ) + + if (revoked) { + throw new Error("Credential has been revoked and hence it's not valid.") + } + if (!trustedAttesterUris.includes(attester)) { + throw `Credential was issued by ${attester} which is not in the provided list of trusted attesters: ${trustedAttesterUris}.` + } +} diff --git a/code_examples/sdk_examples/src/v1/core_features/claiming/07_revoke_credential.ts b/code_examples/sdk_examples/src/v1/core_features/claiming/07_revoke_credential.ts new file mode 100644 index 000000000..ee66732eb --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/claiming/07_revoke_credential.ts @@ -0,0 +1,29 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function revokeCredential( + attester: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + signCallback: Kilt.SignExtrinsicCallback, + credential: Kilt.ICredential, + shouldRemove = false +): Promise { + const api = Kilt.ConfigService.get('api') + + const tx = shouldRemove + ? // If the attestation is to be removed, create a `remove` tx, + // which revokes and removes the attestation in one go. + api.tx.attestation.remove(credential.rootHash, null) + : // Otherwise, simply revoke the attestation but leave it on chain. + // Hence, the storage is not cleared and the deposit not returned. + api.tx.attestation.revoke(credential.rootHash, null) + + const authorizedTx = await Kilt.Did.authorizeTx( + attester, + tx, + signCallback, + submitterAccount.address + ) + + // Submit the right tx to the KILT blockchain. + await Kilt.Blockchain.signAndSubmitTx(authorizedTx, submitterAccount) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/claiming/08_reclaim_attestation_deposit.ts b/code_examples/sdk_examples/src/v1/core_features/claiming/08_reclaim_attestation_deposit.ts new file mode 100644 index 000000000..7c808c9a8 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/claiming/08_reclaim_attestation_deposit.ts @@ -0,0 +1,16 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function reclaimAttestationDeposit( + submitterAddress: Kilt.KiltKeyringPair, + credential: Kilt.ICredential +): Promise { + const api = Kilt.ConfigService.get('api') + + // Generate the tx to claim the deposit back. + const depositReclaimTx = api.tx.attestation.reclaimDeposit( + credential.rootHash + ) + + // Submit the revocation tx to the KILT blockchain. + await Kilt.Blockchain.signAndSubmitTx(depositReclaimTx, submitterAddress) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/claiming/index.ts b/code_examples/sdk_examples/src/v1/core_features/claiming/index.ts new file mode 100644 index 000000000..344ba51ec --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/claiming/index.ts @@ -0,0 +1,104 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +import { createCompleteFullDid } from '../did/05_full_did_complete' +import { createSimpleLightDid } from '../did/01_light_did_simple' + +import { createAttestation } from './04_create_attestation' +import { createDriversLicenseCType } from './01_create_ctype' +import { createPresentation } from './05_create_presentation' +import { fetchCType } from './02_fetch_ctype' +import { reclaimAttestationDeposit } from './08_reclaim_attestation_deposit' +import { requestAttestation } from './03_request_attestation' +import { revokeCredential } from './07_revoke_credential' +import { verifyPresentation } from './06_verify_presentation' + +import { generateKeypairs } from '../utils/generateKeypairs' + +export async function runAll( + submitterAccount: Kilt.KiltKeyringPair +): Promise { + console.log('Running claiming flow...') + const claimerAuthKey = generateKeypairs().authentication + const claimerLightDid = createSimpleLightDid({ + authentication: claimerAuthKey as Kilt.NewLightDidVerificationKey + }) + + const attersterKeys = generateKeypairs() + const attesterFullDid = await createCompleteFullDid( + submitterAccount, + attersterKeys, + async ({ data }) => ({ + signature: attersterKeys.authentication.sign(data), + keyType: attersterKeys.authentication.type + }) + ) + + console.log('1 claming) Create CType') + const ctype = await createDriversLicenseCType( + attesterFullDid.uri, + submitterAccount, + async ({ data }) => ({ + signature: attersterKeys.assertionMethod.sign(data), + keyType: attersterKeys.assertionMethod.type + }) + ) + console.log('2 claiming) Fetch CType') + const ctypeDetails = await fetchCType(ctype.$id) + if (!ctypeDetails) { + throw new Error( + 'Could not retrieve CType details of a CType that was just created.' + ) + } + console.log('Retrieved CType details: ', ctypeDetails) + console.log('3 claiming) Create credential') + const credential = requestAttestation(claimerLightDid, ctype) + console.log('4 claiming) Create attestation and credential') + await createAttestation( + attesterFullDid.uri, + submitterAccount, + async ({ data }) => ({ + signature: attersterKeys.assertionMethod.sign(data), + keyType: attersterKeys.assertionMethod.type + }), + credential + ) + console.log('5 claiming) Create selective disclosure presentation') + const presentation = await createPresentation( + credential, + async ({ data }) => ({ + signature: claimerAuthKey.sign(data), + keyType: claimerAuthKey.type, + keyUri: `${claimerLightDid.uri}${claimerLightDid.authentication[0].id}` + }), + ['name', 'id'] + ) + console.log('6 claiming) Verify selective disclosure presentation') + await verifyPresentation(presentation, { + trustedAttesterUris: [attesterFullDid.uri] + }) + console.log('7.1 claiming) Revoke credential') + await revokeCredential( + attesterFullDid.uri, + submitterAccount, + async ({ data }) => ({ + signature: attersterKeys.assertionMethod.sign(data), + keyType: attersterKeys.assertionMethod.type + }), + credential, + false + ) + console.log( + '7.2 claiming) Presentation should fail to verify after revocation' + ) + try { + await verifyPresentation(presentation, { + trustedAttesterUris: [attesterFullDid.uri] + }) + throw new Error('Error: verification should fail after revocation') + // eslint-disable-next-line no-empty + } catch {} + console.log('8 claiming) Reclaim attestation deposit') + await reclaimAttestationDeposit(submitterAccount, credential) + + console.log('Claiming flow completed!') +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/00_generate_did_keys.ts b/code_examples/sdk_examples/src/v1/core_features/did/00_generate_did_keys.ts new file mode 100644 index 000000000..d2ace38cf --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/00_generate_did_keys.ts @@ -0,0 +1,27 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +import { mnemonicGenerate } from '@polkadot/util-crypto' + +export function generateKeypairs(mnemonic = mnemonicGenerate()): { + authentication: Kilt.KiltKeyringPair + keyAgreement: Kilt.KiltEncryptionKeypair + assertionMethod: Kilt.KiltKeyringPair + capabilityDelegation: Kilt.KiltKeyringPair +} { + const authentication = Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic) + + const assertionMethod = Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic) + + const capabilityDelegation = Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic) + + const keyAgreement = Kilt.Utils.Crypto.makeEncryptionKeypairFromSeed( + Kilt.Utils.Crypto.mnemonicToMiniSecret(mnemonic) + ) + + return { + authentication: authentication, + keyAgreement: keyAgreement, + assertionMethod: assertionMethod, + capabilityDelegation: capabilityDelegation + } +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/01_light_did_simple.ts b/code_examples/sdk_examples/src/v1/core_features/did/01_light_did_simple.ts new file mode 100644 index 000000000..280c08439 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/01_light_did_simple.ts @@ -0,0 +1,15 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export function createSimpleLightDid({ + authentication +}: { + authentication: Kilt.NewLightDidVerificationKey +}): Kilt.DidDocument { + // Create a light DID from the generated authentication key. + const lightDID = Kilt.Did.createLightDidDocument({ + authentication: [authentication] + }) + console.log(lightDID.uri) + + return lightDID +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/02_light_did_complete.ts b/code_examples/sdk_examples/src/v1/core_features/did/02_light_did_complete.ts new file mode 100644 index 000000000..978cfe079 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/02_light_did_complete.ts @@ -0,0 +1,28 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export function createCompleteLightDid({ + authentication, + keyAgreement +}: { + authentication: Kilt.NewLightDidVerificationKey + keyAgreement: Kilt.NewDidEncryptionKey +}): Kilt.DidDocument { + // Example service for the DID. + const service: Kilt.DidServiceEndpoint[] = [ + { + id: '#my-service', + type: ['KiltPublishedCredentialCollectionV1'], + serviceEndpoint: ['http://example.domain.org'] + } + ] + + // Create the KILT light DID with the information generated. + const lightDID = Kilt.Did.createLightDidDocument({ + authentication: [authentication], + keyAgreement: [keyAgreement], + service + }) + console.log(lightDID.uri) + + return lightDID +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/03_light_did_migrate.ts b/code_examples/sdk_examples/src/v1/core_features/did/03_light_did_migrate.ts new file mode 100644 index 000000000..4700128bc --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/03_light_did_migrate.ts @@ -0,0 +1,26 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function migrateLightDid( + lightDid: Kilt.DidDocument, + submitterAccount: Kilt.KiltKeyringPair, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + // Generate the DID migration tx. + const migrationTx = await Kilt.Did.getStoreTx( + lightDid, + submitterAccount.address, + signCallback + ) + + // The tx can then be submitted by the authorized account as usual. + await Kilt.Blockchain.signAndSubmitTx(migrationTx, submitterAccount) + + // The new information is fetched from the blockchain and returned. + const migratedFullDidUri = Kilt.Did.getFullDidUri(lightDid.uri) + const encodedUpdatedDidDetails = await api.call.did.query( + Kilt.Did.toChain(migratedFullDidUri) + ) + return Kilt.Did.linkedInfoFromChain(encodedUpdatedDidDetails).document +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/04_full_did_simple.ts b/code_examples/sdk_examples/src/v1/core_features/did/04_full_did_simple.ts new file mode 100644 index 000000000..ebff33220 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/04_full_did_simple.ts @@ -0,0 +1,33 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function createSimpleFullDid( + submitterAccount: Kilt.KiltKeyringPair, + { + authentication + }: { + authentication: Kilt.NewDidVerificationKey + }, + signCallback: Kilt.Did.GetStoreTxSignCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + // Generate the DID-signed creation tx and submit it to the blockchain with the specified account. + // The submitter account parameter, ensures that only an entity authorized by the DID subject + // can submit the tx to the KILT blockchain. + const fullDidCreationTx = await Kilt.Did.getStoreTx( + { + authentication: [authentication] + }, + submitterAccount.address, + signCallback + ) + + await Kilt.Blockchain.signAndSubmitTx(fullDidCreationTx, submitterAccount) + + // The new information is fetched from the blockchain and returned. + const fullDid = Kilt.Did.getFullDidUriFromKey(authentication) + const encodedUpdatedDidDetails = await api.call.did.query( + Kilt.Did.toChain(fullDid) + ) + return Kilt.Did.linkedInfoFromChain(encodedUpdatedDidDetails).document +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/05_full_did_complete.ts b/code_examples/sdk_examples/src/v1/core_features/did/05_full_did_complete.ts new file mode 100644 index 000000000..fb2edebce --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/05_full_did_complete.ts @@ -0,0 +1,47 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function createCompleteFullDid( + submitterAccount: Kilt.KiltKeyringPair, + { + authentication, + keyAgreement, + assertionMethod, + capabilityDelegation + }: { + authentication: Kilt.NewDidVerificationKey + keyAgreement: Kilt.NewDidEncryptionKey + assertionMethod: Kilt.NewDidVerificationKey + capabilityDelegation: Kilt.NewDidVerificationKey + }, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + const fullDidCreationTx = await Kilt.Did.getStoreTx( + { + authentication: [authentication], + keyAgreement: [keyAgreement], + assertionMethod: [assertionMethod], + capabilityDelegation: [capabilityDelegation], + // Example service. + service: [ + { + id: '#my-service', + type: ['service-type'], + serviceEndpoint: ['https://www.example.com'] + } + ] + }, + submitterAccount.address, + signCallback + ) + + await Kilt.Blockchain.signAndSubmitTx(fullDidCreationTx, submitterAccount) + + // The new information is fetched from the blockchain and returned. + const fullDid = Kilt.Did.getFullDidUriFromKey(authentication) + const encodedUpdatedDidDetails = await api.call.did.query( + Kilt.Did.toChain(fullDid) + ) + return Kilt.Did.linkedInfoFromChain(encodedUpdatedDidDetails).document +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/06_did_query.ts b/code_examples/sdk_examples/src/v1/core_features/did/06_did_query.ts new file mode 100644 index 000000000..0393afa3f --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/06_did_query.ts @@ -0,0 +1,16 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function queryFullDid( + didUri: Kilt.DidUri +): Promise { + const { metadata, document } = await Kilt.Did.resolve(didUri) + if (metadata.deactivated) { + console.log(`DID ${didUri} has been deleted.`) + return null + } else if (document === undefined) { + console.log(`DID ${didUri} does not exist.`) + return null + } else { + return document + } +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/07_full_did_update.ts b/code_examples/sdk_examples/src/v1/core_features/did/07_full_did_update.ts new file mode 100644 index 000000000..41ef49399 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/07_full_did_update.ts @@ -0,0 +1,46 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function updateFullDid( + newAuthKeypair: Kilt.KiltKeyringPair, + fullDid: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + // Create the tx to update the authentication key. + const didKeyUpdateTx = api.tx.did.setAuthenticationKey( + Kilt.Did.publicKeyToChain(newAuthKeypair) + ) + // Create the tx to remove the service with ID `#my-service`. + const didServiceRemoveTx = api.tx.did.removeServiceEndpoint( + Kilt.Did.resourceIdToChain('#my-service') + ) + + // Create the tx to add a new service with ID `#my-new-service`. + const newServiceEndpointTx = api.tx.did.addServiceEndpoint({ + id: Kilt.Did.resourceIdToChain('#my-new-service'), + serviceTypes: [Kilt.KiltPublishedCredentialCollectionV1Type], + urls: ['https://www.new-example.com'] + }) + + // Create and sign the DID operation that contains the two (unsigned) txs. + // This results in a DID-signed tx that can be then signed and submitted to the KILT blockchain by the account + // authorized in this operation, Alice in this case. + const authorizedBatchedTxs = await Kilt.Did.authorizeBatch({ + batchFunction: api.tx.utility.batchAll, + did: fullDid, + extrinsics: [didKeyUpdateTx, didServiceRemoveTx, newServiceEndpointTx], + sign: signCallback, + submitter: submitterAccount.address + }) + + // Submit the DID update tx to the KILT blockchain after signing it with the authorized KILT account. + await Kilt.Blockchain.signAndSubmitTx(authorizedBatchedTxs, submitterAccount) + + // Get the updated DID Document. + const encodedUpdatedDidDetails = await api.call.did.query( + Kilt.Did.toChain(fullDid) + ) + return Kilt.Did.linkedInfoFromChain(encodedUpdatedDidDetails).document +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/08_full_did_batch.ts b/code_examples/sdk_examples/src/v1/core_features/did/08_full_did_batch.ts new file mode 100644 index 000000000..291bb1ed4 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/08_full_did_batch.ts @@ -0,0 +1,27 @@ +import * as Kilt from '@kiltprotocol/sdk-js' +// Just a helper to get an extrinsic +import getExtrinsic from '../utils/getExtrinsic' + +export async function signAndSubmitDidExtrinsicBatch( + submitterAccount: Kilt.KiltKeyringPair, + fullDid: Kilt.DidUri, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + // Build two extrinsics + const extrinsic1 = getExtrinsic() + const extrinsic2 = getExtrinsic() + + // Create the DID-signed batch. + const authorizedBatch = await Kilt.Did.authorizeBatch({ + batchFunction: api.tx.utility.batchAll, + did: fullDid, + extrinsics: [extrinsic1, extrinsic2], + sign: signCallback, + submitter: submitterAccount.address + }) + + // Wrap the DID extrinsic in an account extrinsic. + await Kilt.Blockchain.signAndSubmitTx(authorizedBatch, submitterAccount) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/09_full_did_tx.ts b/code_examples/sdk_examples/src/v1/core_features/did/09_full_did_tx.ts new file mode 100644 index 000000000..f88f032e3 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/09_full_did_tx.ts @@ -0,0 +1,23 @@ +import * as Kilt from '@kiltprotocol/sdk-js' +// Just a helper to get an extrinsic +import getExtrinsic from '../utils/getExtrinsic' + +export async function signAndSubmitDidExtrinsic( + submitterAccount: Kilt.KiltKeyringPair, + fullDid: Kilt.DidUri, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const extrinsic = getExtrinsic() + + // This results in a DID-signed tx that can be signed and submitted to + // the KILT blockchain by the account authorized in this operation (the `submitterAccount`). + const didSignedExtrinsic = await Kilt.Did.authorizeTx( + fullDid, + extrinsic, + signCallback, + submitterAccount.address + ) + + // Wrap the DID extrinsic in an account extrinsic. + await Kilt.Blockchain.signAndSubmitTx(didSignedExtrinsic, submitterAccount) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/10_did_signature.ts b/code_examples/sdk_examples/src/v1/core_features/did/10_did_signature.ts new file mode 100644 index 000000000..480687f5f --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/10_did_signature.ts @@ -0,0 +1,38 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +type KeyLookup = (parameter: { + didUri: Kilt.DidUri + keyRelationship: Kilt.VerificationKeyRelationship +}) => Promise<{ + key: Kilt.KiltKeyringPair + keyType: Kilt.VerificationKeyType + keyUri: Kilt.DidResourceUri +}> + +export async function generateAndVerifyDidAuthenticationSignature( + did: Kilt.DidDocument, + payload: Uint8Array, + keyLookup: KeyLookup +): Promise { + // How the key is looked up depends on where the key is stored (e.g. memory, hardware wallet, browser extension) + const { key, keyUri } = await keyLookup({ + didUri: did.uri, + keyRelationship: 'authentication' + }) + + // Generate a signature using the key that we just looked up. + const signature = key.sign(payload) + + // Print the generated signature object. + console.log('Generated signature:') + console.log(Kilt.Utils.Crypto.u8aToHex(signature)) + + // Verify the validity of the signature using the DID's authentication public key. + // It throws if the signature cannot be verified. + await Kilt.Did.verifyDidSignature({ + message: payload, + signature, + keyUri, + expectedVerificationMethod: 'authentication' + }) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/11_full_did_delete.ts b/code_examples/sdk_examples/src/v1/core_features/did/11_full_did_delete.ts new file mode 100644 index 000000000..30adef4ed --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/11_full_did_delete.ts @@ -0,0 +1,31 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function deleteFullDid( + submitterAccount: Kilt.KiltKeyringPair, + fullDid: Kilt.DidUri, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + // Create a DID deletion tx. We specify the number of endpoints currently stored under the DID because + // of the upper computation limit required by the blockchain runtime. + const didIdentifier = Kilt.Did.toChain(fullDid) + const endpointsCountForDid = + await api.query.did.didEndpointsCount(didIdentifier) + const didDeletionExtrinsic = api.tx.did.delete(endpointsCountForDid) + + // Sign the DID deletion tx using the DID authentication key. + // This results in a DID-signed tx that can be then signed and submitted to the KILT blockchain by the account + // authorized in this operation, Alice in this case. + const didSignedDeletionExtrinsic = await Kilt.Did.authorizeTx( + fullDid, + didDeletionExtrinsic, + signCallback, + submitterAccount.address + ) + + await Kilt.Blockchain.signAndSubmitTx( + didSignedDeletionExtrinsic, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/12_did_export.ts b/code_examples/sdk_examples/src/v1/core_features/did/12_did_export.ts new file mode 100644 index 000000000..6ed26c5e5 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/12_did_export.ts @@ -0,0 +1,28 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function exportDid( + did: Kilt.DidDocument, + exportType: 'application/json' | 'application/ld+json' +) { + const conformingDidDocument = Kilt.Did.exportToDidDocument(did, exportType) + + // Will print the DID URI. + console.log(conformingDidDocument.id) + + // Will print all the public keys associated with the DID. + console.log(conformingDidDocument.verificationMethod) + + // Will print all the assertion keys IDs. + console.log(conformingDidDocument.assertionMethod) + + // Will print all the encryption keys IDs. + console.log(conformingDidDocument.keyAgreement) + + // Will print all the delegation keys IDs. + console.log(conformingDidDocument.capabilityDelegation) + + // Will print all the external services referenced inside the `DidDocument` instance. + console.log(conformingDidDocument.service) + + return conformingDidDocument +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/13_full_did_deposit_reclaim.ts b/code_examples/sdk_examples/src/v1/core_features/did/13_full_did_deposit_reclaim.ts new file mode 100644 index 000000000..b9b481b35 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/13_full_did_deposit_reclaim.ts @@ -0,0 +1,21 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function reclaimFullDidDeposit( + submitterAddress: Kilt.KiltKeyringPair, + fullDid: Kilt.DidUri +): Promise { + const api = Kilt.ConfigService.get('api') + + // Generate the tx to claim the deposit back. + // It includes the DID identifier for which the deposit needs to be returned + // and the count of services to provide an upper bound to the computation of the tx execution. + const identifier = Kilt.Did.toChain(fullDid) + const endpointsCountForDid = await api.query.did.didEndpointsCount(identifier) + const depositClaimExtrinsic = api.tx.did.reclaimDeposit( + identifier, + endpointsCountForDid + ) + + // The submission will fail if `submitterAddress` is not the owner of the deposit associated with the given DID identifier. + await Kilt.Blockchain.signAndSubmitTx(depositClaimExtrinsic, submitterAddress) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/did/index.ts b/code_examples/sdk_examples/src/v1/core_features/did/index.ts new file mode 100644 index 000000000..3ab486625 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/did/index.ts @@ -0,0 +1,141 @@ +import { stringToU8a } from '@polkadot/util' + +import * as Kilt from '@kiltprotocol/sdk-js' + +import { createCompleteFullDid } from './05_full_did_complete' +import { createCompleteLightDid } from './02_light_did_complete' +import { createSimpleFullDid } from './04_full_did_simple' +import { createSimpleLightDid } from './01_light_did_simple' +import { deleteFullDid } from './11_full_did_delete' +import { exportDid } from './12_did_export' +import { generateAndVerifyDidAuthenticationSignature } from './10_did_signature' +import { migrateLightDid } from './03_light_did_migrate' +import { queryFullDid } from './06_did_query' +import { reclaimFullDidDeposit } from './13_full_did_deposit_reclaim' +import { signAndSubmitDidExtrinsic } from './09_full_did_tx' +import { signAndSubmitDidExtrinsicBatch } from './08_full_did_batch' +import { updateFullDid } from './07_full_did_update' + +import { generateKeypairs } from '../utils/generateKeypairs' + +export async function runAll( + submitterAccount: Kilt.KiltKeyringPair +): Promise { + console.log('Running DID flow...') + + console.log('1 did) Create simple light DID') + const { authentication: simpleLightDidAuth } = generateKeypairs() + const simpleLightDid = createSimpleLightDid({ + authentication: simpleLightDidAuth as Kilt.NewLightDidVerificationKey + }) + console.log('2 did) Create complete light DID') + const { + authentication: completeLightDidAuth, + keyAgreement: completeLightDidEnc + } = generateKeypairs() + createCompleteLightDid({ + authentication: completeLightDidAuth as Kilt.NewLightDidVerificationKey, + keyAgreement: completeLightDidEnc + }) + console.log('3 did) Migrate first light DID to full DID') + await migrateLightDid(simpleLightDid, submitterAccount, async ({ data }) => ({ + signature: simpleLightDidAuth.sign(data), + keyType: simpleLightDidAuth.type + })) + console.log('4 did) Create simple full DID') + const { authentication: simpleFullDidAuth } = generateKeypairs() + const createdSimpleFullDid = await createSimpleFullDid( + submitterAccount, + { + authentication: simpleFullDidAuth + }, + async ({ data }) => ({ + signature: simpleFullDidAuth.sign(data), + keyType: simpleFullDidAuth.type + }) + ) + console.log('5 did) Create complete full DID') + const { + authentication: completeFullDidAuth, + keyAgreement: completeFullDidEnc, + assertionMethod: completeFullDidAtt, + capabilityDelegation: completeFullDidDel + } = generateKeypairs() + const createdCompleteFullDid = await createCompleteFullDid( + submitterAccount, + { + authentication: completeFullDidAuth, + keyAgreement: completeFullDidEnc, + assertionMethod: completeFullDidAtt, + capabilityDelegation: completeFullDidDel + }, + async ({ data }) => ({ + signature: completeFullDidAuth.sign(data), + keyType: completeFullDidAuth.type + }) + ) + console.log('6 did) Query full DID') + queryFullDid(createdCompleteFullDid.uri) + + console.log('7 did) Update full DID created at step 5') + const { authentication: newCompleteFullDidAuth } = generateKeypairs() + const updatedFullDid = await updateFullDid( + newCompleteFullDidAuth, + createdCompleteFullDid.uri, + submitterAccount, + async ({ data }) => ({ + signature: completeFullDidAuth.sign(data), + keyType: completeFullDidAuth.type + }) + ) + console.log( + '8.1 did) Use the same full DID created at step 5 to sign the batch' + ) + await signAndSubmitDidExtrinsicBatch( + submitterAccount, + updatedFullDid.uri, + async ({ data }) => ({ + signature: completeFullDidAtt.sign(data), + keyType: completeFullDidAtt.type + }) + ) + + console.log( + '8.2 did) Use the same full DID created at step 5 to sign the single tx' + ) + await signAndSubmitDidExtrinsic( + submitterAccount, + updatedFullDid.uri, + async ({ data }) => ({ + signature: completeFullDidAtt.sign(data), + keyType: completeFullDidAtt.type + }) + ) + + console.log( + '9 did) Use the same full DID created at step 5 to generate the signature' + ) + await generateAndVerifyDidAuthenticationSignature( + updatedFullDid, + stringToU8a('test-payload'), + async () => ({ + key: newCompleteFullDidAuth, + keyType: newCompleteFullDidAuth.type, + keyUri: `${updatedFullDid.uri}${updatedFullDid.authentication[0].id}` + }) + ) + console.log('10 did) Delete full DID created at step 4') + await deleteFullDid( + submitterAccount, + createdSimpleFullDid.uri, + async ({ data }) => ({ + signature: simpleFullDidAuth.sign(data), + keyType: simpleFullDidAuth.type + }) + ) + console.log('11 did) Export DID created at step 5') + await exportDid(createdCompleteFullDid, 'application/ld+json') + console.log('12 did) Delete full DID created at step 5') + await reclaimFullDidDeposit(submitterAccount, createdCompleteFullDid.uri) + console.log('DID flow completed!') +} diff --git a/code_examples/sdk_examples/src/v1/core_features/getting_started/01_print_hello_world.ts b/code_examples/sdk_examples/src/v1/core_features/getting_started/01_print_hello_world.ts new file mode 100644 index 000000000..2108c6153 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/getting_started/01_print_hello_world.ts @@ -0,0 +1,3 @@ +export async function main() { + console.log('Hello, world!') +} diff --git a/code_examples/sdk_examples/src/v1/core_features/getting_started/02_connect_pere.ts b/code_examples/sdk_examples/src/v1/core_features/getting_started/02_connect_pere.ts new file mode 100644 index 000000000..ad266b54f --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/getting_started/02_connect_pere.ts @@ -0,0 +1,10 @@ +/* eslint-disable prefer-const */ +import type { ApiPromise } from '@polkadot/api' + +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function main(): Promise { + let api = await Kilt.connect('wss://peregrine.kilt.io/') + + return api +} diff --git a/code_examples/sdk_examples/src/v1/core_features/getting_started/02_connect_spirit.ts b/code_examples/sdk_examples/src/v1/core_features/getting_started/02_connect_spirit.ts new file mode 100644 index 000000000..b78c70a2e --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/getting_started/02_connect_spirit.ts @@ -0,0 +1,10 @@ +/* eslint-disable prefer-const */ +import type { ApiPromise } from '@polkadot/api' + +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function main(): Promise { + let api = await Kilt.connect('wss://spiritnet.kilt.io/') + + return api +} diff --git a/code_examples/sdk_examples/src/v1/core_features/getting_started/03_fetch_did.ts b/code_examples/sdk_examples/src/v1/core_features/getting_started/03_fetch_did.ts new file mode 100644 index 000000000..32d6d99fa --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/getting_started/03_fetch_did.ts @@ -0,0 +1,16 @@ +/* eslint-disable prefer-const */ +import * as Kilt from '@kiltprotocol/sdk-js' +import * as Did from '@kiltprotocol/did' + +export async function main(): Promise { + let apiConfig = Kilt.ConfigService.get('api') + const encodedKiltnerd123Details = + await apiConfig.call.did.queryByWeb3Name('kiltnerd123') + + const { + document: { id } + } = Did.linkedInfoFromChain(encodedKiltnerd123Details) + console.log(`My name is kiltnerd123 and this is my DID: "${id}"`) + + return id +} diff --git a/code_examples/sdk_examples/src/v1/core_features/getting_started/04_fetch_endpoints.ts b/code_examples/sdk_examples/src/v1/core_features/getting_started/04_fetch_endpoints.ts new file mode 100644 index 000000000..e7b5414af --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/getting_started/04_fetch_endpoints.ts @@ -0,0 +1,18 @@ +import * as Kilt from '@kiltprotocol/sdk-js' +import {Did} from "@kiltprotocol/types" + +export async function main(id: Did): Promise { + const kiltnerd123DidDocument = await Kilt.DidResolver.resolve(id) + console.log(`kiltnerd123's DID Document:`) + console.log(JSON.stringify(kiltnerd123DidDocument, null, 2)) + + const endpoints = kiltnerd123DidDocument?.didDocument?.service + if (!endpoints) { + console.log('No endpoints for the DID.') + return [] + } + console.log('Endpoints:') + console.log(JSON.stringify(endpoints, null, 2)) + + return endpoints +} diff --git a/code_examples/sdk_examples/src/v1/core_features/getting_started/05_fetch_endpoint_data.ts b/code_examples/sdk_examples/src/v1/core_features/getting_started/05_fetch_endpoint_data.ts new file mode 100644 index 000000000..c55f7f195 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/getting_started/05_fetch_endpoint_data.ts @@ -0,0 +1,14 @@ +import axios from 'axios' + +import * as Kilt from '@kiltprotocol/sdk-js' +import { types } from '@kiltprotocol/credentials' + +export async function main( + endpoints: types.DidUrl[] +): Promise { + const { data: credential } = await axios.get( + endpoints[0].serviceEndpoint[0] + ) + console.log(`Credentials: ${JSON.stringify(credential, null, 2)}`) + return credential +} diff --git a/code_examples/sdk_examples/src/v1/core_features/getting_started/06_verify_credential.ts b/code_examples/sdk_examples/src/v1/core_features/getting_started/06_verify_credential.ts new file mode 100644 index 000000000..2c6573825 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/getting_started/06_verify_credential.ts @@ -0,0 +1,16 @@ +import * as Kilt from '@kiltprotocol/sdk-js' +import { VerifiableCredential } from '@kiltprotocol/credentials/lib/cjs/V1/types' + +export async function main(credential: VerifiableCredential): Promise { + try { + const result = await Kilt.Verifier.verifyCredential({ credential }) + console.log(JSON.stringify(result, null, 2)) + if (result.verified == false) { + throw new Error("kiltnerd123's credential is not valid.") + } else { + console.log(`kiltnerd123's credential is valid`) + } + } catch { + console.log("kiltnerd123's credential is not valid.") + } +} diff --git a/code_examples/sdk_examples/src/v1/core_features/getting_started/07_disconnect.ts b/code_examples/sdk_examples/src/v1/core_features/getting_started/07_disconnect.ts new file mode 100644 index 000000000..1fdebc2be --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/getting_started/07_disconnect.ts @@ -0,0 +1,5 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function main(): Promise { + await Kilt.disconnect() +} diff --git a/code_examples/sdk_examples/src/v1/core_features/getting_started/index.ts b/code_examples/sdk_examples/src/v1/core_features/getting_started/index.ts new file mode 100644 index 000000000..f306b6d59 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/getting_started/index.ts @@ -0,0 +1,41 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +import { main as connectToPeregrine } from './02_connect_pere' +import { main as disconnect } from './07_disconnect' +import { main as fetchEndpointData } from './05_fetch_endpoint_data' +import { main as fetchkiltnerd123Did } from './03_fetch_did' +import { main as fetchkiltnerd123Endpoints } from './04_fetch_endpoints' +import { main as printHelloWorld } from './01_print_hello_world' +import { main as verifyCredential } from './06_verify_credential' + +async function fetchDidAndCredential() { + const kiltnerd123Did = await fetchkiltnerd123Did() + if (!kiltnerd123Did) + throw new Error('"kiltnerd123" is not associated to any DID on Spiritnet') + const endpoints = await fetchkiltnerd123Endpoints(kiltnerd123Did) + if (!endpoints || !endpoints.length) + throw new Error(`DID doesn't include services`) + + let credential: Kilt.ICredential + try { + // FIXME: Occasionally there is a timeout error, because the endpoint uses the official ipfs gateway. + // Fix it by using a reliable endpoint. + // For now simply disconnect and return (i.e., ignore this error). + credential = await fetchEndpointData(endpoints) + } catch (error) { + console.error('Error while fetching IPFS', error) + return + } + await verifyCredential(credential) +} + +export async function runAll(): Promise { + await printHelloWorld() + + await connectToPeregrine() + try { + await fetchDidAndCredential() + } finally { + await disconnect() + } +} diff --git a/code_examples/sdk_examples/src/v1/core_features/index.ts b/code_examples/sdk_examples/src/v1/core_features/index.ts new file mode 100644 index 000000000..81f1ed958 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/index.ts @@ -0,0 +1,134 @@ +import { BN } from '@polkadot/util' +import { randomAsU8a } from '@polkadot/util-crypto' + +import * as Kilt from '@kiltprotocol/sdk-js' + +import { endowAccounts } from '../getFunds' +import { runAll as runAllClaiming } from './claiming' +import { runAll as runAllDid } from './did' +import { runAll as runAllGettingStarted } from './getting_started' +import { runAll as runAllLinking } from './linking' +import { runAll as runAllMessaging } from './messaging' +import { runAll as runAllPublicCredentials } from './public_credentials' +import { runAll as runAllSignCallback } from './signCallback' +import { runAll as runAllWeb3 } from './web3names' + +const resolveOn: Kilt.SubscriptionPromise.ResultEvaluator = + Kilt.Blockchain.IS_IN_BLOCK + +export async function testCoreFeatures( + account: Kilt.KeyringPair, + wssAddress: string +): Promise { + // Connects to (and at the end disconnects from) Spiritnet, so it must be called before we connect to Peregrine for the rest of the tests. + const gettingStartedFlow = async () => { + console.log('Running getting started flow...') + await runAllGettingStarted() + console.log('Getting started flow completed!') + } + await gettingStartedFlow() + + Kilt.ConfigService.set({ submitTxResolveOn: resolveOn }) + await Kilt.connect(wssAddress) + + const keyring = new Kilt.Utils.Keyring({ + ss58Format: Kilt.Utils.ss58Format + }) + + const [ + claimingTestAccount, + didTestAccount, + web3TestAccount, + accountLinkingTestAccount, + publicCredentialsTestAccount, + messagingAccount + ] = Array(6) + .fill(0) + .map( + () => + keyring.addFromSeed( + randomAsU8a(32), + undefined, + 'ed25519' + ) as Kilt.KiltKeyringPair & { type: 'ed25519' } + ) + + // Endow all the needed accounts in one batch transfer, to avoid tx collisions. + await endowAccounts( + account, + [ + claimingTestAccount.address, + didTestAccount.address, + web3TestAccount.address, + accountLinkingTestAccount.address, + publicCredentialsTestAccount.address, + messagingAccount.address + ], + new BN(10) + ) + + // These should not conflict anymore since all accounts are different. + await Promise.all([ + (async () => { + try { + await runAllClaiming(claimingTestAccount) + } catch (e) { + console.error('Claiming flow failed') + throw e + } + })(), + (async () => { + try { + await runAllDid(didTestAccount) + } catch (e) { + console.error('DID flow failed') + throw e + } + })(), + (async () => { + try { + await runAllWeb3(web3TestAccount) + } catch (e) { + console.error('Web3name flow failed') + throw e + } + })(), + (async () => { + try { + await runAllLinking( + keyring, + wssAddress, + account as Kilt.KiltKeyringPair, + accountLinkingTestAccount + ) + } catch (e) { + console.error('Linking flow failed') + throw e + } + })(), + (async () => { + try { + await runAllSignCallback() + } catch (e) { + console.error('SignCallback flow failed') + throw e + } + })(), + (async () => { + try { + await runAllPublicCredentials(publicCredentialsTestAccount) + } catch (e) { + console.error('Public credentials flow failed') + throw e + } + })(), + (async () => { + try { + await runAllMessaging(messagingAccount) + } catch (e) { + console.error('Messaging flow failed') + throw e + } + })() + ]) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/linking/01_eth_link.ts b/code_examples/sdk_examples/src/v1/core_features/linking/01_eth_link.ts new file mode 100644 index 000000000..663e9c292 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/linking/01_eth_link.ts @@ -0,0 +1,41 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function linkAccountToDid( + did: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + linkedAccount: Kilt.KeyringPair & { type: 'ethereum' }, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + // Generate the parameters for the extrinsic that links account and DID. + // This will contain the signature of the account that will be linked to the DID + // and therefore signals the agreement of the account to be linked. + const accountLinkingParameters = await Kilt.Did.associateAccountToChainArgs( + linkedAccount.address, + did, + async (payload) => linkedAccount.sign(payload) + ) + + // Afterwards we build the extrinsic using the parameters from above. + const accountLinkingTx = await api.tx.didLookup.associateAccount( + ...accountLinkingParameters + ) + + // Next the DID signs the extrinsic. + // This signals the agreement of the DID owner to be linked to the account. + const authorizedAccountLinkingTx = await Kilt.Did.authorizeTx( + did, + accountLinkingTx, + signCallback, + submitterAccount.address + ) + + // finally we need to submit everything to the blockchain, so that the link gets + // registered. + // This account will provide the required deposit and pay the fees. + await Kilt.Blockchain.signAndSubmitTx( + authorizedAccountLinkingTx, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/linking/01_eth_link_metamask.ts b/code_examples/sdk_examples/src/v1/core_features/linking/01_eth_link_metamask.ts new file mode 100644 index 000000000..ee20d2493 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/linking/01_eth_link_metamask.ts @@ -0,0 +1,65 @@ +import { hexToU8a, u8aToString } from '@polkadot/util' + +import * as Kilt from '@kiltprotocol/sdk-js' + +type MetamaskApi = { + request: (_: { + method: string + params: [string, string, string] + }) => Promise +} + +declare global { + interface Window { + ethereum: MetamaskApi + } +} + +export async function linkAccountToDid( + did: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + linkedAccountAddress: string, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + const blockNo = await api.query.system.number() + // the challenge will be valid for 300 blocks (~1h) + const validTill = blockNo.addn(300) + + // We build the challenge that needs to be signed by the ethereum account + const challenge = u8aToString( + await Kilt.Did.getLinkingChallenge(did, validTill) + ) + + // sign the challenge + const signature = await window.ethereum.request({ + method: 'personal_sign', + params: [challenge, linkedAccountAddress, ''] + }) + + // build the arguments for the extrinsic that links ethereum account and DID + const accountLinkingParameters = await Kilt.Did.getLinkingArguments( + linkedAccountAddress, + validTill, + hexToU8a(signature), + 'ethereum' + ) + + // Build the actual extrinsic + const accountLinkingTx = await api.tx.didLookup.associateAccount( + ...accountLinkingParameters + ) + const authorizedAccountLinkingTx = await Kilt.Did.authorizeTx( + did, + accountLinkingTx, + signCallback, + submitterAccount.address + ) + + // sign and submit the extrinsic to the blockchain + await Kilt.Blockchain.signAndSubmitTx( + authorizedAccountLinkingTx, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/linking/01_eth_link_web3js.ts b/code_examples/sdk_examples/src/v1/core_features/linking/01_eth_link_web3js.ts new file mode 100644 index 000000000..ffa5d0bb9 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/linking/01_eth_link_web3js.ts @@ -0,0 +1,55 @@ +import { hexToU8a, u8aToString } from '@polkadot/util' +import Web3 from 'web3' + +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function linkAccountToDid( + did: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + linkedAccountPrivateKey: string, + linkedAccountAddress: string, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + const web3 = new Web3() + + const blockNo = await api.query.system.number() + // the challenge will be valid for 300 blocks (~1h) + const validTill = blockNo.addn(300) + + // We build the challenge that needs to be signed by the ethereum account + const challenge = u8aToString( + await Kilt.Did.getLinkingChallenge(did, validTill) + ) + + // sign the challenge + const signResult = await web3.eth.accounts.sign( + challenge, + linkedAccountPrivateKey + ) + + // build the arguments for the extrinsic that links ethereum account and DID + const accountLinkingParameters = await Kilt.Did.getLinkingArguments( + linkedAccountAddress, + validTill, + hexToU8a(signResult.signature), + 'ethereum' + ) + + // Build the actual extrinsic + const accountLinkingTx = await api.tx.didLookup.associateAccount( + ...accountLinkingParameters + ) + const authorizedAccountLinkingTx = await Kilt.Did.authorizeTx( + did, + accountLinkingTx, + signCallback, + submitterAccount.address + ) + + // sign and submit the extrinsic to the blockchain + await Kilt.Blockchain.signAndSubmitTx( + authorizedAccountLinkingTx, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/linking/01_sub_link.ts b/code_examples/sdk_examples/src/v1/core_features/linking/01_sub_link.ts new file mode 100644 index 000000000..4b5340962 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/linking/01_sub_link.ts @@ -0,0 +1,41 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function linkAccountToDid( + did: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + linkedAccount: Kilt.KeyringPair & { type: 'ed25519' | 'sr25519' | 'ecdsa' }, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + // Generate the parameters for the extrinsic that links account and DID. + // This will contain the signature of the account that will be linked to the DID + // and therefore signals the agreement of the account to be linked. + const accountLinkingParameters = await Kilt.Did.associateAccountToChainArgs( + linkedAccount.address, + did, + async (payload) => linkedAccount.sign(payload) + ) + + // Afterwards we build the extrinsic using the parameters from above. + const accountLinkingTx = await api.tx.didLookup.associateAccount( + ...accountLinkingParameters + ) + + // Next the DID signs the extrinsic. + // This signals the agreement of the DID owner to be linked to the account. + const authorizedAccountLinkingTx = await Kilt.Did.authorizeTx( + did, + accountLinkingTx, + signCallback, + submitterAccount.address + ) + + // finally we need to submit everything to the blockchain, so that the link gets + // registered. + // This account will provide the required deposit and pay the fees. + await Kilt.Blockchain.signAndSubmitTx( + authorizedAccountLinkingTx, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/linking/02_sender_link.ts b/code_examples/sdk_examples/src/v1/core_features/linking/02_sender_link.ts new file mode 100644 index 000000000..0bb5a12be --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/linking/02_sender_link.ts @@ -0,0 +1,24 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function linkDidToAccount( + did: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + // Authorizing the tx with the full DID and submitting it with the provided account + // results in the submitter's account being linked to the DID authorizing the operation. + const accountLinkingTx = api.tx.didLookup.associateSender() + const authorizedAccountLinkingTx = await Kilt.Did.authorizeTx( + did, + accountLinkingTx, + signCallback, + submitterAccount.address + ) + + await Kilt.Blockchain.signAndSubmitTx( + authorizedAccountLinkingTx, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/linking/03_account_web3name_query.ts b/code_examples/sdk_examples/src/v1/core_features/linking/03_account_web3name_query.ts new file mode 100644 index 000000000..5b200cbac --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/linking/03_account_web3name_query.ts @@ -0,0 +1,23 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function queryAccountWeb3Name( + lookupAccountAddress: Kilt.KiltAddress +): Promise { + const api = Kilt.ConfigService.get('api') + + const encodedLinkedDetails = await api.call.did.queryByAccount( + Kilt.Did.accountToChain(lookupAccountAddress) + ) + const { web3Name } = Kilt.Did.linkedInfoFromChain(encodedLinkedDetails) + if (web3Name) { + console.log( + `web3name for account "${lookupAccountAddress}" -> "${web3Name}"` + ) + } else { + console.log( + `Account "${lookupAccountAddress}" does not have a linked web3name.` + ) + } + + return web3Name +} diff --git a/code_examples/sdk_examples/src/v1/core_features/linking/04_account_web3name_query_no_sdk.ts b/code_examples/sdk_examples/src/v1/core_features/linking/04_account_web3name_query_no_sdk.ts new file mode 100644 index 000000000..f0c17dd7d --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/linking/04_account_web3name_query_no_sdk.ts @@ -0,0 +1,38 @@ +import type { KeyringPair } from '@polkadot/keyring/types' + +import { ApiPromise, WsProvider } from '@polkadot/api' + +// Import needed to provide KILT Typescript support to the api object. +import '@kiltprotocol/augment-api' +import { typesBundle } from '@kiltprotocol/type-definitions' + +export async function queryAccountWeb3Name( + endpoint: string, + lookupAccountAddress: KeyringPair['address'] +): Promise { + const api = await ApiPromise.create({ + provider: new WsProvider(endpoint), + typesBundle + }) + // Call to the KILT runtime API `did.queryByAccount` + const didDetails = await api.call.did.queryByAccount({ + AccountId32: lookupAccountAddress + }) + if (didDetails.isNone) { + throw new Error(`No DID for the KILT account "${lookupAccountAddress}".`) + } + + const { w3n } = didDetails.unwrap() + if (w3n.isNone) { + throw new Error( + `No web3name for the KILT account "${lookupAccountAddress}".` + ) + } + + const web3Name = w3n.unwrap().toHuman() + console.log( + `The provided account is identifiable by the following web3name: "w3n:${web3Name}"` + ) + + return web3Name +} diff --git a/code_examples/sdk_examples/src/v1/core_features/linking/05_did_unlink.ts b/code_examples/sdk_examples/src/v1/core_features/linking/05_did_unlink.ts new file mode 100644 index 000000000..652acb6a8 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/linking/05_did_unlink.ts @@ -0,0 +1,26 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function unlinkAccountFromDid( + did: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + linkedAccountAddress: Kilt.KiltAddress, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + // The DID owner removes the link between itself and the specified account. + const accountUnlinkTx = api.tx.didLookup.removeAccountAssociation({ + AccountId32: linkedAccountAddress + }) + const authorizedAccountUnlinkTx = await Kilt.Did.authorizeTx( + did, + accountUnlinkTx, + signCallback, + submitterAccount.address + ) + + await Kilt.Blockchain.signAndSubmitTx( + authorizedAccountUnlinkTx, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/linking/06_account_unlink.ts b/code_examples/sdk_examples/src/v1/core_features/linking/06_account_unlink.ts new file mode 100644 index 000000000..ddfa79636 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/linking/06_account_unlink.ts @@ -0,0 +1,12 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function unlinkDidFromAccount( + linkOwnerAccount: Kilt.KeyringPair +): Promise { + const api = Kilt.ConfigService.get('api') + + // The tx does not need to be authorized by a DID, but the submitter account removes its own link. + const accountUnlinkTx = api.tx.didLookup.removeSenderAssociation() + + await Kilt.Blockchain.signAndSubmitTx(accountUnlinkTx, linkOwnerAccount) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/linking/07_reclaim_deposit.ts b/code_examples/sdk_examples/src/v1/core_features/linking/07_reclaim_deposit.ts new file mode 100644 index 000000000..5dfd5f661 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/linking/07_reclaim_deposit.ts @@ -0,0 +1,15 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function reclaimLinkDeposit( + submitterAddress: Kilt.KeyringPair, + linkedAccountAddress: Kilt.KiltAddress +): Promise { + const api = Kilt.ConfigService.get('api') + + // The tx does not need to be authorized by a DID, but the deposit payer's account claims the deposit and removes the link. + const accountUnlinkTx = api.tx.didLookup.reclaimDeposit({ + AccountId32: linkedAccountAddress + }) + + await Kilt.Blockchain.signAndSubmitTx(accountUnlinkTx, submitterAddress) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/linking/index.ts b/code_examples/sdk_examples/src/v1/core_features/linking/index.ts new file mode 100644 index 000000000..b611b1182 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/linking/index.ts @@ -0,0 +1,143 @@ +import { randomAsU8a } from '@polkadot/util-crypto' + +import Web3 from 'web3' +const web3 = new Web3() + +import { randomUUID } from 'crypto' + +import * as Kilt from '@kiltprotocol/sdk-js' + +import { claimWeb3Name } from '../web3names/01_claim' +import { createSimpleFullDid } from '../did/04_full_did_simple' + +import { linkAccountToDid as linkEthAccountToDid } from './01_eth_link' +import { linkAccountToDid as linkEthAccountToDidWeb3js } from './01_eth_link_web3js' +import { linkDidToAccount as linkSenderToDid } from './02_sender_link' +import { linkAccountToDid as linkSubAccountToDid } from './01_sub_link' +import { queryAccountWeb3Name as queryAccountWithSdk } from './03_account_web3name_query' +import { queryAccountWeb3Name as queryAccountWithoutSdk } from './04_account_web3name_query_no_sdk' +import { reclaimLinkDeposit } from './07_reclaim_deposit' +import { unlinkAccountFromDid } from './05_did_unlink' +import { unlinkDidFromAccount } from './06_account_unlink' + +import { generateKeypairs } from '../utils/generateKeypairs' + +// The provided DID is assumed to have an associated web3name. +export async function runAll( + keyring: Kilt.Utils.Keyring, + endpoint: string, + submitterAccount: Kilt.KiltKeyringPair, + linkAccount: Kilt.KiltKeyringPair & { type: 'ed25519' | 'sr25519' | 'ecdsa' } +): Promise { + console.log('Running linking flow...') + const { authentication } = generateKeypairs() + const fullDid = await createSimpleFullDid( + submitterAccount, + { + authentication + }, + async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type + }) + ) + const randomWeb3Name = randomUUID().substring(0, 32) + await claimWeb3Name( + fullDid.uri, + submitterAccount, + randomWeb3Name, + async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type + }) + ) + + console.log('1.1 linking) Link link account to DID') + await linkSubAccountToDid( + fullDid.uri, + submitterAccount, + linkAccount, + async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type + }) + ) + + // Link eth address using polkadot-js + { + console.log('1.2.1 linking) Link eth account to DID (polkadot-js)') + const linkEthAccount = keyring.addFromSeed( + randomAsU8a(32), + undefined, + 'ethereum' + ) as Kilt.KeyringPair & { type: 'ethereum' } + await linkEthAccountToDid( + fullDid.uri, + submitterAccount, + linkEthAccount, + async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type + }) + ) + } + + // link eth address using web3js + { + console.log('1.2.2 linking) Link eth account to DID (web3js)') + const ethSecretKey = randomAsU8a(32) + const linkEthAddress = web3.eth.accounts.privateKeyToAccount( + Kilt.Utils.Crypto.u8aToHex(ethSecretKey) + ).address + + await linkEthAccountToDidWeb3js( + fullDid.uri, + submitterAccount, + Kilt.Utils.Crypto.u8aToHex(ethSecretKey), + linkEthAddress, + async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type + }) + ) + } + + console.log('2 linking) Link DID to submitter account') + await linkSenderToDid(fullDid.uri, submitterAccount, async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type + })) + console.log('3 linking) Query web3name for link account with SDK') + let web3Name = await queryAccountWithSdk(linkAccount.address) + if (!web3Name) { + throw new Error( + `The DID "${fullDid.uri}" is assumed to have a linked web3name, which it does not.` + ) + } + console.log('4 linking) Query web3name for submitter account without SDK') + web3Name = await queryAccountWithoutSdk(endpoint, submitterAccount.address) + if (!web3Name) { + throw new Error( + 'The retrieved web3name should have been the same as the one of the link account, which is not.' + ) + } + console.log('5 linking) Unlink link account from DID') + await unlinkAccountFromDid( + fullDid.uri, + submitterAccount, + linkAccount.address, + async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type + }) + ) + console.log('6 linking) Unlink submitter account from DID') + await unlinkDidFromAccount(submitterAccount) + console.log('7 linking) Re-add submitter account and claim deposit back') + await linkSenderToDid(fullDid.uri, submitterAccount, async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type + })) + await reclaimLinkDeposit(submitterAccount, submitterAccount.address) + console.log('Linking flow completed!') +} diff --git a/code_examples/sdk_examples/src/v1/core_features/messaging/01_generate_request_credential_message.ts b/code_examples/sdk_examples/src/v1/core_features/messaging/01_generate_request_credential_message.ts new file mode 100644 index 000000000..9aeb57738 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/messaging/01_generate_request_credential_message.ts @@ -0,0 +1,35 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function generateRequestCredentialMessage( + senderUri: Kilt.DidUri, + receiverUri: Kilt.DidUri, + cTypeHash: Kilt.CTypeHash +) { + // Creating a challenge to submit to the receiver + const challenge = Kilt.Utils.UUID.generate() + + // Sender uri is checked if it is a valid URI + Kilt.Did.validateUri(senderUri) + // Receiver uri is checked if it is a valid URI + Kilt.Did.validateUri(receiverUri) + + // The content of the 'request-credential' message + // It includes a CType that is being requested, this can be for attestation or verification + // The sender is the trusted attester in the scenario + const requestCredentialContent = { + cTypeHash: cTypeHash, + trustedAttesters: [senderUri] + } + + const messageBody: Kilt.IRequestCredential = { + type: 'request-credential', + content: { cTypes: [requestCredentialContent], challenge: challenge } + } + + // The message will throw an Error if invalid + const message = Kilt.Message.fromBody(messageBody, senderUri, receiverUri) + + console.log(`Generated message: ${JSON.stringify(message, null, 4)}`) + + return message +} diff --git a/code_examples/sdk_examples/src/v1/core_features/messaging/02_encrypt_message.ts b/code_examples/sdk_examples/src/v1/core_features/messaging/02_encrypt_message.ts new file mode 100644 index 000000000..f25639435 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/messaging/02_encrypt_message.ts @@ -0,0 +1,31 @@ +import * as Kilt from '@kiltprotocol/sdk-js' +import { useEncryptionCallback } from '../signCallback/useEncryptionCallback' + +export async function encryptMessage( + message: Kilt.IMessage, + senderUri: Kilt.DidUri, + receiverUri: Kilt.DidUri, + keyAgreement: Kilt.KiltEncryptionKeypair +): Promise { + const { document: senderDocument } = await Kilt.Did.resolve(senderUri) + + const { document: receiverDocument } = await Kilt.Did.resolve(receiverUri) + + const receiverKeyAgreementUri = + `${receiverUri}${receiverDocument.keyAgreement?.[0].id}` as Kilt.DidResourceUri + const senderKeyAgreeementUri = + `${senderUri}${senderDocument.keyAgreement?.[0].id}` as Kilt.DidResourceUri + // encrypt the message + const encryptedMessage = await Kilt.Message.encrypt( + message, + useEncryptionCallback({ + keyAgreement, + keyAgreementUri: senderKeyAgreeementUri + }), + receiverKeyAgreementUri + ) + + console.log(`Encrypted Message: ${JSON.stringify(encryptedMessage, null, 4)}`) + + return encryptedMessage +} diff --git a/code_examples/sdk_examples/src/v1/core_features/messaging/03_decrypt_message.ts b/code_examples/sdk_examples/src/v1/core_features/messaging/03_decrypt_message.ts new file mode 100644 index 000000000..47e0f907c --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/messaging/03_decrypt_message.ts @@ -0,0 +1,38 @@ +import * as Kilt from '@kiltprotocol/sdk-js' +import { useDecryptionCallback } from '../signCallback/useDecryptionCallback' + +export async function decryptMessage( + encryptedMessage: Kilt.IEncryptedMessage, + keyAgreement: Kilt.KiltEncryptionKeypair +): Promise { + // Decrypting the message to retrieve the content + const decryptedMessage = await Kilt.Message.decrypt( + encryptedMessage, + useDecryptionCallback(keyAgreement) + ) + + // Verifying this is a properly-formatted message + Kilt.Message.verify(decryptedMessage) + + console.log(`Decrypted Message: ${JSON.stringify(decryptedMessage, null, 4)}`) + + // Checking if the message type matches the expected checks + if (decryptedMessage.body.type !== 'request-credential') { + throw new Error('Not the correct body type') + } + + // Destructing the message to receive the cTypes array to see what credentials + // Are valid for the given request + const { cTypes } = decryptedMessage.body.content + + const { cTypeHash, trustedAttesters } = cTypes[0] + + // The receiver can check if they have a valid credential that matches the cTypeHash + console.log('The sent cType hash :', cTypeHash) + + // The trusted attesters is an array that includes the list of trusted entities + // The receiver can check if they have a given credential from the trusted list + console.log(`A list of trusted attesters DID :${trustedAttesters}`) + + return decryptedMessage +} diff --git a/code_examples/sdk_examples/src/v1/core_features/messaging/_replay_protection_01.ts b/code_examples/sdk_examples/src/v1/core_features/messaging/_replay_protection_01.ts new file mode 100644 index 000000000..a87e21a4f --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/messaging/_replay_protection_01.ts @@ -0,0 +1,6 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +export function main() { + const MAX_ACCEPTED_AGE = 60_000 // ms -> 1 minute + const MIN_ACCEPTED_AGE = -1_000 // allow for some imprecision in system time + const submissions = new Map() +} diff --git a/code_examples/sdk_examples/src/v1/core_features/messaging/_replay_protection_02.ts b/code_examples/sdk_examples/src/v1/core_features/messaging/_replay_protection_02.ts new file mode 100644 index 000000000..e305c48ab --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/messaging/_replay_protection_02.ts @@ -0,0 +1,24 @@ +import { blake2AsHex } from '@polkadot/util-crypto' + +import * as Kilt from '@kiltprotocol/sdk-js' + +export function main( + submissions: Map, + decrypted: Kilt.IMessage, + MIN_ACCEPTED_AGE: number, + MAX_ACCEPTED_AGE: number +) { + // Is messageId fresh and createdAt recent? + const messageId = + decrypted.messageId || blake2AsHex(JSON.stringify(decrypted)) + if ( + submissions.has(messageId) || + decrypted.createdAt < Date.now() - MAX_ACCEPTED_AGE || + decrypted.createdAt > Date.now() - MIN_ACCEPTED_AGE + ) { + // no -> reject message + } else { + submissions.set(messageId, decrypted.createdAt) + // yes -> accept & process message + } +} diff --git a/code_examples/sdk_examples/src/v1/core_features/messaging/_replay_protection_03.ts b/code_examples/sdk_examples/src/v1/core_features/messaging/_replay_protection_03.ts new file mode 100644 index 000000000..237a98de1 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/messaging/_replay_protection_03.ts @@ -0,0 +1,11 @@ +export function main( + submissions: Map, + MAX_ACCEPTED_AGE: number +) { + setInterval(() => { + const outdatedTimestamp = Date.now() - MAX_ACCEPTED_AGE + submissions.forEach((timestamp, hash) => { + if (timestamp < outdatedTimestamp) submissions.delete(hash) + }) + }, 1000) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/messaging/index.ts b/code_examples/sdk_examples/src/v1/core_features/messaging/index.ts new file mode 100644 index 000000000..f59b83d49 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/messaging/index.ts @@ -0,0 +1,71 @@ +import * as Kilt from '@kiltprotocol/sdk-js' +import { createCompleteFullDid } from '../did/05_full_did_complete' +import { createDriversLicenseCType } from '../claiming/01_create_ctype' +import { decryptMessage } from './03_decrypt_message' +import { encryptMessage } from './02_encrypt_message' +import { generateKeypairs } from '../utils/generateKeypairs' +import { generateRequestCredentialMessage } from './01_generate_request_credential_message' + +// Runs through the messaging encryption and decryption of messages +export async function runAll(submitterAccount: Kilt.KiltKeyringPair) { + console.log('Running messaging flow...') + console.log(`1 Messaging) Generating a sender's DID`) + const senderKeypairs = generateKeypairs() + const senderFullDid = await createCompleteFullDid( + submitterAccount, + { + ...senderKeypairs + }, + async ({ data }) => ({ + signature: senderKeypairs.authentication.sign(data), + keyType: senderKeypairs.authentication.type + }) + ) + + console.log(`2 Messaging) Generating a receiver's DID`) + const receiverKeypairs = generateKeypairs() + const receiverFullDid = await createCompleteFullDid( + submitterAccount, + { + ...receiverKeypairs + }, + async ({ data }) => ({ + signature: receiverKeypairs.authentication.sign(data), + keyType: receiverKeypairs.authentication.type + }) + ) + + console.log('3 Messaging) Generating a ctype for the message passing') + const { $id } = await createDriversLicenseCType( + senderFullDid.uri, + submitterAccount, + async ({ data }) => ({ + signature: senderKeypairs.assertionMethod.sign(data), + keyType: senderKeypairs.assertionMethod.type + }) + ) + + const cTypeHash = Kilt.CType.idToHash($id) + + console.log('4 Messaging) Generating the message to encrypt and decrypt') + const message = await generateRequestCredentialMessage( + senderFullDid.uri, + receiverFullDid.uri, + cTypeHash + ) + + console.log('5 Messaging) Encrypting the message for sender to receiver') + const encryptedMessage = await encryptMessage( + message, + senderFullDid.uri, + receiverFullDid.uri, + senderKeypairs.keyAgreement + ) + + console.log( + '6 Messaging) Decrypting the message from sender for the receiver' + ) + await decryptMessage(encryptedMessage, receiverKeypairs.keyAgreement) + + console.log('Messaging flow completed!') +} diff --git a/code_examples/sdk_examples/src/v1/core_features/public_credentials/01_create_credential.ts b/code_examples/sdk_examples/src/v1/core_features/public_credentials/01_create_credential.ts new file mode 100644 index 000000000..1120d23ca --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/public_credentials/01_create_credential.ts @@ -0,0 +1,38 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +// CType definition. +const ctype = Kilt.CType.fromProperties(`NFT Collection Certification CType`, { + name: { + type: 'string' + }, + pieces: { + type: 'integer' + }, + creationDate: { + type: 'string' + }, + artistIdentity: { + type: 'string' + } +}) + +export function createNftCollectionCredential( + assetDid: Kilt.AssetDidUri, + artistDid: Kilt.DidUri +): Kilt.IPublicCredentialInput { + const claimProperties: Kilt.IClaimContents = { + name: 'Awesome NFT drop', + // NFT collection only has 100 pieces in total + pieces: 100, + // NFT collection was released on Jan 1st, 2023 + creationDate: new Date(2023, 0, 1).toISOString(), + artistIdentity: artistDid + } + const fullClaim: Kilt.IAssetClaim = { + contents: claimProperties, + cTypeHash: Kilt.CType.idToHash(ctype.$id), + subject: assetDid + } + + return Kilt.PublicCredential.fromClaim(fullClaim) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/public_credentials/02_issue_credential.ts b/code_examples/sdk_examples/src/v1/core_features/public_credentials/02_issue_credential.ts new file mode 100644 index 000000000..1aff3faff --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/public_credentials/02_issue_credential.ts @@ -0,0 +1,26 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function issueCredential( + attester: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + signCallback: Kilt.SignExtrinsicCallback, + credential: Kilt.IPublicCredentialInput +): Promise { + const api = Kilt.ConfigService.get('api') + + const credentialCreationTx = api.tx.publicCredentials.add( + Kilt.PublicCredential.toChain(credential) + ) + + // Same as for traditional KILT credentials + const authorizedAttestationTx = await Kilt.Did.authorizeTx( + attester, + credentialCreationTx, + signCallback, + submitterAccount.address + ) + await Kilt.Blockchain.signAndSubmitTx( + authorizedAttestationTx, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/public_credentials/03_retrieve_credential_by_id.ts b/code_examples/sdk_examples/src/v1/core_features/public_credentials/03_retrieve_credential_by_id.ts new file mode 100644 index 000000000..fe3ceea40 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/public_credentials/03_retrieve_credential_by_id.ts @@ -0,0 +1,7 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function fetchCredentialById( + credentialId: Kilt.IPublicCredential['id'] +): Promise { + return Kilt.PublicCredential.fetchCredentialFromChain(credentialId) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/public_credentials/04_retrieve_credentials_by_subject.ts b/code_examples/sdk_examples/src/v1/core_features/public_credentials/04_retrieve_credentials_by_subject.ts new file mode 100644 index 000000000..13d729a37 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/public_credentials/04_retrieve_credentials_by_subject.ts @@ -0,0 +1,7 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function retrieveAllAssetCredentials( + assetDid: Kilt.AssetDidUri +): Promise { + return Kilt.PublicCredential.fetchCredentialsFromChain(assetDid) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/public_credentials/05_verify_credential.ts b/code_examples/sdk_examples/src/v1/core_features/public_credentials/05_verify_credential.ts new file mode 100644 index 000000000..4831f1ee9 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/public_credentials/05_verify_credential.ts @@ -0,0 +1,8 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function verifyCredential( + credential: Kilt.IPublicCredential, + cType?: Kilt.ICType +): Promise { + await Kilt.PublicCredential.verifyCredential(credential, { cType }) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/public_credentials/06_revoke_remove_credential_by_id.ts b/code_examples/sdk_examples/src/v1/core_features/public_credentials/06_revoke_remove_credential_by_id.ts new file mode 100644 index 000000000..ad6ad135c --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/public_credentials/06_revoke_remove_credential_by_id.ts @@ -0,0 +1,27 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function revokeCredentialById( + attester: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + signCallback: Kilt.SignExtrinsicCallback, + credentialId: Kilt.IPublicCredential['id'], + shouldRemove = false +): Promise { + const api = Kilt.ConfigService.get('api') + + const tx = shouldRemove + ? api.tx.publicCredentials.remove(credentialId, null) + : api.tx.publicCredentials.revoke(credentialId, null) + + // Same as for traditional KILT credentials + const authorizedAttestationTx = await Kilt.Did.authorizeTx( + attester, + tx, + signCallback, + submitterAccount.address + ) + await Kilt.Blockchain.signAndSubmitTx( + authorizedAttestationTx, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/public_credentials/07_revoke_remove_credential_by_content.ts b/code_examples/sdk_examples/src/v1/core_features/public_credentials/07_revoke_remove_credential_by_content.ts new file mode 100644 index 000000000..8c3c83ee1 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/public_credentials/07_revoke_remove_credential_by_content.ts @@ -0,0 +1,31 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function revokeCredential( + attester: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + signCallback: Kilt.SignExtrinsicCallback, + credential: Kilt.IPublicCredentialInput, + shouldRemove = false +): Promise { + const api = Kilt.ConfigService.get('api') + + const credentialId = Kilt.PublicCredential.getIdForCredential( + credential, + attester + ) + const tx = shouldRemove + ? api.tx.publicCredentials.remove(credentialId, null) + : api.tx.publicCredentials.revoke(credentialId, null) + + // Same as for traditional KILT credentials + const authorizedAttestationTx = await Kilt.Did.authorizeTx( + attester, + tx, + signCallback, + submitterAccount.address + ) + await Kilt.Blockchain.signAndSubmitTx( + authorizedAttestationTx, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/public_credentials/08_unrevoke_credential.ts b/code_examples/sdk_examples/src/v1/core_features/public_credentials/08_unrevoke_credential.ts new file mode 100644 index 000000000..807efffbd --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/public_credentials/08_unrevoke_credential.ts @@ -0,0 +1,27 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function unrevokeCredential( + attester: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + signCallback: Kilt.SignExtrinsicCallback, + credential: Kilt.IPublicCredentialInput +): Promise { + const api = Kilt.ConfigService.get('api') + + const credentialId = Kilt.PublicCredential.getIdForCredential( + credential, + attester + ) + const tx = api.tx.publicCredentials.unrevoke(credentialId, null) + + const authorizedAttestationTx = await Kilt.Did.authorizeTx( + attester, + tx, + signCallback, + submitterAccount.address + ) + await Kilt.Blockchain.signAndSubmitTx( + authorizedAttestationTx, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/public_credentials/09_reclaim_deposit.ts b/code_examples/sdk_examples/src/v1/core_features/public_credentials/09_reclaim_deposit.ts new file mode 100644 index 000000000..284b9afb1 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/public_credentials/09_reclaim_deposit.ts @@ -0,0 +1,18 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function reclaimDeposit( + submitterAddress: Kilt.KiltKeyringPair, + credential: Kilt.IPublicCredential +): Promise { + const api = Kilt.ConfigService.get('api') + + // Generate the tx to claim the deposit back. + const credentialId = Kilt.PublicCredential.getIdForCredential( + credential, + credential.attester + ) + const depositReclaimTx = api.tx.publicCredentials.reclaimDeposit(credentialId) + + // Submit the revocation tx to the KILT blockchain. + await Kilt.Blockchain.signAndSubmitTx(depositReclaimTx, submitterAddress) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/public_credentials/index.ts b/code_examples/sdk_examples/src/v1/core_features/public_credentials/index.ts new file mode 100644 index 000000000..e8fff72a9 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/public_credentials/index.ts @@ -0,0 +1,113 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +import { createCompleteFullDid } from '../did/05_full_did_complete' + +import { createNftCollectionCredential } from './01_create_credential' +import { fetchCredentialById } from './03_retrieve_credential_by_id' +import { issueCredential } from './02_issue_credential' +import { reclaimDeposit } from './09_reclaim_deposit' +import { retrieveAllAssetCredentials } from './04_retrieve_credentials_by_subject' +import { revokeCredential } from './07_revoke_remove_credential_by_content' +import { revokeCredentialById } from './06_revoke_remove_credential_by_id' +import { unrevokeCredential } from './08_unrevoke_credential' +import { verifyCredential } from './05_verify_credential' + +import { generateKeypairs } from '../utils/generateKeypairs' + +export async function runAll( + submitterAccount: Kilt.KiltKeyringPair +): Promise { + console.log('Running public credentials flow...') + const keypairs = generateKeypairs() + const attesterDid = await createCompleteFullDid( + submitterAccount, + keypairs, + async ({ data }) => ({ + signature: keypairs.authentication.sign(data), + keyType: keypairs.authentication.type + }) + ) + + console.log('1 public credentials) Create credential object') + const { authentication } = generateKeypairs() + const artistDid = Kilt.Did.getFullDidUriFromKey(authentication) + const collectionDid: Kilt.AssetDidUri = + 'did:asset:eip155:1.erc721:0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb' + const credential = createNftCollectionCredential(collectionDid, artistDid) + console.log('2 public credentials) Issue credential') + await issueCredential( + attesterDid.uri, + submitterAccount, + async ({ data }) => ({ + signature: keypairs.assertionMethod.sign(data), + keyType: keypairs.assertionMethod.type + }), + credential + ) + console.log('3 public credentials) Fetch credential by ID') + const credentialId = Kilt.PublicCredential.getIdForCredential( + credential, + attesterDid.uri + ) + const fetchedCredential = await fetchCredentialById(credentialId) + if (!fetchedCredential) { + throw new Error( + `Was not possible to retrieve just-issued credential with ID ${credentialId}` + ) + } + console.log('4 public credentials) Retrieve credentials by subject') + const retrievedCredentials = await retrieveAllAssetCredentials(collectionDid) + if (!retrievedCredentials) { + throw new Error( + `Was not possible to retrieve just-issued credentials for asset ${collectionDid}` + ) + } + console.log('5 public credentials) Verify credential') + await verifyCredential(fetchedCredential) + await verifyCredential(retrievedCredentials[0]) + console.log('6 public credentials) Revoke and remove credential by ID') + await revokeCredentialById( + attesterDid.uri, + submitterAccount, + async ({ data }) => ({ + signature: keypairs.assertionMethod.sign(data), + keyType: keypairs.assertionMethod.type + }), + credentialId, + true + ) + console.log('7.1 public credentials) Re-issue credential') + await issueCredential( + attesterDid.uri, + submitterAccount, + async ({ data }) => ({ + signature: keypairs.assertionMethod.sign(data), + keyType: keypairs.assertionMethod.type + }), + credential + ) + console.log('7.2 public credentials) Revoke credential') + await revokeCredential( + attesterDid.uri, + submitterAccount, + async ({ data }) => ({ + signature: keypairs.assertionMethod.sign(data), + keyType: keypairs.assertionMethod.type + }), + credential + ) + console.log('8 public credentials) Unrevoke credential') + await unrevokeCredential( + attesterDid.uri, + submitterAccount, + async ({ data }) => ({ + signature: keypairs.assertionMethod.sign(data), + keyType: keypairs.assertionMethod.type + }), + credential + ) + console.log('9 public credentials) Reclaim deposit') + await reclaimDeposit(submitterAccount, fetchedCredential) + + console.log('Public credentials flow completed!') +} diff --git a/code_examples/sdk_examples/src/v1/core_features/signCallback/index.ts b/code_examples/sdk_examples/src/v1/core_features/signCallback/index.ts new file mode 100644 index 000000000..9d68391a8 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/signCallback/index.ts @@ -0,0 +1,59 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +import { useSignCallback } from './useSignCallback' +import { useSignExtrinsicCallback } from './useExtrinsicCallback' +import { useStoreTxSignCallback } from './useStoreTxSignCallback' + +// The _keyUri parameter is there to show that the DID key pair is looked up using the URI +export function lookupDidKeyPair( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _keyUri: Kilt.DidResourceUri +): Kilt.KiltKeyringPair { + return Kilt.Utils.Crypto.makeKeypairFromSeed() +} + +export function generateDidKeyPair(): Kilt.KiltKeyringPair { + return Kilt.Utils.Crypto.makeKeypairFromSeed() +} + +// The _did parameter is there to show that the DID document is looked up using the DID +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export function lookupDidDocument(_did: Kilt.DidUri): Kilt.DidDocument { + const authentication = Kilt.Utils.Crypto.makeKeypairFromSeed() + const lightDID = Kilt.Did.createLightDidDocument({ + authentication: [authentication] + }) + + return lightDID +} + +export async function runAll(): Promise { + const api = Kilt.ConfigService.get('api') + + console.log('Test signCallback') + const didKey = Kilt.Utils.Crypto.makeKeypairFromSeed() + + ;( + await useSignCallback( + 'did:kilt:4pZGzLSybfMsxB1DcpFNYmnqFv5QihbFb1zuSuuATqjRQv2g#key-one', + didKey + ) + )({ + data: new Uint8Array([0, 1, 2, 3, 4]), + keyRelationship: 'authentication', + did: 'did:kilt:4pZGzLSybfMsxB1DcpFNYmnqFv5QihbFb1zuSuuATqjRQv2g' + }) + + console.log('Test signExtrinsicCallback') + await useSignExtrinsicCallback( + 'did:kilt:4pZGzLSybfMsxB1DcpFNYmnqFv5QihbFb1zuSuuATqjRQv2g', + didKey, + api.tx.didLookup.associateSender(), + '4pZGzLSybfMsxB1DcpFNYmnqFv5QihbFb1zuSuuATqjRQv2g' + ) + + console.log('Test getStoreTxSignCallback') + await useStoreTxSignCallback( + '4pZGzLSybfMsxB1DcpFNYmnqFv5QihbFb1zuSuuATqjRQv2g' + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/signCallback/useDecryptionCallback.ts b/code_examples/sdk_examples/src/v1/core_features/signCallback/useDecryptionCallback.ts new file mode 100644 index 000000000..eb5f7f70b --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/signCallback/useDecryptionCallback.ts @@ -0,0 +1,25 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export function useDecryptionCallback( + keyAgreement: Kilt.KiltEncryptionKeypair +): Kilt.DecryptCallback { + return async function decryptCallback({ + data, + nonce, + peerPublicKey + }): Promise { + const decrypted = Kilt.Utils.Crypto.decryptAsymmetric( + { box: data, nonce }, + peerPublicKey, + keyAgreement.secretKey + ) + + if (!decrypted) { + throw new Error('Failed to decrypt with given key') + } + + return { + data: decrypted + } + } +} diff --git a/code_examples/sdk_examples/src/v1/core_features/signCallback/useEncryptionCallback.ts b/code_examples/sdk_examples/src/v1/core_features/signCallback/useEncryptionCallback.ts new file mode 100644 index 000000000..1bf261844 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/signCallback/useEncryptionCallback.ts @@ -0,0 +1,25 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export function useEncryptionCallback({ + keyAgreement, + keyAgreementUri +}: { + keyAgreement: Kilt.KiltEncryptionKeypair + keyAgreementUri: Kilt.DidResourceUri +}): Kilt.EncryptCallback { + return async function encryptCallback({ + data, + peerPublicKey + }): Promise { + const { box, nonce } = Kilt.Utils.Crypto.encryptAsymmetric( + data, + peerPublicKey, + keyAgreement.secretKey + ) + return { + nonce, + data: box, + keyUri: keyAgreementUri + } + } +} diff --git a/code_examples/sdk_examples/src/v1/core_features/signCallback/useExtrinsicCallback.ts b/code_examples/sdk_examples/src/v1/core_features/signCallback/useExtrinsicCallback.ts new file mode 100644 index 000000000..09c9ae177 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/signCallback/useExtrinsicCallback.ts @@ -0,0 +1,31 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import * as Kilt from '@kiltprotocol/sdk-js' +import { Extrinsic } from '@polkadot/types/interfaces' + +export async function useSignExtrinsicCallback( + didUri: Kilt.DidUri, + didSigningKey: Kilt.KeyringPair & { type: 'sr25519' | 'ed25519' }, + extrinsic: Extrinsic, + submitterAddress: Kilt.KiltAddress +) { + // The SignExtrinsicCallback is a more specialized SignCallback since it doesn't + // need to return the keyUri. + const signCallback: Kilt.SignExtrinsicCallback = async ({ + data, + // The key relationship specifies which DID key must be used. + keyRelationship, + // The DID URI specifies which DID must be used. We already know which DID + // this will be since we will use this callback just a few lines later (did === didUri). + did + }) => ({ + signature: didSigningKey.sign(data), + keyType: didSigningKey.type + }) + + return await Kilt.Did.authorizeTx( + didUri, + extrinsic, + signCallback, + submitterAddress + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/signCallback/useSignCallback.ts b/code_examples/sdk_examples/src/v1/core_features/signCallback/useSignCallback.ts new file mode 100644 index 000000000..8c7373b5a --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/signCallback/useSignCallback.ts @@ -0,0 +1,22 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import * as Kilt from '@kiltprotocol/sdk-js' + +export function useSignCallback( + keyUri: Kilt.DidResourceUri, + didSigningKey: Kilt.KeyringPair & { type: 'sr25519' | 'ed25519' } +): Kilt.SignCallback { + const signCallback: Kilt.SignCallback = async ({ + data, + // The key relationship specifies which DID key must be used. + keyRelationship, + // The DID URI specifies which DID must be used. We already know which DID + // this will be since we will use this callback just a few lines later (did === didUri). + did + }) => ({ + signature: didSigningKey.sign(data), + keyType: didSigningKey.type, + keyUri + }) + + return signCallback +} diff --git a/code_examples/sdk_examples/src/v1/core_features/signCallback/useStoreTxSignCallback.ts b/code_examples/sdk_examples/src/v1/core_features/signCallback/useStoreTxSignCallback.ts new file mode 100644 index 000000000..2f0cb2237 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/signCallback/useStoreTxSignCallback.ts @@ -0,0 +1,28 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function useStoreTxSignCallback( + submitterAddress: Kilt.KiltAddress +): Promise { + // Here we create a new key pair for the DID that will be created later. + // This step might happen in an extension or else where, depending on your application. + const authenticationKey: Kilt.KiltKeyringPair = + Kilt.Utils.Crypto.makeKeypairFromSeed() + + // This is the sign callback. We use the just created key to sign arbitrary data + // and return the signature together with the key type. + const getStoreTxSignCallback: Kilt.Did.GetStoreTxSignCallback = async ({ + data + }) => ({ + signature: authenticationKey.sign(data), + keyType: authenticationKey.type + }) + + // Here we use the call back + return await Kilt.Did.getStoreTx( + { + authentication: [authenticationKey] + }, + submitterAddress, + getStoreTxSignCallback + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/utils/generateKeypairs.ts b/code_examples/sdk_examples/src/v1/core_features/utils/generateKeypairs.ts new file mode 100644 index 000000000..d2ace38cf --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/utils/generateKeypairs.ts @@ -0,0 +1,27 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +import { mnemonicGenerate } from '@polkadot/util-crypto' + +export function generateKeypairs(mnemonic = mnemonicGenerate()): { + authentication: Kilt.KiltKeyringPair + keyAgreement: Kilt.KiltEncryptionKeypair + assertionMethod: Kilt.KiltKeyringPair + capabilityDelegation: Kilt.KiltKeyringPair +} { + const authentication = Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic) + + const assertionMethod = Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic) + + const capabilityDelegation = Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic) + + const keyAgreement = Kilt.Utils.Crypto.makeEncryptionKeypairFromSeed( + Kilt.Utils.Crypto.mnemonicToMiniSecret(mnemonic) + ) + + return { + authentication: authentication, + keyAgreement: keyAgreement, + assertionMethod: assertionMethod, + capabilityDelegation: capabilityDelegation + } +} diff --git a/code_examples/sdk_examples/src/v1/core_features/utils/getExtrinsic.ts b/code_examples/sdk_examples/src/v1/core_features/utils/getExtrinsic.ts new file mode 100644 index 000000000..5588ffa00 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/utils/getExtrinsic.ts @@ -0,0 +1,20 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export default function getExtrinsic(): Kilt.SubmittableExtrinsic { + const api = Kilt.ConfigService.get('api') + + // Random factor ensures that each created CType is unique and does not already exist on chain. + const randomFactor = Kilt.Utils.UUID.generate() + return api.tx.ctype.add( + Kilt.CType.toChain( + Kilt.CType.fromProperties(`CType ${randomFactor}`, { + name: { + type: 'string' + }, + age: { + type: 'integer' + } + }) + ) + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/web3names/01_claim.ts b/code_examples/sdk_examples/src/v1/core_features/web3names/01_claim.ts new file mode 100644 index 000000000..b51921295 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/web3names/01_claim.ts @@ -0,0 +1,22 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function claimWeb3Name( + did: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + name: Kilt.Did.Web3Name, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + const web3NameClaimTx = api.tx.web3Names.claim(name) + const authorizedWeb3NameClaimTx = await Kilt.Did.authorizeTx( + did, + web3NameClaimTx, + signCallback, + submitterAccount.address + ) + await Kilt.Blockchain.signAndSubmitTx( + authorizedWeb3NameClaimTx, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/web3names/02_query_did_name.ts b/code_examples/sdk_examples/src/v1/core_features/web3names/02_query_did_name.ts new file mode 100644 index 000000000..4430a0b35 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/web3names/02_query_did_name.ts @@ -0,0 +1,16 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function queryDidDocument( + web3Name: Kilt.Did.Web3Name +): Promise { + const api = Kilt.ConfigService.get('api') + + console.log(`Querying the blockchain for the web3name "${web3Name}"`) + // Query the owner of the provided web3name. + const encodedWeb3NameOwner = await api.call.did.queryByWeb3Name(web3Name) + + // Extract the DidDocument and other linked information from the encodedWeb3NameOwner. + const { document } = Kilt.Did.linkedInfoFromChain(encodedWeb3NameOwner) + + return document +} diff --git a/code_examples/sdk_examples/src/v1/core_features/web3names/03_query_name_credentials.ts b/code_examples/sdk_examples/src/v1/core_features/web3names/03_query_name_credentials.ts new file mode 100644 index 000000000..a136fdc67 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/web3names/03_query_name_credentials.ts @@ -0,0 +1,82 @@ +import fetch from 'node-fetch' + +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function queryPublishedCredentials( + web3Name: Kilt.Did.Web3Name +): Promise { + const api = Kilt.ConfigService.get('api') + + const encodedDidForWeb3Name = await api.call.did.queryByWeb3Name(web3Name) + const { + document: { uri } + } = Kilt.Did.linkedInfoFromChain(encodedDidForWeb3Name) + + console.log(`DID for "${web3Name}": ${uri}`) + + const resolutionResult = await Kilt.Did.resolve(uri) + if (!resolutionResult) { + throw new Error('The DID does not exist on the KILT blockchain.') + } + + const { document } = resolutionResult + // If no details are returned but resolutionResult is not null, the DID has been deleted. + // This information is present in `resolutionResult.metadata.deactivated`. + if (!document) { + throw new Error('The DID has already been deleted.') + } + + // Filter the endpoints by their type. + const credentialEndpoints = document.service?.filter((service) => + service.type.includes(Kilt.KiltPublishedCredentialCollectionV1Type) + ) + + console.log( + `Endpoints of type "${Kilt.KiltPublishedCredentialCollectionV1Type}" for the retrieved DID:` + ) + console.log(JSON.stringify(credentialEndpoints, null, 2)) + + // For demonstration, only the first endpoint and its first URL are considered. + const firstCredentialCollectionEndpointUrl = + credentialEndpoints?.[0]?.serviceEndpoint[0] + if (!firstCredentialCollectionEndpointUrl) { + console.log( + `The DID has no services of type "${Kilt.KiltPublishedCredentialCollectionV1Type}".` + ) + } + + // Retrieve the credentials pointed at by the endpoint. + // Being an IPFS endpoint, the fetching can take an arbitrarily long time or even fail if the timeout is reached. + // In production settings, error cases including those where the result is not a correct JSON should be handled accordingly. + const response = await fetch(firstCredentialCollectionEndpointUrl as string) + const credentialCollection: Kilt.KiltPublishedCredentialCollectionV1 = + await response.json() + console.log(`Credential collection behind the endpoint:`) + console.log(JSON.stringify(credentialCollection, null, 2)) + + // Verify that all credentials are valid and that they all refer to the same subject DID. + await Promise.all( + credentialCollection.map(async ({ credential }) => { + const { revoked } = await Kilt.Credential.verifyCredential(credential) + + // Verify that the credential is not revoked. + if (revoked) { + throw new Error( + 'One of the credentials has been revoked, hence it is not valid.' + ) + } + + // Verify that the credential refers to the intended subject. + if (!Kilt.Did.isSameSubject(credential.claim.owner, uri)) { + throw new Error( + 'One of the credentials refers to a different subject than expected.' + ) + } + }) + ) + + // If none of the above operations throw, the credentials are valid. + console.log('All retrieved credentials are valid! โœ…!') + + return credentialCollection +} diff --git a/code_examples/sdk_examples/src/v1/core_features/web3names/04_release.ts b/code_examples/sdk_examples/src/v1/core_features/web3names/04_release.ts new file mode 100644 index 000000000..4a4bac84a --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/web3names/04_release.ts @@ -0,0 +1,21 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function releaseWeb3Name( + did: Kilt.DidUri, + submitterAccount: Kilt.KiltKeyringPair, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + const web3NameReleaseTx = api.tx.web3Names.releaseByOwner() + const authorizedWeb3NameReleaseTx = await Kilt.Did.authorizeTx( + did, + web3NameReleaseTx, + signCallback, + submitterAccount.address + ) + await Kilt.Blockchain.signAndSubmitTx( + authorizedWeb3NameReleaseTx, + submitterAccount + ) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/web3names/05_reclaim_deposit.ts b/code_examples/sdk_examples/src/v1/core_features/web3names/05_reclaim_deposit.ts new file mode 100644 index 000000000..1283b4118 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/web3names/05_reclaim_deposit.ts @@ -0,0 +1,12 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function reclaimWeb3NameDeposit( + submitterAccount: Kilt.KiltKeyringPair, + web3Name: Kilt.Did.Web3Name +): Promise { + const api = Kilt.ConfigService.get('api') + + // Release the web3name by the deposit payer. + const web3NameReleaseTx = api.tx.web3Names.reclaimDeposit(web3Name) + await Kilt.Blockchain.signAndSubmitTx(web3NameReleaseTx, submitterAccount) +} diff --git a/code_examples/sdk_examples/src/v1/core_features/web3names/index.ts b/code_examples/sdk_examples/src/v1/core_features/web3names/index.ts new file mode 100644 index 000000000..1a49ae271 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/core_features/web3names/index.ts @@ -0,0 +1,78 @@ +import { FetchError } from 'node-fetch' +import { randomUUID } from 'crypto' + +import * as Kilt from '@kiltprotocol/sdk-js' + +import { claimWeb3Name } from './01_claim' +import { createSimpleFullDid } from '../did/04_full_did_simple' +import { queryDidDocument } from './02_query_did_name' +import { queryPublishedCredentials } from './03_query_name_credentials' +import { reclaimWeb3NameDeposit } from './05_reclaim_deposit' +import { releaseWeb3Name } from './04_release' + +import { generateKeypairs } from '../utils/generateKeypairs' + +export async function runAll( + submitterAccount: Kilt.KiltKeyringPair +): Promise { + console.log('Running web3name flow...') + const { authentication } = generateKeypairs() + const fullDid = await createSimpleFullDid( + submitterAccount, + { + authentication + }, + async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type + }) + ) + const randomWeb3Name = randomUUID().substring(0, 32) + + console.log('1 w3n) Claim web3name') + await claimWeb3Name( + fullDid.uri, + submitterAccount, + randomWeb3Name, + async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type + }) + ) + console.log('2 w3n) Verify web3name owner and DID web3name') + const doc = await queryDidDocument(randomWeb3Name) + if (doc.uri !== fullDid.uri) { + throw new Error('web3name is registered for a wrong DID') + } + + console.log('3 w3n) Query credentials for "kiltnerd123" web3name') + try { + await queryPublishedCredentials('kiltnerd123') + } catch (e) { + if (e instanceof FetchError) { + console.log( + 'Query credentials for "kiltnerd123" web3name failed because of bad IPFS gateway. Ignoring this.' + ) + } else { + // This one should not have happened. + throw e + } + } + console.log('4 w3n) Release web3name') + await releaseWeb3Name(fullDid.uri, submitterAccount, async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type + })) + console.log('5 w3n) Re-claim web3name and reclaim deposit') + await claimWeb3Name( + fullDid.uri, + submitterAccount, + randomWeb3Name, + async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type + }) + ) + await reclaimWeb3NameDeposit(submitterAccount, randomWeb3Name) + console.log('web3name flow completed!') +} diff --git a/code_examples/sdk_examples/src/v1/dapp/dapp/01_domain_linkage_ctype.ts b/code_examples/sdk_examples/src/v1/dapp/dapp/01_domain_linkage_ctype.ts new file mode 100644 index 000000000..818f2b429 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/dapp/dapp/01_domain_linkage_ctype.ts @@ -0,0 +1,33 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function main(): Promise { + const { + creator, + createdAt, + cType: domainLinkageCType + } = await Kilt.CType.fetchFromChain( + 'kilt:ctype:0xb08800a574c436831a2b9fce00fd16e9df489b2b3695e88a0895d148eca0311e' + ) + + console.log(JSON.stringify(domainLinkageCType, null, 2)) + + /** Prints the following definition: + { + "$schema": "ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq/", + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "origin": { + "type": "string" + } + }, + "title": "Domain Linkage Credential", + "type": "object", + "$id": "kilt:ctype:0xb08800a574c436831a2b9fce00fd16e9df489b2b3695e88a0895d148eca0311e" + } + */ + return domainLinkageCType +} diff --git a/code_examples/sdk_examples/src/v1/dapp/dapp/02_domain_linkage_claim.ts b/code_examples/sdk_examples/src/v1/dapp/dapp/02_domain_linkage_claim.ts new file mode 100644 index 000000000..578af1f24 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/dapp/dapp/02_domain_linkage_claim.ts @@ -0,0 +1,23 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export function main({ + domainLinkageCType, + didUri +}: { + domainLinkageCType: Kilt.ICType + didUri: Kilt.DidUri +}) { + const claimContents: Kilt.IClaimContents = { + id: didUri, + origin: 'https://example.com' + } + + const claim = Kilt.Claim.fromCTypeAndClaimContents( + domainLinkageCType, + claimContents, + didUri + ) + const domainLinkageCredential = Kilt.Credential.fromClaim(claim) + + return { domainLinkageCredential } +} diff --git a/code_examples/sdk_examples/src/v1/dapp/dapp/03_sign_presentation.ts b/code_examples/sdk_examples/src/v1/dapp/dapp/03_sign_presentation.ts new file mode 100644 index 000000000..dddefe88a --- /dev/null +++ b/code_examples/sdk_examples/src/v1/dapp/dapp/03_sign_presentation.ts @@ -0,0 +1,30 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function main({ + didUri, + assertionMethodKey, + domainLinkageCredential +}: { + didUri: Kilt.DidUri + assertionMethodKey: Kilt.KiltKeyringPair + domainLinkageCredential: Kilt.ICredential +}) { + // We need the KeyId of the AssertionMethod Key. There is only + // one AssertionMethodKey and its id is stored on the blockchain. + const didResolveResult = await Kilt.Did.resolve(didUri) + if (typeof didResolveResult.document === 'undefined') { + throw new Error('DID must be resolvable (i.e. not deleted)') + } + const assertionMethodKeyId = didResolveResult.document.assertionMethod[0].id + + const domainLinkagePresentation = await Kilt.Credential.createPresentation({ + credential: domainLinkageCredential, + signCallback: async ({ data }) => ({ + signature: assertionMethodKey.sign(data), + keyType: assertionMethodKey.type, + keyUri: `${didUri}${assertionMethodKeyId}` + }) + }) + + return { domainLinkagePresentation } +} diff --git a/code_examples/sdk_examples/src/v1/dapp/dapp/04_attest_credential.ts b/code_examples/sdk_examples/src/v1/dapp/dapp/04_attest_credential.ts new file mode 100644 index 000000000..6d76666cb --- /dev/null +++ b/code_examples/sdk_examples/src/v1/dapp/dapp/04_attest_credential.ts @@ -0,0 +1,34 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function main({ + didUri, + dappAccount, + assertionMethodKey, + domainLinkageCredential +}: { + didUri: Kilt.DidUri + dappAccount: Kilt.KiltKeyringPair + assertionMethodKey: Kilt.KiltKeyringPair + domainLinkageCredential: Kilt.ICredential +}) { + const api = Kilt.ConfigService.get('api') + const { cTypeHash, claimHash } = Kilt.Attestation.fromCredentialAndDid( + domainLinkageCredential, + didUri + ) + const attestationTx = api.tx.attestation.add(claimHash, cTypeHash, null) + + // We authorize the call using the attestation key of the Dapps DID. + const extrinsic = api.tx.did.dispatchAs(dappAccount.address, attestationTx) + + // Since DIDs can not hold any balance, we pay for the transaction using our blockchain account + const result = await Kilt.Blockchain.signAndSubmitTx(extrinsic, dappAccount) + + if (result.isError) { + console.log('Attestation failed') + } else { + console.log('Attestation successful') + } + return result +} diff --git a/code_examples/sdk_examples/src/v1/dapp/dapp/05_format_credential.ts b/code_examples/sdk_examples/src/v1/dapp/dapp/05_format_credential.ts new file mode 100644 index 000000000..b9a6b3312 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/dapp/dapp/05_format_credential.ts @@ -0,0 +1,58 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function main( + domainLinkagePresentation: Kilt.ICredentialPresentation +) { + const api = Kilt.ConfigService.get('api') + + const credentialSubject = { + ...domainLinkagePresentation.claim.contents, + rootHash: domainLinkagePresentation.rootHash + } + + const encodedAttestationDetails = await api.query.attestation.attestations( + domainLinkagePresentation.rootHash + ) + const issuer = Kilt.Attestation.fromChain( + encodedAttestationDetails, + domainLinkagePresentation.claim.cTypeHash + ).owner + + const issuanceDate = new Date().toISOString() + + const claimerSignature = domainLinkagePresentation.claimerSignature + if (!claimerSignature) { + throw new Error('Claimer signature is required.') + } + + const proof = { + type: 'KILTSelfSigned2020', + proofPurpose: 'assertionMethod', + verificationMethod: claimerSignature.keyUri, + signature: claimerSignature.signature, + challenge: claimerSignature.challenge + } + + const wellKnownDidconfig = { + '@context': 'https://identity.foundation/.well-known/did-configuration/v1', + linked_dids: [ + { + '@context': [ + 'https://www.w3.org/2018/credentials/v1', + 'https://identity.foundation/.well-known/did-configuration/v1' + ], + issuer, + issuanceDate, + type: [ + 'VerifiableCredential', + 'DomainLinkageCredential', + 'KiltCredential2020' + ], + credentialSubject, + proof + } + ] + } + + return wellKnownDidconfig +} diff --git a/code_examples/sdk_examples/src/v1/dapp/dapp/06_dapp_introduction.ts b/code_examples/sdk_examples/src/v1/dapp/dapp/06_dapp_introduction.ts new file mode 100644 index 000000000..b2a20dcef --- /dev/null +++ b/code_examples/sdk_examples/src/v1/dapp/dapp/06_dapp_introduction.ts @@ -0,0 +1,44 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +// `window` object: Should be used only in the following example. +// Otherwise import directly from the KILT extension library. +// eslint-disable-next-line @typescript-eslint/no-explicit-any +let window: { + kilt: { + sporran: { + startSession: ( + dAppName: string, + dAppEncryptionKeyUri: Kilt.DidResourceUri, + challenge: string + ) => Promise + } + } +} + +export async function main() { + const api = Kilt.ConfigService.get('api') + + const did = 'did:kilt:4smcAoiTiCLaNrGhrAM4wZvt5cMKEGm8f3Cu9aFrpsh5EiNV' + const dAppName = 'Your dApp Name' + + const encodedFullDid = await api.call.did.query(Kilt.Did.toChain(did)) + const { document } = Kilt.Did.linkedInfoFromChain(encodedFullDid) + // If there is no DID, or the DID does not have any key agreement key, return + if (!document.keyAgreement || !document.keyAgreement[0]) { + return + } + const dAppEncryptionKeyUri = + `${document.uri}${document.keyAgreement[0].id}` as Kilt.DidResourceUri + + // Generate and store challenge on the server side for the next step. + const response = await fetch('/challenge') + const challenge = await response.text() + + const session = await window.kilt.sporran.startSession( + dAppName, + dAppEncryptionKeyUri, + challenge + ) + + return session +} diff --git a/code_examples/sdk_examples/src/v1/dapp/dapp/07_session_check.ts b/code_examples/sdk_examples/src/v1/dapp/dapp/07_session_check.ts new file mode 100644 index 000000000..47e0935e4 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/dapp/dapp/07_session_check.ts @@ -0,0 +1,39 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function main({ + session, + keyAgreementKeyPair, + originalChallenge +}: { + session: { + encryptionKeyUri: Kilt.DidResourceUri + encryptedChallenge: string + nonce: string + } + keyAgreementKeyPair: Kilt.KiltEncryptionKeypair + originalChallenge: `0x{string}` +}) { + const { encryptionKeyUri, encryptedChallenge, nonce } = session + const encryptionKey = await Kilt.Did.resolveKey(encryptionKeyUri) + if (!encryptionKey) { + throw new Error('an encryption key is required') + } + + const decryptedBytes = Kilt.Utils.Crypto.decryptAsymmetric( + { box: encryptedChallenge, nonce }, + encryptionKey.publicKey, + keyAgreementKeyPair.secretKey // derived from your seed phrase + ) + // If it fails to decrypt, return. + if (!decryptedBytes) { + throw new Error('Could not decode') + } + + const decryptedChallenge = Kilt.Utils.Crypto.u8aToHex(decryptedBytes) + + // Compare the decrypted challenge to the challenge you stored earlier. + if (decryptedChallenge !== originalChallenge) { + throw new Error('Invalid challenge') + } + return session +} diff --git a/code_examples/sdk_examples/src/v1/dapp/index.ts b/code_examples/sdk_examples/src/v1/dapp/index.ts new file mode 100644 index 000000000..f5afed159 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/dapp/index.ts @@ -0,0 +1,45 @@ +import * as Kilt from '@kiltprotocol/sdk-js' +import { main as attestCredential } from './dapp/04_attest_credential' +import { createFullDid } from '../workshop/attester/generateDid' +import { main as formatCredential } from './dapp/05_format_credential' +import { generateAccount } from '../workshop/attester/generateAccount' +import { generateKeypairs as generateAttesterKeypairs } from '../workshop/attester/generateKeypairs' +import { main as getDomainLinkageCType } from './dapp/01_domain_linkage_ctype' +import { main as getDomainLinkageCredential } from './dapp/02_domain_linkage_claim' +import { getFunds } from '../getFunds' +import { main as signPresentation } from './dapp/03_sign_presentation' + +export async function testDapp(account: Kilt.KeyringPair, wssAddress: string) { + console.log('Running the dapp examples!') + + Kilt.ConfigService.set({ submitTxResolveOn: Kilt.Blockchain.IS_IN_BLOCK }) + await Kilt.connect(wssAddress) + + // Setup attester account. + const { account: dappAccount } = generateAccount() + + await getFunds(account, dappAccount.address, 4) + + // Create attester DID & ensure CType. + const { fullDid: attesterDid } = await createFullDid(dappAccount) + const { assertionMethod: assertionMethodKey } = generateAttesterKeypairs() + + const domainLinkageCType = await getDomainLinkageCType() + const { domainLinkageCredential } = getDomainLinkageCredential({ + domainLinkageCType, + didUri: attesterDid.uri + }) + await attestCredential({ + didUri: attesterDid.uri, + dappAccount, + assertionMethodKey, + domainLinkageCredential + }) + const { domainLinkagePresentation } = await signPresentation({ + didUri: attesterDid.uri, + assertionMethodKey, + domainLinkageCredential + }) + const pseudoVc = await formatCredential(domainLinkagePresentation) + console.log(JSON.stringify(pseudoVc)) +} diff --git a/code_examples/sdk_examples/src/v1/dapp/verifier/01_email_ctype.ts b/code_examples/sdk_examples/src/v1/dapp/verifier/01_email_ctype.ts new file mode 100644 index 000000000..240bc6406 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/dapp/verifier/01_email_ctype.ts @@ -0,0 +1,19 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export function main() { + const emailCType: Kilt.ICType = { + $id: 'kilt:ctype:0xae5bc64e500eb576b7b137288cec5d532094e103be46872f1ad54641e477d9fe', + $schema: + 'ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq/', + title: 'Email', + properties: { + Email: { + type: 'string' + } + }, + type: 'object', + additionalProperties: false + } + + console.log(emailCType) +} diff --git a/code_examples/sdk_examples/src/v1/dapp/verifier/02_generate_challenge.ts b/code_examples/sdk_examples/src/v1/dapp/verifier/02_generate_challenge.ts new file mode 100644 index 000000000..d2b9f7a5e --- /dev/null +++ b/code_examples/sdk_examples/src/v1/dapp/verifier/02_generate_challenge.ts @@ -0,0 +1,6 @@ +import { randomAsHex } from '@polkadot/util-crypto' + +// Store somewhere in the backend. +export function generateRequestChallenge() { + return randomAsHex(24) +} diff --git a/code_examples/sdk_examples/src/v1/dapp/verifier/03_create_request_credential_message.ts b/code_examples/sdk_examples/src/v1/dapp/verifier/03_create_request_credential_message.ts new file mode 100644 index 000000000..0bb04cfcb --- /dev/null +++ b/code_examples/sdk_examples/src/v1/dapp/verifier/03_create_request_credential_message.ts @@ -0,0 +1,40 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export function main({ + verifierDidUri, + session, + requestChallenge +}: { + verifierDidUri: Kilt.DidUri + session: { + encryptionKeyUri: Kilt.DidResourceUri + } + requestChallenge: string +}): { + message: Kilt.IMessage +} { + // The `session` was created earlier in your frontend. Only the session DID URI is sent to your backend. + const { did: claimerSessionDidUri } = Kilt.Did.parse(session.encryptionKeyUri) + + // The message is constructed in your backend + const message = Kilt.Message.fromBody( + { + content: { + cTypes: [ + { + // the hash of the email CType + cTypeHash: + '0x3291bb126e33b4862d421bfaa1d2f272e6cdfc4f96658988fbcffea8914bd9ac', + requiredProperties: ['Email'] + } + ], + challenge: requestChallenge + }, + type: 'request-credential' + }, + verifierDidUri, + claimerSessionDidUri + ) + + return { message } +} diff --git a/code_examples/sdk_examples/src/v1/dapp/verifier/04_encrypt_request_credential_message.ts b/code_examples/sdk_examples/src/v1/dapp/verifier/04_encrypt_request_credential_message.ts new file mode 100644 index 000000000..c0e51dc73 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/dapp/verifier/04_encrypt_request_credential_message.ts @@ -0,0 +1,58 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function main({ + message, + verifierDidUri, + verifierKeys, + session +}: { + message: Kilt.IMessage + verifierDidUri: Kilt.DidUri + verifierKeys: { + authentication: Kilt.KiltKeyringPair + encryption: Kilt.KiltEncryptionKeypair + attestation: Kilt.KiltKeyringPair + delegation: Kilt.KiltKeyringPair + } + session: { + encryptionKeyUri: Kilt.DidResourceUri + send: (message: Kilt.IEncryptedMessage) => Promise + } +}) { + const { document: verifierDidDoc } = await Kilt.Did.resolve(verifierDidUri) + if (!verifierDidDoc) { + throw new Error('The verifier DID must exist') + } + const verifierEncryptionKey = verifierDidDoc.keyAgreement?.[0] + if (!verifierEncryptionKey) { + throw new Error('The verifier DID must have a key agreement key') + } + + // Create a callback that uses the DID encryption key to encrypt the message. + const encryptCallback: Kilt.EncryptCallback = async ({ + data, + peerPublicKey + }) => { + const { box, nonce } = Kilt.Utils.Crypto.encryptAsymmetric( + data, + peerPublicKey, + verifierKeys.encryption.secretKey + ) + return { + data: box, + nonce, + keyUri: `${verifierDidDoc.uri}${verifierEncryptionKey.id}` + } + } + + const encryptedMessage = await Kilt.Message.encrypt( + message, + encryptCallback, + session.encryptionKeyUri + ) + + // Finally, send the encrypted message to the extension. + // While the above code will be executed on the server, this must happen in + // the frontend since it's dispatching the message to the browser extension. + await session.send(encryptedMessage) +} diff --git a/code_examples/sdk_examples/src/v1/dapp/verifier/05_verify_credential_message.ts b/code_examples/sdk_examples/src/v1/dapp/verifier/05_verify_credential_message.ts new file mode 100644 index 000000000..bfacc1782 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/dapp/verifier/05_verify_credential_message.ts @@ -0,0 +1,71 @@ +import '@kiltprotocol/augment-api' +import * as Kilt from '@kiltprotocol/sdk-js' + +type ListenCallback = (message: Kilt.IEncryptedMessage) => Promise + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function isTrustedAttester(_attester: Kilt.DidUri): boolean { + return true +} + +export async function main({ + session, + verifierKeys +}: { + session: { listen: (call: ListenCallback) => ReturnType } + verifierKeys: { + authentication: Kilt.KiltKeyringPair + encryption: Kilt.KiltEncryptionKeypair + attestation: Kilt.KiltKeyringPair + delegation: Kilt.KiltKeyringPair + } +}) { + async function processInBackend(message: Kilt.IEncryptedMessage) { + // Create a callback that uses the DID encryption key to decrypt the message. + const decryptCallback: Kilt.DecryptCallback = async ({ + data, + nonce, + peerPublicKey + }) => { + const result = Kilt.Utils.Crypto.decryptAsymmetric( + { box: data, nonce }, + peerPublicKey, + verifierKeys.encryption.secretKey + ) + if (!result) { + throw new Error('Cannot decrypt') + } + return { + data: result + } + } + + const decryptedMessage = await Kilt.Message.decrypt( + message, + decryptCallback + ) + + if (decryptedMessage.body.type !== 'submit-credential') { + throw new Error('Unexpected message type') + } + const credential = decryptedMessage.body.content[0] + + const { revoked, attester } = + await Kilt.Credential.verifyPresentation(credential) + + if (revoked) { + throw new Error("Credential has been revoked and hence it's not valid.") + } + if (isTrustedAttester(attester)) { + console.log( + "The claim is valid. Claimer's email:", + credential.claim.contents.Email + ) + } + } + + // In the frontend we wait for messages from the browser extension and forward them to the server. + await session.listen(async (message: Kilt.IEncryptedMessage) => { + processInBackend(message) + }) +} diff --git a/code_examples/sdk_examples/src/v1/getFunds.ts b/code_examples/sdk_examples/src/v1/getFunds.ts new file mode 100644 index 000000000..f295af472 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/getFunds.ts @@ -0,0 +1,68 @@ +import * as Kilt from '@kiltprotocol/sdk-js' +import { BN } from '@polkadot/util' +import { setTimeout } from 'timers/promises' + +async function failproofSubmit( + tx: Kilt.SubmittableExtrinsic, + submitter: Kilt.KeyringPair +) { + try { + await Kilt.Blockchain.signAndSubmitTx(tx, submitter) + } catch { + // Try a second time after a small delay and fetching the right nonce. + const waitingTime = 12_000 // 12 seconds + console.log( + `First submission failed for workshop. Waiting ${waitingTime} ms before retrying.` + ) + await setTimeout(waitingTime) + console.log('Retrying...') + // nonce: -1 tells the client to fetch the latest nonce by also checking the tx pool. + const resignedBatchTx = await tx.signAsync(submitter, { nonce: -1 }) + await Kilt.Blockchain.submitSignedTx(resignedBatchTx) + } +} + +export async function getFunds( + faucetAccount: Kilt.KeyringPair, + recipient: Kilt.KiltAddress, + kiltAmount: number +) { + const api = Kilt.ConfigService.get('api') + const tx = api.tx.balances.transferKeepAlive( + recipient, + Kilt.BalanceUtils.convertToTxUnit(new BN(kiltAmount), 0) + ) + await failproofSubmit(tx, faucetAccount) + console.log('Successfully transferred tokens') +} + +export async function endowAccounts( + faucetAccount: Kilt.KeyringPair, + destinationAccounts: Kilt.KiltAddress[], + amount: BN +): Promise { + const api = Kilt.ConfigService.get('api') + + const transferBatch = destinationAccounts.map((acc) => + api.tx.balances.transferKeepAlive( + acc, + Kilt.BalanceUtils.convertToTxUnit( + Kilt.BalanceUtils.KILT_COIN.mul(amount), + 0 + ) + ) + ) + + console.log( + `Endowing test accounts "${destinationAccounts}" + from faucet "${faucetAccount.address}" + with ${Kilt.BalanceUtils.formatKiltBalance(amount, { + decimals: 0 + })} each...` + ) + const batchTx = api.tx.utility.batchAll(transferBatch) + + await failproofSubmit(batchTx, faucetAccount) + + console.log('Successfully transferred tokens') +} diff --git a/code_examples/sdk_examples/src/v1/staking/index.ts b/code_examples/sdk_examples/src/v1/staking/index.ts new file mode 100644 index 000000000..0674777f7 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/staking/index.ts @@ -0,0 +1,25 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +import { claimCollatorStakingRewards } from './rewards/02_claim_collator_staking_rewards' +import { claimDelegatorStakingRewards } from './rewards/03_claim_delegator_staking_rewards' + +import { getUnclaimedStakingRewards } from './rewards/01_query_staking_rewards' + +// We don't expect these tests to pass yet. +// We would need a collator seed and a delegator seed to test if we can claim rewards. +export async function testStaking(wssAddress: string) { + await Kilt.connect(wssAddress) + + const collator = Kilt.Utils.Crypto.makeKeypairFromUri('//Alice', 'sr25519') + const delegator = Kilt.Utils.Crypto.makeKeypairFromUri('//Charlie', 'sr25519') + + console.log('1) Checking staking rewards') + const rewards = await getUnclaimedStakingRewards(collator.address) + console.log(`Done checking rewards: ${rewards}`) + + console.log('2) Claiming staking rewards') + console.log(`2a) Claiming collator rewards for ${collator.address}`) + await claimCollatorStakingRewards(collator) + console.log(`2b) Claiming delegator rewards for ${delegator.address}`) + await claimDelegatorStakingRewards(delegator) +} diff --git a/code_examples/sdk_examples/src/v1/staking/rewards/01_query_staking_rewards.ts b/code_examples/sdk_examples/src/v1/staking/rewards/01_query_staking_rewards.ts new file mode 100644 index 000000000..37dfab228 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/staking/rewards/01_query_staking_rewards.ts @@ -0,0 +1,10 @@ +import * as Kilt from '@kiltprotocol/sdk-js' +import { Balance } from '@polkadot/types/interfaces' + +export async function getUnclaimedStakingRewards(account: Kilt.KiltAddress) { + const api = Kilt.ConfigService.get('api') + + const rewards = + await api.call.staking.getUnclaimedStakingRewards(account) + return rewards.toBigInt() +} diff --git a/code_examples/sdk_examples/src/v1/staking/rewards/02_claim_collator_staking_rewards.ts b/code_examples/sdk_examples/src/v1/staking/rewards/02_claim_collator_staking_rewards.ts new file mode 100644 index 000000000..af7e1c3ff --- /dev/null +++ b/code_examples/sdk_examples/src/v1/staking/rewards/02_claim_collator_staking_rewards.ts @@ -0,0 +1,57 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function claimCollatorStakingRewards( + submitterAccount: Kilt.KeyringPair +) { + const api = Kilt.ConfigService.get('api') + + const tx = api.tx.utility.batch([ + // convert collator participation points into rewards + api.tx.parachainStaking.incrementCollatorRewards(), + // mint rewards for collator address + api.tx.parachainStaking.claimRewards() + ]) + + // boilerplate to sign and send tx to websocket + return new Promise((resolve, reject) => + tx.signAndSend(submitterAccount, ({ status, dispatchError }) => { + if (status.isFinalized && !dispatchError) { + onSuccess( + submitterAccount.address, + status.asFinalized.toString(), + resolve + ) + } + if (dispatchError) { + if (dispatchError.isModule) { + // for module errors, we have the section indexed, lookup + const decoded = api.registry.findMetaError(dispatchError.asModule) + const { docs, name, section } = decoded + + const error = new Error(`${section}.${name}: ${docs.join(' ')}`) + onError(error, reject) + } else { + // Other, CannotLookup, BadOrigin, no extra info + const error = new Error(dispatchError.toString()) + onError(error, reject) + } + } + }) + ) +} + +// boilerplate handlers +const onSuccess = ( + address: string, + txHash: string, + resolve: (res: string) => void +) => { + console.log( + `Claimed collator staking rewards for ${address} with tx hash ${txHash}` + ) + resolve(txHash) +} +const onError = (error: Error, reject: (err: Error) => void) => { + console.error(`Failed to claim collator staking rewards due to ${error}`) + reject(error) +} diff --git a/code_examples/sdk_examples/src/v1/staking/rewards/03_claim_delegator_staking_rewards.ts b/code_examples/sdk_examples/src/v1/staking/rewards/03_claim_delegator_staking_rewards.ts new file mode 100644 index 000000000..f7ae26a73 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/staking/rewards/03_claim_delegator_staking_rewards.ts @@ -0,0 +1,57 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function claimDelegatorStakingRewards( + submitterAccount: Kilt.KeyringPair +) { + const api = Kilt.ConfigService.get('api') + + const tx = api.tx.utility.batch([ + // convert delegator participation points into rewards + api.tx.parachainStaking.incrementDelegatorRewards(), + // mint rewards for delegator address + api.tx.parachainStaking.claimRewards() + ]) + + // boilerplate to sign and send tx to websocket + return new Promise((resolve, reject) => + tx.signAndSend(submitterAccount, ({ status, dispatchError }) => { + if (status.isFinalized && !dispatchError) { + onSuccess( + submitterAccount.address, + status.asFinalized.toString(), + resolve + ) + } + if (dispatchError) { + if (dispatchError.isModule) { + // for module errors, we have the section indexed, lookup + const decoded = api.registry.findMetaError(dispatchError.asModule) + const { docs, name, section } = decoded + + const error = new Error(`${section}.${name}: ${docs.join(' ')}`) + onError(error, reject) + } else { + // Other, CannotLookup, BadOrigin, no extra info + const error = new Error(dispatchError.toString()) + onError(error, reject) + } + } + }) + ) +} + +// boilerplate handlers +const onSuccess = ( + address: string, + txHash: string, + resolve: (res: string) => void +) => { + console.log( + `Claimed delegator staking rewards for ${address} with tx hash ${txHash}` + ) + resolve(txHash) +} +const onError = (error: Error, reject: (err: Error) => void) => { + console.error(`Failed to claim delegator staking rewards due to ${error}`) + reject(error) +} diff --git a/code_examples/sdk_examples/src/v1/staking/utility.ts b/code_examples/sdk_examples/src/v1/staking/utility.ts new file mode 100644 index 000000000..02724d798 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/staking/utility.ts @@ -0,0 +1,30 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function signAndSend( + tx: Kilt.SubmittableExtrinsic, + signer: Kilt.KeyringPair, + onSuccess: (txHash: string) => void, + onError: (error: Error) => void +) { + const api = Kilt.ConfigService.get('api') + + return tx.signAndSend(signer, ({ status, dispatchError }) => { + if (status.isFinalized && !dispatchError) { + onSuccess(status.asFinalized.toString()) + } + if (dispatchError) { + if (dispatchError.isModule) { + // for module errors, we have the section indexed, lookup + const decoded = api.registry.findMetaError(dispatchError.asModule) + const { docs, name, section } = decoded + + const error = new Error(`${section}.${name}: ${docs.join(' ')}`) + onError(error) + } else { + // Other, CannotLookup, BadOrigin, no extra info + const error = new Error(dispatchError.toString()) + onError(error) + } + } + }) +} diff --git a/code_examples/sdk_examples/src/v1/test.ts b/code_examples/sdk_examples/src/v1/test.ts new file mode 100644 index 000000000..10c71b2b5 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/test.ts @@ -0,0 +1,88 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +import { config as envConfig } from 'dotenv' +import { hexToU8a } from '@polkadot/util' +import { program } from 'commander' + +import { testCoreFeatures } from './core_features' +import { testDapp } from './dapp' +import { testStaking } from './staking' +import { testWorkshop } from './workshop' +;(async () => { + const whichToRun = { + workshop: false, + dapp: false, + core: false, + staking: false + } + // Can pass specific tests via command line arguments, or run all tests by default. + program.description('Test the code examples used in the KILT documentation.') + program + .command('all', { isDefault: true }) + .description('Run all tests') + .action(() => { + for (const key in whichToRun) { + whichToRun[key] = true + } + }) + program + .command('workshop') + .description('Test code examples inside the workshop') + .action(() => { + whichToRun.workshop = true + }) + program + .command('dapp') + .description('Test code examples inside the DApp section') + .action(() => { + whichToRun.dapp = true + }) + program + .command('core') + .description('Test code examples inside the Core Feature section') + .action(() => { + whichToRun.core = true + }) + program + .command('staking') + .description('Test code examples inside the Staking section') + .action(() => { + whichToRun.staking = true + }) + program.parse() + + envConfig() + await Kilt.init() + const wssAddress = process.env.WSS_ADDRESS || 'wss://peregrine.kilt.io' + const faucetSeed = process.env.FAUCET_SEED + + let [workshopAccount, dappAccount, coreAccount] = new Array(3) + + const faucetAccount = Kilt.Utils.Crypto.makeKeypairFromSeed( + hexToU8a(faucetSeed), + 'sr25519' + ) as Kilt.KeyringPair + workshopAccount = faucetAccount + dappAccount = faucetAccount + coreAccount = faucetAccount + + // If any of these flows fail, just send some more tokens to the account that is failing. + try { + if (whichToRun.workshop) { + await testWorkshop(workshopAccount, wssAddress) + } + if (whichToRun.dapp) { + await testDapp(dappAccount, wssAddress) + } + if (whichToRun.core) { + await testCoreFeatures(coreAccount, wssAddress) + } + if (whichToRun.staking) { + await testStaking(wssAddress) + } + process.exit(0) + } catch (e) { + console.error(e) + process.exit(1) + } +})() diff --git a/code_examples/sdk_examples/src/v1/workshop/attester/attestCredential.ts b/code_examples/sdk_examples/src/v1/workshop/attester/attestCredential.ts new file mode 100644 index 000000000..ad4474641 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/attester/attestCredential.ts @@ -0,0 +1,93 @@ +import { config as envConfig } from 'dotenv' + +import * as Kilt from '@kiltprotocol/sdk-js' + +import { generateAccount } from './generateAccount' +import { generateCredential } from '../claimer/generateCredential' +import { generateKeypairs } from './generateKeypairs' +import { generateLightDid } from '../claimer/generateLightDid' + +export async function attestCredential( + attesterAccount: Kilt.KiltKeyringPair, + attesterDid: Kilt.DidUri, + credential: Kilt.ICredential +): Promise { + const api = Kilt.ConfigService.get('api') + + // Get CType and root hash from the provided credential. + const { cTypeHash, claimHash } = Kilt.Attestation.fromCredentialAndDid( + credential, + attesterDid + ) + + // Create the tx and authorize it. + const tx = api.tx.attestation.add(claimHash, cTypeHash, null) + const extrinsic = api.tx.did.dispatchAs(attesterAccount.address, tx) + + // Submit the tx to write the attestation to the chain. + console.log('Attester -> create attestation...') + await Kilt.Blockchain.signAndSubmitTx(extrinsic, attesterAccount) +} + +export async function attestingFlow( + claimerDid: Kilt.DidUri, + attesterAccount: Kilt.KiltKeyringPair, + attesterDid: Kilt.DidUri, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + signCallback: Kilt.SignExtrinsicCallback +): Promise { + // First the claimer. + const credential = generateCredential(claimerDid, { + age: 27, + name: 'Mia Musterfrau' + }) + + // ... send the request to the attester + + // The attester checks the attributes and attests the provided credential. + await attestCredential(attesterAccount, attesterDid, credential) + + // Return the generated credential. + return credential +} + +// Don't execute if this is imported by another file. +if (require.main === module) { + ;(async () => { + envConfig() + + try { + await Kilt.connect(process.env.WSS_ADDRESS as string) + + const attesterAccountMnemonic = process.env + .ATTESTER_ACCOUNT_MNEMONIC as string + const { account: attesterAccount } = generateAccount( + attesterAccountMnemonic + ) + + const attesterDidMnemonic = process.env.ATTESTER_DID_MNEMONIC as string + const { authentication, assertionMethod } = + generateKeypairs(attesterDidMnemonic) + const attesterDidUri = Kilt.Did.getFullDidUriFromKey(authentication) + + const claimerDidMnemonic = process.env.CLAIMER_DID_MNEMONIC as string + const claimerDid = await generateLightDid(claimerDidMnemonic) + + const credential = await attestingFlow( + claimerDid.uri, + attesterAccount, + attesterDidUri, + async ({ data }) => ({ + signature: assertionMethod.sign(data), + keyType: assertionMethod.type + }) + ) + console.log('The claimer build their credential and now has to store it.') + console.log('Add the following to your .env file. ') + console.log(`CLAIMER_CREDENTIAL='${JSON.stringify(credential)}'`) + } catch (e) { + console.log('Error while going throw attesting workflow') + throw e + } + })() +} diff --git a/code_examples/sdk_examples/src/v1/workshop/attester/ctypeSchema.ts b/code_examples/sdk_examples/src/v1/workshop/attester/ctypeSchema.ts new file mode 100644 index 000000000..71fdc236b --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/attester/ctypeSchema.ts @@ -0,0 +1,13 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +// Return CType with the properties matching a given schema. +export function getCtypeSchema(): Kilt.ICType { + return Kilt.CType.fromProperties('Drivers License', { + name: { + type: 'string' + }, + age: { + type: 'integer' + } + }) +} diff --git a/code_examples/sdk_examples/src/v1/workshop/attester/generateAccount.ts b/code_examples/sdk_examples/src/v1/workshop/attester/generateAccount.ts new file mode 100644 index 000000000..74e647445 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/attester/generateAccount.ts @@ -0,0 +1,34 @@ +import { config as envConfig } from 'dotenv' + +import * as Kilt from '@kiltprotocol/sdk-js' + +export function generateAccount( + mnemonic = Kilt.Utils.Crypto.mnemonicGenerate() +): { + account: Kilt.KiltKeyringPair & { type: 'ed25519' } + mnemonic: string +} { + return { + account: Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic), + mnemonic + } +} + +// Don't execute if this is imported by another file. +if (require.main === module) { + ;(async () => { + envConfig() + + try { + await Kilt.init() + + const { mnemonic, account } = generateAccount() + console.log('save to mnemonic and address to .env to continue!\n\n') + console.log(`ATTESTER_ACCOUNT_MNEMONIC="${mnemonic}"`) + console.log(`ATTESTER_ACCOUNT_ADDRESS="${account.address}"\n\n`) + } catch (e) { + console.log('Error while setting up attester account') + throw e + } + })() +} diff --git a/code_examples/sdk_examples/src/v1/workshop/attester/generateCtype.ts b/code_examples/sdk_examples/src/v1/workshop/attester/generateCtype.ts new file mode 100644 index 000000000..b72850944 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/attester/generateCtype.ts @@ -0,0 +1,77 @@ +import { config as envConfig } from 'dotenv' + +import * as Kilt from '@kiltprotocol/sdk-js' + +import { generateAccount } from './generateAccount' +import { generateKeypairs } from './generateKeypairs' +import { getCtypeSchema } from './ctypeSchema' + +export async function ensureStoredCtype( + attesterAccount: Kilt.KiltKeyringPair, + attesterDid: Kilt.DidUri, + signCallback: Kilt.SignExtrinsicCallback +): Promise { + const api = Kilt.ConfigService.get('api') + + // Get the CTYPE and see if it's stored, if yes return it. + const ctype = getCtypeSchema() + try { + await Kilt.CType.verifyStored(ctype) + console.log('Ctype already stored. Skipping creation') + return ctype + } catch { + console.log('Ctype not present. Creating it now...') + // Authorize the tx. + const encodedCtype = Kilt.CType.toChain(ctype) + const tx = api.tx.ctype.add(encodedCtype) + const extrinsic = await Kilt.Did.authorizeTx( + attesterDid, + tx, + signCallback, + attesterAccount.address + ) + + // Write to chain then return the CType. + await Kilt.Blockchain.signAndSubmitTx(extrinsic, attesterAccount) + + return ctype + } +} + +// Don't execute if this is imported by another file. +if (require.main === module) { + ;(async () => { + envConfig() + + try { + await Kilt.connect(process.env.WSS_ADDRESS as string) + + const accountMnemonic = process.env.ATTESTER_ACCOUNT_MNEMONIC as string + const { account } = generateAccount(accountMnemonic) + + const didMnemonic = process.env.ATTESTER_DID_MNEMONIC as string + const { authentication, assertionMethod } = generateKeypairs(didMnemonic) + const attesterDidUri = Kilt.Did.getFullDidUriFromKey(authentication) + + const newCType = await ensureStoredCtype( + account, + attesterDidUri, + async ({ data }) => ({ + signature: assertionMethod.sign(data), + keyType: assertionMethod.type + }) + ) + + console.log( + `your ctype was succsesfully created\n\n${JSON.stringify( + newCType, + null, + 2 + )}` + ) + } catch (e) { + console.log('Error while checking on chain ctype') + throw e + } + })() +} diff --git a/code_examples/sdk_examples/src/v1/workshop/attester/generateDid.ts b/code_examples/sdk_examples/src/v1/workshop/attester/generateDid.ts new file mode 100644 index 000000000..54557bcef --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/attester/generateDid.ts @@ -0,0 +1,60 @@ +import * as Kilt from '@kiltprotocol/sdk-js' +import { config as envConfig } from 'dotenv' +import { generateAccount } from './generateAccount' + +export async function createFullDid( + creatorAccount: Kilt.KiltKeyringPair & { + type: 'ed25519' | 'sr25519' | 'ecdsa' + } +): Promise<{ + fullDid: Kilt.DidDocument +}> { + const api = Kilt.ConfigService.get('api') + + const verificationMethod = Kilt.Did.publicKeyToChain(creatorAccount) + + const txs = [ + api.tx.did.createFromAccount(verificationMethod), + api.tx.did.dispatchAs( + creatorAccount.address, + api.tx.did.setAttestationKey(verificationMethod) + ) + ] + + console.log('Creating DID from accountโ€ฆ') + await Kilt.Blockchain.signAndSubmitTx( + api.tx.utility.batch(txs), + creatorAccount + ) + const didUri = Kilt.Did.getFullDidUriFromKey(creatorAccount) + const encodedFullDid = await api.call.did.query(Kilt.Did.toChain(didUri)) + const { document: didDocument } = Kilt.Did.linkedInfoFromChain(encodedFullDid) + + if (!didDocument) { + throw new Error('Full DID was not successfully created.') + } + + return { fullDid: didDocument } +} + +// Don't execute if this is imported by another file. +if (require.main === module) { + ;(async () => { + envConfig() + + try { + await Kilt.connect(process.env.WSS_ADDRESS as string) + + // Load attester account + const accountMnemonic = process.env.ATTESTER_ACCOUNT_MNEMONIC as string + const { account } = generateAccount(accountMnemonic) + const { fullDid } = await createFullDid(account) + + console.log('\nsave following to .env to continue\n') + console.error(`ATTESTER_DID_URI="${fullDid.uri}"\n`) + } catch (e) { + console.log('Error while creating attester DID') + throw e + } + })() +} diff --git a/code_examples/sdk_examples/src/v1/workshop/attester/generateKeypairs.ts b/code_examples/sdk_examples/src/v1/workshop/attester/generateKeypairs.ts new file mode 100644 index 000000000..d2ace38cf --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/attester/generateKeypairs.ts @@ -0,0 +1,27 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +import { mnemonicGenerate } from '@polkadot/util-crypto' + +export function generateKeypairs(mnemonic = mnemonicGenerate()): { + authentication: Kilt.KiltKeyringPair + keyAgreement: Kilt.KiltEncryptionKeypair + assertionMethod: Kilt.KiltKeyringPair + capabilityDelegation: Kilt.KiltKeyringPair +} { + const authentication = Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic) + + const assertionMethod = Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic) + + const capabilityDelegation = Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic) + + const keyAgreement = Kilt.Utils.Crypto.makeEncryptionKeypairFromSeed( + Kilt.Utils.Crypto.mnemonicToMiniSecret(mnemonic) + ) + + return { + authentication: authentication, + keyAgreement: keyAgreement, + assertionMethod: assertionMethod, + capabilityDelegation: capabilityDelegation + } +} diff --git a/code_examples/sdk_examples/src/v1/workshop/claimer/createClaim.ts b/code_examples/sdk_examples/src/v1/workshop/claimer/createClaim.ts new file mode 100644 index 000000000..fce9b1243 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/claimer/createClaim.ts @@ -0,0 +1,12 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +// Create a Claim object from light DID, CType and given content. +export function createClaim( + lightDid: Kilt.DidUri, + ctype: Kilt.ICType, + content: Kilt.IClaim['contents'] +): Kilt.IClaim { + const claim = Kilt.Claim.fromCTypeAndClaimContents(ctype, content, lightDid) + + return claim +} diff --git a/code_examples/sdk_examples/src/v1/workshop/claimer/createPresentation.ts b/code_examples/sdk_examples/src/v1/workshop/claimer/createPresentation.ts new file mode 100644 index 000000000..3c7001321 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/claimer/createPresentation.ts @@ -0,0 +1,14 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +export async function createPresentation( + credential: Kilt.ICredential, + signCallback: Kilt.SignCallback, + challenge?: string +): Promise { + // Create the presentation from credential, DID and challenge. + return Kilt.Credential.createPresentation({ + credential, + signCallback, + challenge + }) +} diff --git a/code_examples/sdk_examples/src/v1/workshop/claimer/generateAccount.ts b/code_examples/sdk_examples/src/v1/workshop/claimer/generateAccount.ts new file mode 100644 index 000000000..c1f48261b --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/claimer/generateAccount.ts @@ -0,0 +1,17 @@ +import { mnemonicGenerate } from '@polkadot/util-crypto' + +import * as Kilt from '@kiltprotocol/sdk-js' + +export function generateAccount(mnemonic = mnemonicGenerate()): { + account: Kilt.KiltKeyringPair + mnemonic: string +} { + const keyring = new Kilt.Utils.Keyring({ + ss58Format: 38, + type: 'sr25519' + }) + return { + account: keyring.addFromMnemonic(mnemonic) as Kilt.KiltKeyringPair, + mnemonic + } +} diff --git a/code_examples/sdk_examples/src/v1/workshop/claimer/generateCredential.ts b/code_examples/sdk_examples/src/v1/workshop/claimer/generateCredential.ts new file mode 100644 index 000000000..51236ab09 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/claimer/generateCredential.ts @@ -0,0 +1,46 @@ +import { config as envConfig } from 'dotenv' + +import * as Kilt from '@kiltprotocol/sdk-js' + +import { createClaim } from './createClaim' +import { generateLightDid } from './generateLightDid' +import { getCtypeSchema } from '../attester/ctypeSchema' + +export function generateCredential( + claimerDid: Kilt.DidUri, + claimAttributes: Kilt.IClaim['contents'] +): Kilt.ICredential { + // Create claim. + const ctype = getCtypeSchema() + const claim = createClaim(claimerDid, ctype, claimAttributes) + + // Create credential and request attestation. + console.log('Claimer -> create request') + return Kilt.Credential.fromClaim(claim) +} + +// Don't execute if this is imported by another file. +if (require.main === module) { + ;(async () => { + envConfig() + + try { + await Kilt.init() + + const claimerDidMnemonic = process.env.CLAIMER_DID_MNEMONIC as string + const claimerDid = generateLightDid(claimerDidMnemonic) + + const request = generateCredential(claimerDid.uri, { + age: 28, + name: 'Max Mustermann' + }) + console.log( + 'โš ๏ธ save this to ./claimer/_credential.json for testing โš ๏ธ\n\n' + ) + console.log(JSON.stringify(request, null, 2)) + } catch (e) { + console.log('Error while building credential') + throw e + } + })() +} diff --git a/code_examples/sdk_examples/src/v1/workshop/claimer/generateKeypairs.ts b/code_examples/sdk_examples/src/v1/workshop/claimer/generateKeypairs.ts new file mode 100644 index 000000000..7f3068459 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/claimer/generateKeypairs.ts @@ -0,0 +1,15 @@ +import * as Kilt from '@kiltprotocol/sdk-js' +import { mnemonicGenerate } from '@polkadot/util-crypto' + +export function generateKeypairs(mnemonic = mnemonicGenerate()) { + const authentication = Kilt.Utils.Crypto.makeKeypairFromUri(mnemonic) + + const keyAgreement = Kilt.Utils.Crypto.makeEncryptionKeypairFromSeed( + Kilt.Utils.Crypto.mnemonicToMiniSecret(mnemonic) + ) + + return { + authentication: authentication, + keyAgreement: keyAgreement + } +} diff --git a/code_examples/sdk_examples/src/v1/workshop/claimer/generateLightDid.ts b/code_examples/sdk_examples/src/v1/workshop/claimer/generateLightDid.ts new file mode 100644 index 000000000..f0dff4dda --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/claimer/generateLightDid.ts @@ -0,0 +1,33 @@ +import { config as envConfig } from 'dotenv' + +import { mnemonicGenerate } from '@polkadot/util-crypto' + +import * as Kilt from '@kiltprotocol/sdk-js' + +import { generateKeypairs } from './generateKeypairs' + +export function generateLightDid(mnemonic: string): Kilt.DidDocument { + const { authentication, keyAgreement } = generateKeypairs(mnemonic) + return Kilt.Did.createLightDidDocument({ + authentication: [authentication as Kilt.NewLightDidVerificationKey], + keyAgreement: [keyAgreement] + }) +} + +// Don't execute if this is imported by another file. +if (require.main === module) { + ;(async () => { + envConfig() + + try { + await Kilt.init() + + const mnemonic = mnemonicGenerate() + console.log('\nsave following to .env to continue\n') + console.log(`CLAIMER_DID_MNEMONIC="${mnemonic}"`) + } catch (e) { + console.log('Error while setting up claimer DID') + throw e + } + })() +} diff --git a/code_examples/sdk_examples/src/v1/workshop/index.ts b/code_examples/sdk_examples/src/v1/workshop/index.ts new file mode 100644 index 000000000..1dc8ff550 --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/index.ts @@ -0,0 +1,70 @@ +import * as Kilt from '@kiltprotocol/sdk-js' + +import { attestingFlow } from './attester/attestCredential' +import { createFullDid } from './attester/generateDid' +import { ensureStoredCtype } from './attester/generateCtype' +import { generateAccount } from './attester/generateAccount' +import { generateKeypairs as generateAttesterKeypairs } from './attester/generateKeypairs' +import { generateKeypairs as generateClaimerKeypairs } from './claimer/generateKeypairs' +import { generateCredential } from './claimer/generateCredential' +import { generateLightDid } from './claimer/generateLightDid' +import { getFunds } from '../getFunds' +import { verificationFlow } from './verify' + +export async function testWorkshop( + account: Kilt.KeyringPair, + wssAddress: string +) { + console.log('Running the workshop!') + + Kilt.ConfigService.set({ submitTxResolveOn: Kilt.Blockchain.IS_IN_BLOCK }) + await Kilt.connect(wssAddress) + + // Setup attester account. + const { account: attesterAccount } = await generateAccount() + + // Setup claimer & create a credential. + const claimerMnemonic = Kilt.Utils.Crypto.mnemonicGenerate() + const { authentication } = generateClaimerKeypairs(claimerMnemonic) + const lightDid = generateLightDid(claimerMnemonic) + + generateCredential(lightDid.uri, { + age: 27, + name: 'Karl' + }) + + await getFunds(account, attesterAccount.address, 5) + + // Create attester DID & ensure CType. + const { fullDid: attesterDid } = await createFullDid(attesterAccount) + const { assertionMethod } = generateAttesterKeypairs() + + await ensureStoredCtype( + attesterAccount, + attesterDid.uri, + async ({ data }) => ({ + signature: assertionMethod.sign(data), + keyType: assertionMethod.type + }) + ) + + // Do attestation & verification. + const credential = await attestingFlow( + lightDid.uri, + attesterAccount, + attesterDid.uri, + async ({ data }) => ({ + signature: assertionMethod.sign(data), + keyType: assertionMethod.type + }) + ) + await verificationFlow( + credential, + async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type, + keyUri: `${lightDid.uri}${lightDid.authentication[0].id}` + }), + [attesterDid.uri] + ) +} diff --git a/code_examples/sdk_examples/src/v1/workshop/verify.ts b/code_examples/sdk_examples/src/v1/workshop/verify.ts new file mode 100644 index 000000000..34de7fd9c --- /dev/null +++ b/code_examples/sdk_examples/src/v1/workshop/verify.ts @@ -0,0 +1,93 @@ +import { config as envConfig } from 'dotenv' + +import * as Kilt from '@kiltprotocol/sdk-js' + +import { createPresentation } from './claimer/createPresentation' +import { generateKeypairs } from './claimer/generateKeypairs' +import { generateLightDid } from './claimer/generateLightDid' + +function getChallenge(): string { + return Kilt.Utils.UUID.generate() +} + +// Verifies validity, ownership & attestation. +async function verifyPresentation( + presentation: Kilt.ICredentialPresentation, + challenge: string, + trustedAttesterUris: Kilt.DidUri[] +): Promise { + Kilt.ConfigService.get('api') + + try { + const { revoked, attester } = await Kilt.Credential.verifyPresentation( + presentation, + { challenge } + ) + + if (revoked) { + return false + } + // Returns true if no trusted attester URI is provided or, if it is, if it matches the one that issued the presented credential. + return trustedAttesterUris.includes(attester) + } catch { + return false + } +} + +export async function verificationFlow( + credential: Kilt.ICredential, + signCallback: Kilt.SignCallback, + trustedAttesterUris: Kilt.DidUri[] = [] +) { + // Verifier sends a unique challenge to the claimer ๐Ÿ•Š + const challenge = getChallenge() + + // Create a presentation and send it to the verifier ๐Ÿ•Š + const presentation = await createPresentation( + credential, + signCallback, + challenge + ) + + // The verifier checks the presentation. + const isValid = await verifyPresentation( + presentation, + challenge, + trustedAttesterUris + ) + + if (isValid) { + console.log('Verification successful! You are allowed to enter the club ๐ŸŽ‰') + } else { + console.log('Verification failed! ๐Ÿšซ') + } +} + +// Don't execute if this is imported by another file. +if (require.main === module) { + ;(async () => { + envConfig() + + try { + await Kilt.connect(process.env.WSS_ADDRESS as string) + const claimerDidMnemonic = process.env.CLAIMER_DID_MNEMONIC as string + const { authentication } = generateKeypairs(claimerDidMnemonic) + const claimerDid = generateLightDid(claimerDidMnemonic) + const attesterDid = process.env.ATTESTER_DID_URI as Kilt.DidUri + // Load credential and claimer DID + const credential = JSON.parse(process.env.CLAIMER_CREDENTIAL as string) + await verificationFlow( + credential, + async ({ data }) => ({ + signature: authentication.sign(data), + keyType: authentication.type, + keyUri: `${claimerDid.uri}${claimerDid.authentication[0].id}` + }), + [attesterDid] + ) + } catch (e) { + console.log('Error in the verification flow') + throw e + } + })() +} diff --git a/versioned_docs/version-1.0.0/develop/01_sdk/01_quickstart.md b/versioned_docs/version-1.0.0/develop/01_sdk/01_quickstart.md index 02bd1c8f5..7f31a6729 100644 --- a/versioned_docs/version-1.0.0/develop/01_sdk/01_quickstart.md +++ b/versioned_docs/version-1.0.0/develop/01_sdk/01_quickstart.md @@ -10,14 +10,14 @@ import TsJsBlock from '@site/src/components/TsJsBlock'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -import PrintHelloWorld from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/01_print_hello_world.ts'; -import ConnectSpirit from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/02_connect_spirit.ts'; -import ConnectPere from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/02_connect_pere.ts'; -import FetchDid from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/03_fetch_did.ts'; -import FetchEndpoints from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/04_fetch_endpoints.ts'; -import FetchEndpointData from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/05_fetch_endpoint_data.ts'; -import VerifyCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/06_verify_credential.ts'; -import Disconnect from '!!raw-loader!@site/code_examples/sdk_examples/src/core_features/getting_started/07_disconnect.ts'; +import PrintHelloWorld from '!!raw-loader!@site/code_examples/sdk_examples/src/v1/core_features/getting_started/01_print_hello_world.ts'; +import ConnectSpirit from '!!raw-loader!@site/code_examples/sdk_examples/src/v1/core_features/getting_started/02_connect_spirit.ts'; +import ConnectPere from '!!raw-loader!@site/code_examples/sdk_examples/src/v1//core_features/getting_started/02_connect_pere.ts'; +import FetchDid from '!!raw-loader!@site/code_examples/sdk_examples/src/v1/core_features/getting_started/03_fetch_did.ts'; +import FetchEndpoints from '!!raw-loader!@site/code_examples/sdk_examples/src/v1/core_features/getting_started/04_fetch_endpoints.ts'; +import FetchEndpointData from '!!raw-loader!@site/code_examples/sdk_examples/src/v1/core_features/getting_started/05_fetch_endpoint_data.ts'; +import VerifyCredential from '!!raw-loader!@site/code_examples/sdk_examples/src/v1/core_features/getting_started/06_verify_credential.ts'; +import Disconnect from '!!raw-loader!@site/code_examples/sdk_examples/src/v1/core_features/getting_started/07_disconnect.ts'; Get started with KILT by following this guide, which teaches you to: @@ -33,6 +33,41 @@ Basic knowledge of JavaScript and command-line tools is recommended. ::: +## Core Functions Explained + +Throughout this guide, we use several key functions from the KILT SDK: + +### Kilt.connect() +This function establishes a connection to a KILT blockchain node: +- Creates a WebSocket connection to the specified node +- Initializes the blockchain API interface +- Enables communication with the KILT network + +### Did.linkedInfoFromChain() +This function processes blockchain data to extract DID information: +- Takes encoded blockchain data as input +- Decodes the DID document information +- Returns the structured DID document with its identifier + +### Kilt.DidResolver.resolve() +The resolver function retrieves comprehensive DID information: +- Takes a DID identifier as input +- Queries the blockchain for the complete DID Document +- Returns service endpoints and other DID-related data +- Useful for finding where to query for credentials + +### Kilt.Verifier.verifyCredential() +This crucial function performs comprehensive credential verification: +- Validates the credential's cryptographic signatures +- Checks if the credential has been revoked +- Verifies the credential's format and structure +- Returns a verification result object with detailed status + +The verification result includes: +- `verified`: Boolean indicating overall validity +- Details about the verification process +- Any errors or issues encountered + ## Setup Create a new project and directory and move into the directory by running `mkdir kilt-rocks && cd kilt-rocks`. @@ -44,7 +79,7 @@ Inside the `kilt-rocks` project directory, install the **KILT SDK**, **Typescrip ```bash npm2yarn npm init -y -npm install @kiltprotocol/sdk-js ts-node typescript axios +npm install @kiltprotocol/sdk-js @kiltprotocol/did @kiltprotocol/credentials ts-node typescript axios ``` With the required dependencies installed, create a TypeScript file with `touch quickstart.ts`. @@ -56,7 +91,7 @@ From inside the `kilt-rocks` project directory, install the **KILT SDK**, **Node ```bash npm2yarn npm init -y -npm install @kiltprotocol/sdk-js node axios +npm install @kiltprotocol/sdk-js @kiltprotocol/did @kiltprotocol/credentials node axios ``` With the required dependencies installed, create a JavaScript file with `touch quickstart.js`. @@ -66,9 +101,7 @@ To enable ES modules in your project, add `"type": "module"` to the `package.jso -Declare an `async main` function in the `quickstart.ts` file that executes the rest of the code in this quickstart and call the `main()` function by default: - -{/* TODO: Do we need to test this or provide JS/TS equivalent? */} +Declare an `async main` function that executes the rest of the code in this quickstart: ```js async function main() { @@ -81,21 +114,22 @@ main() ### Import the KILT SDK -Begin by importing the **KILT SDK** and **Axios** at the top of the file: +Begin by importing the required packages. Each package serves a specific purpose: +- `@kiltprotocol/sdk-js`: Core SDK functionality for blockchain interaction +- `@kiltprotocol/did`: Handles DID (Decentralized Identifier) operations +- `@kiltprotocol/credentials`: Manages credential types and verification +- `axios`: Used for HTTP requests to credential endpoints ```js -import * as Kilt from '@kiltprotocol/sdk-js' -import axios from 'axios' +import * as Kilt from "@kiltprotocol/sdk-js"; +import axios from "axios"; +import * as Did from "@kiltprotocol/did"; +import { types } from "@kiltprotocol/credentials"; ``` -Now, you can access the SDK and all its functionality. -The next step is connecting to the **KILT blockchain**. - ### Connect to the KILT Blockchain -To perform operations that rely on the **KILT blockchain**, such as querying and verifying a credential, you must first connect to the **KILT blockchain**. - -Within the `main` function, configure the SDK to connect to a KILT node using the `Kilt.connect()` method: +To perform operations that rely on the **KILT blockchain**, first establish a connection that allows you to query the blockchain state and interact with smart contracts. @@ -120,49 +154,9 @@ Within the `main` function, configure the SDK to connect to a KILT node using th -To ensure proper cleanup, call the `Kilt.disconnect()` function at the bottom of the `main()` function. -You should add all other code before this function call: - - -{Disconnect} - - -By adding `await Kilt.disconnect()`, you ensure that the connection to the blockchain node is properly closed when the script finishes executing, which helps maintain the integrity of your application and is a good practice to follow. - -Run the code by calling the name of the file. -If you set up everything correctly, you should see no output showing that your code connected to the **KILT blockchain**. - - - - -```bash -yarn ts-node quickstart.ts -``` - - - - -```bash -node quickstart.js -``` - - - - -As you add to the code in this file, you can always run it with the same command. - -**Congratulations! ๐Ÿ”ฅ** - -You have connected to a KILT blockchain node. -The next step is to start querying data from the blockchain. - ## Query a KILT Identity -The following code queries information related to a **web3name** (`kiltnerd123`) and uses it to retrieve the **KILT DID** linked to it. - -Between the `Kilt.connect()` and `Kilt.disconnect()` lines, add the following code: +The following code demonstrates how to retrieve a DID associated with a web3name. Web3names are human-readable identifiers that map to DIDs on the KILT blockchain: {FetchEndpointData} -If the script completes without errors, you retrieved the published credential using the URL specified in the service. +Finally, verify the credential using KILT's verification system: -The next step is to make sure the credential is **valid** and has a valid **structure**. + +{VerifyCredential} + -The following code outputs a string depending on whether the credential is valid, revoked, or not valid. -Add it before `await Kilt.disconnect()`: +To ensure proper cleanup, make sure to disconnect at the end of your main function: -{VerifyCredential} +{Disconnect} -Run the code and wait to see if you can retrieve **and** verify one of kiltnerd123's credentials! +## Running the Code + + + + +```bash +yarn ts-node quickstart.ts +``` + + + + +```bash +node quickstart.js +``` + + + -:::info Next steps +:::info Next step - If you want to explore more of KILT's features, read our [Concepts section](../../concepts/01_what_is_kilt.md). - If you want to dive deeper into the SDK, read the next section, [the KILT Cookbook](./02_cookbook/01_dids/01_light_did_creation.md).