Skip to content

Commit

Permalink
Rework workshop to use new SDK methods (#306)
Browse files Browse the repository at this point in the history
* Draft

Signed-off-by: Chris Chinchilla <[email protected]>

* Factor into tests

Signed-off-by: Chris Chinchilla <[email protected]>

* Update docs

Signed-off-by: Chris Chinchilla <[email protected]>

* Lint

Signed-off-by: Chris Chinchilla <[email protected]>

* Draft

Signed-off-by: Chris Chinchilla <[email protected]>

* Lint

Signed-off-by: Chris Chinchilla <[email protected]>

* Update dependencies

Signed-off-by: Chris Chinchilla <[email protected]>

* Revert

Signed-off-by: Chris Chinchilla <[email protected]>

* Update docs

Signed-off-by: Chris Chinchilla <[email protected]>

* Respond to feedback

Signed-off-by: Chris Chinchilla <[email protected]>

* Draft

Signed-off-by: Chris Chinchilla <[email protected]>

* Test

Signed-off-by: Chris Chinchilla <[email protected]>

* Draft

Signed-off-by: Chris Chinchilla <[email protected]>

* Prettier

Signed-off-by: Chris Chinchilla <[email protected]>

* Fix mnemonic vs seed confusion

* Fixes!

Signed-off-by: Chris Chinchilla <[email protected]>

* Tweaks

Signed-off-by: Chris Chinchilla <[email protected]>

* Update code_examples/sdk_examples/src/workshop/attester/generateDid.ts

Co-authored-by: Raphael Flechtner <[email protected]>

* Respond to feedback

Signed-off-by: Chris Chinchilla <[email protected]>

* Update

Signed-off-by: Chris Chinchilla <[email protected]>

* Update docs/develop/03_workshop/04_attester/01_account.md

Co-authored-by: Raphael Flechtner <[email protected]>

* Remove defunct function

Signed-off-by: Chris Chinchilla <[email protected]>

---------

Signed-off-by: Chris Chinchilla <[email protected]>
Co-authored-by: Antonio Antonino <[email protected]>
Co-authored-by: Raphael Flechtner <[email protected]>
  • Loading branch information
3 people authored Apr 17, 2024
1 parent cbeda54 commit 3bc23e9
Show file tree
Hide file tree
Showing 17 changed files with 71 additions and 150 deletions.
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/* eslint-disable @typescript-eslint/no-unused-vars */

import { blake2AsHex } from '@polkadot/util-crypto'

import * as Kilt from '@kiltprotocol/sdk-js'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/* eslint-disable @typescript-eslint/no-unused-vars */

export function main(
submissions: Map<string, number>,
MAX_ACCEPTED_AGE: number
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Kilt.ICType> {
const {
creator,
Expand Down
14 changes: 3 additions & 11 deletions code_examples/sdk_examples/src/dapp/dapp/04_attest_credential.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import * as Kilt from '@kiltprotocol/sdk-js'

export async function main({
Expand All @@ -12,26 +13,17 @@ export async function main({
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 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')
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
6 changes: 2 additions & 4 deletions code_examples/sdk_examples/src/dapp/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
50 changes: 8 additions & 42 deletions code_examples/sdk_examples/src/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
const api = Kilt.ConfigService.get('api')

Expand All @@ -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...')
Expand All @@ -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<Kilt.ICredential> {
// First the claimer.
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
56 changes: 22 additions & 34 deletions code_examples/sdk_examples/src/workshop/attester/generateDid.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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')
Expand Down
5 changes: 2 additions & 3 deletions code_examples/sdk_examples/src/workshop/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions docs/concepts/07_dip/02_provider.md
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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<Self::RuntimeOrigin, Success = Self::CommitOrigin>`: The check ensuring a given runtime origin is allowed to generate and remove identity commitments.
* `type CommitOrigin: SubmitterInfo<Submitter = Self::AccountId>`: 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<Submitter = Self::AccountId>`: 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<Self>`: The type responsible for generating identity commitments, given the identity information associated to a given `Identifier`.
* `type IdentityProvider: IdentityProvider<Self>`: 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.
Expand Down
9 changes: 2 additions & 7 deletions docs/develop/03_workshop/04_attester/01_account.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
Loading

0 comments on commit 3bc23e9

Please sign in to comment.