OnChain Credential Status
On-chain identity verification requires the ability to check whether a credential has been revoked using a smart contract. To accomplish this, the credential should have the CredentialStatus
structure of type Iden3OnchainSparseMerkleTreeProof2023
and include a revocation nonce with information about the smart contract, such as its address, blockchain, and network.
The CredentialStatus
structure should contain the following fields:
type CredentialStatus struct {
ID string `json:"id"`
Type CredentialStatusType `json:"type"`
RevocationNonce uint64 `json:"revocationNonce"`
}
The ID
field is a composite field that contains encoded information in the following format:
did:[did-method]:[blockchain]:[network]:[id]/credentialStatus?(revocationNonce=value)&(contractAddress={chainID}:{contractAddress})
type
- credential type
revocationNonce
- unique revocation nonce
Example:
{
"id": "did:polygonid:polygon:main:2qCU58EJgrEMWhziKqC3qNXJkZPY8XCxDSBM4mqPkM/credentialStatus?revocationNonce=1234&contractAddress=1:0xf3bB959314B5D1e4587e1f597ccc289216608ac5",
"type": "Iden3OnchainSparseMerkleTreeProof2023",
"revocationNonce": "1234"
}
The revocationNonce
and contractAddress
parameters inside the ID field are optional. Here's an example without them:
{
"id": "did:polygonid:polygon:main:2qCU58EJgrEMWhziKqC3qNXJkZPY8XCxDSBM4mqPkM/credentialStatus",
"type": "Iden3OnchainSparseMerkleTreeProof2023",
"revocationNonce": "1234"
}
Process ID field
In the context of OnChainCredentialStatus
, the id
field can contain two additional optional parameters: revocationNonce
and contractAddress
.
revocationNonce
is a credential revocation nonce
, while contractAddress
is the address of a smart contract that implements an on-chain issuer interface. The contractAddress
field is composed by two parts: chainID
and contractAddress
. Use chainID
to select the correct network.
If contractAddress
is not set, find the default contract address by parsing DID extracting the on-chain issuer contract address and getting chainID
from the DID network. Use the blockchain name, network and contract address from the DID to make on-chain revocation request. If the DID doesn't have a contract address inside and contractAddress
parameter is empty, this VC document should be considered invalid.
If revocationNonce
is not set, the revocationNonce
value from the struct will be used instead.
Workflow
Example of how to build a non-revocation
proof with the Iden3OnchainSparseMerkleTreeProof2023
credential status type:
- Extract the
credentialStatus
object from the verifiable credential. - Parse core.DID from credentialStatus.id field with js|go
- Extract core.Id fome core.DID with js|go
-
Use the DID from step two to extract the on-chain issuer contract address:
a. If the
contractAddress
parameter is not empty, use this address to build the non-revocation proof.b. If the
contractAddress
is empty, extract the contract address from theid
field (refer to this code snippet).c. If the
id
doesn't have thecontractAddress
parameter, and you are not allowed to extract the contract address from theDID
, consider this VC document invalid. -
Extract
chainID
fromcontractAddress
parameter. IfchainID
does not exist - try to extractchainID
from DID. If both empty - return an error. -
Parse the
id
to obtain therevocationNonce
:a. You can extract the
revocationNonce
from theid
parameterrevocationNonce
.b. If the
id
doesn't have therevocationNonce
, you can get therevocationNonce
from therevocationNonce
field.c. If the parameter doesn't exist and the
revocationNonce
field is empty, consider this VC document invalid. -
Generate revocation proof call method
getRevocationStatus
from the issuer smart contract using the information you received earlier.
const response = await this.onchainContract.getRevocationStatus(id, nonce);
- Use this ABI to make getRevocationStatus call.
[
{
"inputs": [
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"internalType": "uint64",
"name": "nonce",
"type": "uint64"
}
],
"name": "getRevocationStatus",
"outputs": [
{
"components": [
{
"components": [
{
"internalType": "uint256",
"name": "state",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "claimsTreeRoot",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "revocationTreeRoot",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "rootOfRoots",
"type": "uint256"
}
],
"internalType": "struct IOnchainCredentialStatusResolver.IdentityStateRoots",
"name": "issuer",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "root",
"type": "uint256"
},
{
"internalType": "bool",
"name": "existence",
"type": "bool"
},
{
"internalType": "uint256[]",
"name": "siblings",
"type": "uint256[]"
},
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "bool",
"name": "auxExistence",
"type": "bool"
},
{
"internalType": "uint256",
"name": "auxIndex",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "auxValue",
"type": "uint256"
}
],
"internalType": "struct IOnchainCredentialStatusResolver.Proof",
"name": "mtp",
"type": "tuple"
}
],
"internalType": "struct IOnchainCredentialStatusResolver.CredentialStatus",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
}
]
Also, you can use the method ID of getRevocationStatus 0xeb62ed0e
instead of the ABI.