From 3bc23e93006b256a59241d212f4bbda2a037df1f Mon Sep 17 00:00:00 2001 From: Chris Chinchilla Date: Wed, 17 Apr 2024 18:38:53 +0200 Subject: [PATCH] Rework workshop to use new SDK methods (#306) * Draft Signed-off-by: Chris Chinchilla * Factor into tests Signed-off-by: Chris Chinchilla * Update docs Signed-off-by: Chris Chinchilla * Lint Signed-off-by: Chris Chinchilla * Draft Signed-off-by: Chris Chinchilla * Lint Signed-off-by: Chris Chinchilla * Update dependencies Signed-off-by: Chris Chinchilla * Revert Signed-off-by: Chris Chinchilla * Update docs Signed-off-by: Chris Chinchilla * Respond to feedback Signed-off-by: Chris Chinchilla * Draft Signed-off-by: Chris Chinchilla * Test Signed-off-by: Chris Chinchilla * Draft Signed-off-by: Chris Chinchilla * Prettier Signed-off-by: Chris Chinchilla * Fix mnemonic vs seed confusion * Fixes! Signed-off-by: Chris Chinchilla * Tweaks Signed-off-by: Chris Chinchilla * Update code_examples/sdk_examples/src/workshop/attester/generateDid.ts Co-authored-by: Raphael Flechtner <39338561+rflechtner@users.noreply.github.com> * Respond to feedback Signed-off-by: Chris Chinchilla * Update Signed-off-by: Chris Chinchilla * Update docs/develop/03_workshop/04_attester/01_account.md Co-authored-by: Raphael Flechtner <39338561+rflechtner@users.noreply.github.com> * Remove defunct function Signed-off-by: Chris Chinchilla --------- Signed-off-by: Chris Chinchilla Co-authored-by: Antonio Antonino Co-authored-by: Raphael Flechtner <39338561+rflechtner@users.noreply.github.com> --- .github/workflows/test.yml | 1 + .../messaging/_replay_protection_01.ts | 1 - .../messaging/_replay_protection_02.ts | 2 - .../messaging/_replay_protection_03.ts | 2 - .../src/core_features/signCallback/index.ts | 2 +- .../src/dapp/dapp/01_domain_linkage_ctype.ts | 2 +- .../src/dapp/dapp/04_attest_credential.ts | 14 +---- .../src/dapp/dapp/06_dapp_introduction.ts | 1 - code_examples/sdk_examples/src/dapp/index.ts | 6 +- code_examples/sdk_examples/src/test.ts | 50 +++-------------- .../src/workshop/attester/attestCredential.ts | 13 ++--- .../src/workshop/attester/generateAccount.ts | 2 +- .../src/workshop/attester/generateDid.ts | 56 ++++++++----------- .../sdk_examples/src/workshop/index.ts | 5 +- docs/concepts/07_dip/02_provider.md | 4 +- .../03_workshop/04_attester/01_account.md | 9 +-- .../develop/03_workshop/04_attester/02_did.md | 51 ++++++++--------- 17 files changed, 71 insertions(+), 150 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f9dc9cdac..ebf3ffd6e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,6 +44,7 @@ jobs: env: NODE_OPTIONS: --unhandled-rejections=strict BASE_MNEMONIC: ${{ secrets.BASE_MNEMONIC }} + FAUCET_SEED: ${{ secrets.FAUCET_SEED }} run: | yarn install --frozen-lockfile yarn test ${{ matrix.test_case }} diff --git a/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_01.ts b/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_01.ts index b5a28ca38..a87e21a4f 100644 --- a/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_01.ts +++ b/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_01.ts @@ -1,5 +1,4 @@ /* 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 diff --git a/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_02.ts b/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_02.ts index 9549f1ab2..e305c48ab 100644 --- a/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_02.ts +++ b/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_02.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ - import { blake2AsHex } from '@polkadot/util-crypto' import * as Kilt from '@kiltprotocol/sdk-js' diff --git a/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_03.ts b/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_03.ts index 8dc8bbafb..237a98de1 100644 --- a/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_03.ts +++ b/code_examples/sdk_examples/src/core_features/messaging/_replay_protection_03.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ - export function main( submissions: Map, MAX_ACCEPTED_AGE: number diff --git a/code_examples/sdk_examples/src/core_features/signCallback/index.ts b/code_examples/sdk_examples/src/core_features/signCallback/index.ts index da9341892..9d68391a8 100644 --- a/code_examples/sdk_examples/src/core_features/signCallback/index.ts +++ b/code_examples/sdk_examples/src/core_features/signCallback/index.ts @@ -5,8 +5,8 @@ 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 -// eslint-disable-next-line @typescript-eslint/no-unused-vars export function lookupDidKeyPair( + // eslint-disable-next-line @typescript-eslint/no-unused-vars _keyUri: Kilt.DidResourceUri ): Kilt.KiltKeyringPair { return Kilt.Utils.Crypto.makeKeypairFromSeed() diff --git a/code_examples/sdk_examples/src/dapp/dapp/01_domain_linkage_ctype.ts b/code_examples/sdk_examples/src/dapp/dapp/01_domain_linkage_ctype.ts index 1d9df6ada..818f2b429 100644 --- a/code_examples/sdk_examples/src/dapp/dapp/01_domain_linkage_ctype.ts +++ b/code_examples/sdk_examples/src/dapp/dapp/01_domain_linkage_ctype.ts @@ -1,6 +1,6 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ import * as Kilt from '@kiltprotocol/sdk-js' -/* eslint-disable @typescript-eslint/no-unused-vars */ export async function main(): Promise { const { creator, diff --git a/code_examples/sdk_examples/src/dapp/dapp/04_attest_credential.ts b/code_examples/sdk_examples/src/dapp/dapp/04_attest_credential.ts index 46d758ce2..6d76666cb 100644 --- a/code_examples/sdk_examples/src/dapp/dapp/04_attest_credential.ts +++ b/code_examples/sdk_examples/src/dapp/dapp/04_attest_credential.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ import * as Kilt from '@kiltprotocol/sdk-js' export async function main({ @@ -12,7 +13,6 @@ export async function main({ domainLinkageCredential: Kilt.ICredential }) { const api = Kilt.ConfigService.get('api') - const { cTypeHash, claimHash } = Kilt.Attestation.fromCredentialAndDid( domainLinkageCredential, didUri @@ -20,18 +20,10 @@ export async function main({ const attestationTx = api.tx.attestation.add(claimHash, cTypeHash, null) // We authorize the call using the attestation key of the Dapps DID. - const submitTx = await Kilt.Did.authorizeTx( - didUri, - attestationTx, - async ({ data }) => ({ - signature: assertionMethodKey.sign(data), - keyType: assertionMethodKey.type - }), - dappAccount.address - ) + 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(submitTx, dappAccount) + const result = await Kilt.Blockchain.signAndSubmitTx(extrinsic, dappAccount) if (result.isError) { console.log('Attestation failed') diff --git a/code_examples/sdk_examples/src/dapp/dapp/06_dapp_introduction.ts b/code_examples/sdk_examples/src/dapp/dapp/06_dapp_introduction.ts index 4a6212224..b2a20dcef 100644 --- a/code_examples/sdk_examples/src/dapp/dapp/06_dapp_introduction.ts +++ b/code_examples/sdk_examples/src/dapp/dapp/06_dapp_introduction.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ import * as Kilt from '@kiltprotocol/sdk-js' // `window` object: Should be used only in the following example. diff --git a/code_examples/sdk_examples/src/dapp/index.ts b/code_examples/sdk_examples/src/dapp/index.ts index 4ad3f5937..f5afed159 100644 --- a/code_examples/sdk_examples/src/dapp/index.ts +++ b/code_examples/sdk_examples/src/dapp/index.ts @@ -21,10 +21,8 @@ export async function testDapp(account: Kilt.KeyringPair, wssAddress: string) { await getFunds(account, dappAccount.address, 4) // Create attester DID & ensure CType. - const { fullDid: attesterDid, mnemonic: attesterMnemonic } = - await createFullDid(dappAccount) - const { assertionMethod: assertionMethodKey } = - generateAttesterKeypairs(attesterMnemonic) + const { fullDid: attesterDid } = await createFullDid(dappAccount) + const { assertionMethod: assertionMethodKey } = generateAttesterKeypairs() const domainLinkageCType = await getDomainLinkageCType() const { domainLinkageCredential } = getDomainLinkageCredential({ diff --git a/code_examples/sdk_examples/src/test.ts b/code_examples/sdk_examples/src/test.ts index 30e19597f..10c71b2b5 100644 --- a/code_examples/sdk_examples/src/test.ts +++ b/code_examples/sdk_examples/src/test.ts @@ -8,10 +8,6 @@ import { testCoreFeatures } from './core_features' import { testDapp } from './dapp' import { testStaking } from './staking' import { testWorkshop } from './workshop' - -const MNEMONIC_ENV = 'BASE_MNEMONIC' -const FAUCET_SEED_ENV = 'FAUCET_SEED' - ;(async () => { const whichToRun = { workshop: false, @@ -57,48 +53,18 @@ const FAUCET_SEED_ENV = 'FAUCET_SEED' envConfig() await Kilt.init() - const wssAddress = process.env.WSS_ADDRESS || 'wss://peregrine.kilt.io' - const mnemonic = process.env[MNEMONIC_ENV] - const faucetSeed = process.env[FAUCET_SEED_ENV] - - let baseAccountStrategy: 'base-mnemonic' | 'faucet-seed' = 'base-mnemonic' - - // Faucet seed only a fallback if mnemonic is not specified. Otherwise mnemonic always wins. - if (!mnemonic && faucetSeed) { - baseAccountStrategy = 'faucet-seed' - } else if (!mnemonic && !faucetSeed) { - console.log( - `Neither base mnemonic "${MNEMONIC_ENV}" nor faucet seed "${FAUCET_SEED_ENV}" have been specified. - Please specify at least one of them.` - ) - throw new Error('Account mnemonic or faucet seed is missing.') - } + const faucetSeed = process.env.FAUCET_SEED let [workshopAccount, dappAccount, coreAccount] = new Array(3) - switch (baseAccountStrategy) { - case 'base-mnemonic': { - const baseAccount = new Kilt.Utils.Keyring({ - type: 'sr25519', - ss58Format: Kilt.Utils.ss58Format - }).addFromMnemonic(mnemonic as string) - workshopAccount = baseAccount.derive('//workshop') - dappAccount = baseAccount.derive('//dapp') - coreAccount = baseAccount.derive('//core') - - break - } - case 'faucet-seed': { - const faucetAccount = Kilt.Utils.Crypto.makeKeypairFromSeed( - hexToU8a(faucetSeed), - 'sr25519' - ) as Kilt.KeyringPair - workshopAccount = faucetAccount - dappAccount = faucetAccount - coreAccount = faucetAccount - } - } + 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 { diff --git a/code_examples/sdk_examples/src/workshop/attester/attestCredential.ts b/code_examples/sdk_examples/src/workshop/attester/attestCredential.ts index 0344f8a82..ad4474641 100644 --- a/code_examples/sdk_examples/src/workshop/attester/attestCredential.ts +++ b/code_examples/sdk_examples/src/workshop/attester/attestCredential.ts @@ -10,8 +10,7 @@ import { generateLightDid } from '../claimer/generateLightDid' export async function attestCredential( attesterAccount: Kilt.KiltKeyringPair, attesterDid: Kilt.DidUri, - credential: Kilt.ICredential, - signCallback: Kilt.SignExtrinsicCallback + credential: Kilt.ICredential ): Promise { const api = Kilt.ConfigService.get('api') @@ -23,12 +22,7 @@ export async function attestCredential( // Create the tx and authorize it. const tx = api.tx.attestation.add(claimHash, cTypeHash, null) - const extrinsic = await Kilt.Did.authorizeTx( - attesterDid, - tx, - signCallback, - attesterAccount.address - ) + const extrinsic = api.tx.did.dispatchAs(attesterAccount.address, tx) // Submit the tx to write the attestation to the chain. console.log('Attester -> create attestation...') @@ -39,6 +33,7 @@ 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. @@ -50,7 +45,7 @@ export async function attestingFlow( // ... send the request to the attester // The attester checks the attributes and attests the provided credential. - await attestCredential(attesterAccount, attesterDid, credential, signCallback) + await attestCredential(attesterAccount, attesterDid, credential) // Return the generated credential. return credential diff --git a/code_examples/sdk_examples/src/workshop/attester/generateAccount.ts b/code_examples/sdk_examples/src/workshop/attester/generateAccount.ts index 02da570b3..74e647445 100644 --- a/code_examples/sdk_examples/src/workshop/attester/generateAccount.ts +++ b/code_examples/sdk_examples/src/workshop/attester/generateAccount.ts @@ -5,7 +5,7 @@ import * as Kilt from '@kiltprotocol/sdk-js' export function generateAccount( mnemonic = Kilt.Utils.Crypto.mnemonicGenerate() ): { - account: Kilt.KiltKeyringPair + account: Kilt.KiltKeyringPair & { type: 'ed25519' } mnemonic: string } { return { diff --git a/code_examples/sdk_examples/src/workshop/attester/generateDid.ts b/code_examples/sdk_examples/src/workshop/attester/generateDid.ts index e0c900c78..54557bcef 100644 --- a/code_examples/sdk_examples/src/workshop/attester/generateDid.ts +++ b/code_examples/sdk_examples/src/workshop/attester/generateDid.ts @@ -1,51 +1,40 @@ -import { config as envConfig } from 'dotenv' - import * as Kilt from '@kiltprotocol/sdk-js' - +import { config as envConfig } from 'dotenv' import { generateAccount } from './generateAccount' -import { generateKeypairs } from './generateKeypairs' export async function createFullDid( - submitterAccount: Kilt.KiltKeyringPair + creatorAccount: Kilt.KiltKeyringPair & { + type: 'ed25519' | 'sr25519' | 'ecdsa' + } ): Promise<{ - mnemonic: string fullDid: Kilt.DidDocument }> { const api = Kilt.ConfigService.get('api') - const mnemonic = Kilt.Utils.Crypto.mnemonicGenerate() - const { - authentication, - keyAgreement, - assertionMethod, - capabilityDelegation - } = generateKeypairs(mnemonic) - // Get tx that will create the DID on chain and DID-URI that can be used to resolve the DID Document. - const fullDidCreationTx = await Kilt.Did.getStoreTx( - { - authentication: [authentication], - keyAgreement: [keyAgreement], - assertionMethod: [assertionMethod], - capabilityDelegation: [capabilityDelegation] - }, - submitterAccount.address, - async ({ data }) => ({ - signature: authentication.sign(data), - keyType: authentication.type - }) - ) + const verificationMethod = Kilt.Did.publicKeyToChain(creatorAccount) - await Kilt.Blockchain.signAndSubmitTx(fullDidCreationTx, submitterAccount) + const txs = [ + api.tx.did.createFromAccount(verificationMethod), + api.tx.did.dispatchAs( + creatorAccount.address, + api.tx.did.setAttestationKey(verificationMethod) + ) + ] - const didUri = Kilt.Did.getFullDidUriFromKey(authentication) + 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 } = Kilt.Did.linkedInfoFromChain(encodedFullDid) + const { document: didDocument } = Kilt.Did.linkedInfoFromChain(encodedFullDid) - if (!document) { + if (!didDocument) { throw new Error('Full DID was not successfully created.') } - return { mnemonic, fullDid: document } + return { fullDid: didDocument } } // Don't execute if this is imported by another file. @@ -59,10 +48,9 @@ if (require.main === module) { // Load attester account const accountMnemonic = process.env.ATTESTER_ACCOUNT_MNEMONIC as string const { account } = generateAccount(accountMnemonic) - const { mnemonic, fullDid } = await createFullDid(account) + const { fullDid } = await createFullDid(account) console.log('\nsave following to .env to continue\n') - console.error(`ATTESTER_DID_MNEMONIC="${mnemonic}"\n`) console.error(`ATTESTER_DID_URI="${fullDid.uri}"\n`) } catch (e) { console.log('Error while creating attester DID') diff --git a/code_examples/sdk_examples/src/workshop/index.ts b/code_examples/sdk_examples/src/workshop/index.ts index 5a868b865..1dc8ff550 100644 --- a/code_examples/sdk_examples/src/workshop/index.ts +++ b/code_examples/sdk_examples/src/workshop/index.ts @@ -36,9 +36,8 @@ export async function testWorkshop( await getFunds(account, attesterAccount.address, 5) // Create attester DID & ensure CType. - const { fullDid: attesterDid, mnemonic: attesterMnemonic } = - await createFullDid(attesterAccount) - const { assertionMethod } = generateAttesterKeypairs(attesterMnemonic) + const { fullDid: attesterDid } = await createFullDid(attesterAccount) + const { assertionMethod } = generateAttesterKeypairs() await ensureStoredCtype( attesterAccount, diff --git a/docs/concepts/07_dip/02_provider.md b/docs/concepts/07_dip/02_provider.md index 0b384009e..1803e52dd 100644 --- a/docs/concepts/07_dip/02_provider.md +++ b/docs/concepts/07_dip/02_provider.md @@ -1,4 +1,4 @@ -# Decentralized Identity Provider (DIP) provider pallet +# 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. @@ -21,7 +21,7 @@ After removal, the identity becomes unusable cross-chain, although it will still 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 with errors. The origin is not required to be an `AccountId`, but must include information about the `AccountId` of the tx submitter. +* `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. diff --git a/docs/develop/03_workshop/04_attester/01_account.md b/docs/develop/03_workshop/04_attester/01_account.md index baf89e28e..e2710f623 100644 --- a/docs/develop/03_workshop/04_attester/01_account.md +++ b/docs/develop/03_workshop/04_attester/01_account.md @@ -66,14 +66,9 @@ The `generateAccount` method returns an object with the following two properties 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 with the following parameters: +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. - 1. `ss58Format`: Specifies the encoding format for the key. Substrate-based blockchains commonly use [SS58](https://docs.substrate.io/reference/address-formats/). - The value `38` represents the KILT blockchain prefix. - 2. `type`: Specifies the user's cryptographic algorithm. - Substrate-based blockchains commonly use sr25519. - - The function then returns the value using the `addFromMnemonic()` method to create a key pair for the address using the given mnemonic. +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. diff --git a/docs/develop/03_workshop/04_attester/02_did.md b/docs/develop/03_workshop/04_attester/02_did.md index bc294b575..dc44f932a 100644 --- a/docs/develop/03_workshop/04_attester/02_did.md +++ b/docs/develop/03_workshop/04_attester/02_did.md @@ -5,6 +5,7 @@ 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'; @@ -26,12 +27,12 @@ Other users can now encrypt messages using your public encryption key and send a Kilt supports two DID types: **light** and **full**. -There are many 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. +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 -There are four different key types that a DID supports: +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 @@ -58,43 +59,34 @@ In summary, you register a DID on the blockchain by an account submitting the DI As an Attester needs to interact with the chain, you must create a full DID. -### Generate key pairs - -An Attester needs an authentication and attestation key at minimum. -Since three of the key types sign transactions, you can use the same key for them using the default KILT keyring to generate them, which is the same keyring used to generate accounts. - -Add the following code to the `attester/generateKeypairs` file. - - - {GenerateKeypairs} - +### Write DID to chain -Throughout the code are `account.derive` methods that use key derivation syntax. You can read more about this syntax in [the Substrate documentation](https://docs.substrate.io/reference/command-line-tools/subkey/#working-with-derived-keys). +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. -The `generateKeypairs` function code derives base and sub keys from a particular path relevant to the use case for each key. -It uses the sr25519 key type, which is the default key type for KILT. + + -This method works for three of the four key types needed, so the `generateKeyAgreement` function helps generate the key-agreement key pair using the mnemonic. -The function takes the mnemonic and creates another key pair from it using the `sr25519PairFromSeed(mnemonicToMiniSecret(mnemonic))` combination of functions. -The function then creates a secret key based on the earlier temporary key pair and a derivation path relevant to key agreement. +:::info Bring your own account -The function returns the key pair needed by generating one more key pair suitable for encryption and decryption using the secret key. +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. -### Write DID to chain +::: -Once you have created all the necessary keys for a DID, you can create the on-chain DID. -To create a DID, load the account created in the [last section](./01_account.md) and use it to pay for the DID registration. Create and submit the extrinsic (aka transaction) that registers the DID. {GenerateDid} -The `createFullDid` function takes the key pair generated for the submitter in the previous step and creates a full DID. It returns a mnemonic as a string and DID document. -Inside the function, the `getStoreTx` method creates a DID creation operation based on the four key pairs created earlier. -It returns the extrinsic (aka transaction) that registers the DID. +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. -The `signAndSubmitTx` method takes that extrinsic and submits it to the chain, also passing the submitter's account. +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 @@ -117,15 +109,16 @@ Now run the code with: -Once you have run the script, the output should provide you with your `ATTESTER_DID_MNEMONIC` and `ATTESTER_DID_URI`. -The output should look like the following, but not identical since the DIDs are constructed from your account: +Once you have run the script, the output should provide you with the `ATTESTER_DID_MNEMONIC` and `ATTESTER_DID_URI`. + +The output should look like the following, but not identical since the code creates the DIDs from your account: ``` ATTESTER_DID_MNEMONIC="beyond large galaxy… ATTESTER_DID_URI="did:kilt:4ohMvUHsyeD…" ``` -Save it in the `.env` file, which should now look like the following: +Save the values in the `.env` file, which should now look like the following: ```env title=".env" WSS_ADDRESS=wss://peregrine.kilt.io