Issuer Quickstart
Claims rely on the claim_id field as the primary binding agent for use of their relevant methods.
They should not be mistaken for attributes even though they bare a lot of similarities.
Introduction
Fundamentally, a claim can be thought of as a package of fields which are stored on the blockchain.
We call these fields attestations. For the Moonlight and Vivid usecase, each attestation reflects an
individual verified attribute on the platform making the relationship between attributes and claims
many x many. The relationship between attributes and attestations is one x many because you may have
multiple claims which are made against a single attribute. A good example of the one x many relationship
is someone undergoing two different verification workflows where each one verifies the individual’s name. In this scenario, each workflow would submit a unique claim. Each claim would have an attestation for the
verified name, which happens to be the same value.
Claims and Their Fields
{
"attestations": [
{
"encryption": //(enum) a number defining the encryption type of the value,
"remark": //(hexstring) an optional discription field for context,
"value": //(hexstring) a string formatted representation of the value,
}
],
"signed_by": //(pubkey) the public key of the claim author,
"signature": //(hexstring) signature of the attestations by the claim issuer,
"claim_id": //(hexstring) a uniqueidentifier for the claim,
"sub": //(pubkey) the subject of the claim,
"claim_topic": //(hexstring) the claim topic,
"expires": //(unixtimestamp) a timestamp indicating the claim expiration date,
"verification_uri": //(hexstring) an optional string for off-chain claim resources,
}
Install Asteroid SDK
npm install @moonlight-io/asteroid-sdk-js
go get github.com/Moonlight-io/asteroid-sdk-go
Retrieving a Claim
Because of the storage approach of Vivid, there are multiple ways to retrieve a raw claim
const neoCNS = "b434339f25b6f1bec68e99f620dfbf3ec27dacdc"
const network = {
name: "network",
extra: {
neoscan: "https://p1.neo.blockchain.moonlight.io:4001/api/main_net",
rpcServer: "https://p1.neo.blockchain.moonlight.io:60333"
}
}
//get the claims contract target
const neoClaimsContract = await sdk.NeoContractNameService.getAddress(network, neoCNS, "moonlight", "claims")
//get the claim by its ID
let claim = await sdk.NeoContractClaims.getClaimByClaimID(network, neoClaimsContract, "NLBnCtGcA6Gx4NJ8")
console.log("first res: ", claim)
//get the claim by its pointer
claim = await sdk.NeoContractClaims.getClaimByPointer(network, neoClaimsContract, 2)
console.log("second res: ", claim)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
first res: {
"claim_id": "NLBnCtGcA6Gx4NJ8",
"attestations": [
{
"remark": "",
"value": "6f2eaf3c9deefbb3fa61bf71427f6d0cce1e7e699409fb55e25634d1bac3c946",
"encryption": "symmetric_aes256"
}
],
"signed_by": "02498c5c154df8a2b26047a9205d1329aa0d626a1ef9185a7e3ae4993290905afd",
"signature": "f2adae922a028e346825890afba09c1e88ee2f5ae5be3187d3d908ee907d94f79d9c2821ac6a06bddef1c3ef7c281f29ee9c3688d662c093fc17203a69dabfb7",
"sub": "02e8a8ecfaebe8b3fe19debfbb35939a9ba8e440e718977d3bc390d8d7aa4c6210",
"claim_topic": "email",
"expires": "undefined",
"verification_uri": "https://app.moonlight.io"
}
second res: {
"claim_id": "NLBnCtGcA6Gx4NJ8",
"attestations": [
{
"remark": "",
"value": "6f2eaf3c9deefbb3fa61bf71427f6d0cce1e7e699409fb55e25634d1bac3c946",
"encryption": "symmetric_aes256"
}
],
"signed_by": "02498c5c154df8a2b26047a9205d1329aa0d626a1ef9185a7e3ae4993290905afd",
"signature": "f2adae922a028e346825890afba09c1e88ee2f5ae5be3187d3d908ee907d94f79d9c2821ac6a06bddef1c3ef7c281f29ee9c3688d662c093fc17203a69dabfb7",
"sub": "02e8a8ecfaebe8b3fe19debfbb35939a9ba8e440e718977d3bc390d8d7aa4c6210",
"claim_topic": "email",
"expires": "undefined",
"verification_uri": "https://app.moonlight.io"
}
//To Be Defined
Querying for the claim topic will return contextual information about the attestation payloads. Note that in the case of the claim in the example, the encryption is “1” (encoded to a string value by the sdk).
In order to use the attestation payload, we need a key which can be recovered from the identity’s keychain. To recover a key, refer to the keychain documentation.
A helper method is also available which can retrieve the claim and attempt to access the attestation payloads using the requestors key. It is used as follows:
const neoCNS = "b434339f25b6f1bec68e99f620dfbf3ec27dacdc"
const wif = "KxDgvEKzgSBPPfuVfw67oPQBSjidEiqTHURKSDL1R7yGaGYAeYnr"
const network = {
name: "network",
extra: {
neoscan: "https://p1.neo.blockchain.moonlight.io:4001/api/main_net",
rpcServer: "https://p1.neo.blockchain.moonlight.io:60333"
}
}
claim = await sdk.NeoVivid.getDecryptedClaimByClaimID(
network,
neoCNS,
"NLBnCtGcA6Gx4NJ8",
wif
)
console.log(claim)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
{
"claim_id": "NLBnCtGcA6Gx4NJ8",
"attestations": [
{
"remark": "",
"value": "6f2eaf3c9deefbb3fa61bf71427f6d0cce1e7e699409fb55e25634d1bac3c946",
"encryption": "symmetric_aes256",
"identifier": "email",
"decrypted_value": "[email protected]"
}
],
"signed_by": "02498c5c154df8a2b26047a9205d1329aa0d626a1ef9185a7e3ae4993290905afd",
"signature": "f2adae922a028e346825890afba09c1e88ee2f5ae5be3187d3d908ee907d94f79d9c2821ac6a06bddef1c3ef7c281f29ee9c3688d662c093fc17203a69dabfb7",
"sub": "02e8a8ecfaebe8b3fe19debfbb35939a9ba8e440e718977d3bc390d8d7aa4c6210",
"claim_topic": "email",
"expires": "undefined",
"verification_uri": "https://app.moonlight.io"
}
//To Be Defined
Issuing Claims
In order to issue a claim, the claim topic must already be issued to the claims contract. To create a claim topic, refer to the claim topic documentation. In the example below, we issue an email claim against an identity and also issue keys so the subject can access and share access to the attestations. In a typical workflow, we would also issue a key to the issuer so they can access the content they’ve generated.
const neoCNS = "b434339f25b6f1bec68e99f620dfbf3ec27dacdc"
const wif = "KxDgvEKzgSBPPfuVfw67oPQBSjidEiqTHURKSDL1R7yGaGYAeYnr"
const issuer = new neon.wallet.Account(wif);
const network = {
name: "network",
extra: {
neoscan: "https://p1.neo.blockchain.moonlight.io:4001/api/main_net",
rpcServer: "https://p1.neo.blockchain.moonlight.io:60333"
}
}
const rawClaim = {
sub: '029151b428cd17079bd1be8a1133874ecf4d323357b0372e5a467905a3fbb34e88',
claim_id: 'e2ji2Jut76VKem19',
claim_topic: 'email',
verification_uri: 'http://localhost:8000',
expires: 0,
attestations:
[ { identifier: 'EMAIL',
remark: '',
value: '[email protected]',
encryption: 'symmetric_aes256' } ]
}
//get the claims and identity contract targets
const neoClaimsContract = await sdk.NeoContractNameService.getAddress(network, neoCNS, "moonlight", "claims")
const neoIdentityContract = await sdk.NeoContractNameService.getAddress(network, neoCNS, "moonlight", "identity")
//build the secure claim
const secureClaim = sdk.NeoContractClaims.buildClaim(rawclaim, issuer.WIF)
//issue the claim
await sdk.NeoContractClaims.createClaim(network, newClaimsContract, secureClaim, issuer.WIF)
//issue keys to the claim subject for each attestation in the claim
for ( let i = 0; i < secureClaim.keys.length; i++ ) {
key = secureClaim.keys[i]
keySub = rawClaim.claim_id + ":" + i
await sdk.NeoContractIdentity.issueKey(
network,
neoIdentityContract,
rawClaim.sub,
issuer.publicKey,
keySub,
"proof",
Buffer.from(JSON.stringify(key)),
"holder_ecies",
issuer.WIF
)
//To Be Defined