๐งพ Attestation
In this section, your Attester will receive and process a Credential
where you'll
- Attest or deny it;
- Store the attestation information on the chain;
Attest a Credentialโ
The attestCredential
function loads the account and DID of the Attester.
When everything is prepared, we can issue an attestation for the credential we received from the Claimer.
The credential is considered to be valid from the time it is attested on chain until the time it is revoked.
- Typescript
- Javascript
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,
signCallback: Kilt.SignExtrinsicCallback
): Promise<void> {
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 = await Kilt.Did.authorizeTx(
attesterDid,
tx,
signCallback,
attesterAccount.address
)
// 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,
signCallback: Kilt.SignExtrinsicCallback
): Promise<Kilt.ICredential> {
// 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, signCallback)
// 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
}
})()
}
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,
attesterDid,
credential,
signCallback
) {
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 = await Kilt.Did.authorizeTx(
attesterDid,
tx,
signCallback,
attesterAccount.address
)
// 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,
attesterAccount,
attesterDid,
signCallback
) {
// 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, signCallback)
// 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)
const attesterAccountMnemonic = process.env.ATTESTER_ACCOUNT_MNEMONIC
const { account: attesterAccount } = generateAccount(
attesterAccountMnemonic
)
const attesterDidMnemonic = process.env.ATTESTER_DID_MNEMONIC
const { authentication, assertionMethod } =
generateKeypairs(attesterDidMnemonic)
const attesterDidUri = Kilt.Did.getFullDidUriFromKey(authentication)
const claimerDidMnemonic = process.env.CLAIMER_DID_MNEMONIC
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
}
})()
}
The function attestingFlow
shows the process from the beginning to the end.
First the Claimer generates the credential and sends it to the Attester.
After that the Attester checks the attributes and either attests or denies the attestation because the attributes are invalid.
Once the attestation is written on the chain, they can share all or part of the attested credentials with verifiers.
Runโ
Run it from command line:
- Typescript
- Javascript
yarn ts-node attester/attestCredential.ts
node attester/attestCredential.js
You can copy the Credential
object if you want to test with other Verifiers
in the workshop :-)
Your job as an Attester is done: you've successfully attested a credential and written the attestation hash onto the chain.
Let's move on to setup our Verifier!