public async Task <(CredentialIssueMessage, CredentialRecord)> CreateCredentialAsync(IAgentContext agentContext, string credentialId, IEnumerable <CredentialPreviewAttribute> values) { var credential = await GetAsync(agentContext, credentialId); if (credential.State != CredentialState.Requested) { throw new AgentFrameworkException(ErrorCode.RecordInInvalidState, $"Credential state was invalid. Expected '{CredentialState.Requested}', found '{credential.State}'"); } if (values != null && values.Any()) { credential.CredentialAttributesValues = values; } var definitionRecord = await SchemaService.GetCredentialDefinitionAsync(agentContext.Wallet, credential.CredentialDefinitionId); var connection = await ConnectionService.GetAsync(agentContext, credential.ConnectionId); var provisioning = await ProvisioningService.GetProvisioningAsync(agentContext.Wallet); if (connection.State != ConnectionState.Connected) { throw new AgentFrameworkException(ErrorCode.RecordInInvalidState, $"Connection state was invalid. Expected '{ConnectionState.Connected}', found '{connection.State}'"); } string revocationRegistryId = null; BlobStorageReader tailsReader = null; if (definitionRecord.SupportsRevocation) { var revocationRecordSearch = await RecordService.SearchAsync <RevocationRegistryRecord>( agentContext.Wallet, SearchQuery.Equal(nameof(RevocationRegistryRecord.CredentialDefinitionId), definitionRecord.Id), null, 5); var revocationRecord = revocationRecordSearch.Single(); // TODO: Credential definition can have multiple revocation registries revocationRegistryId = revocationRecord.Id; tailsReader = await TailsService.OpenTailsAsync(revocationRecord.TailsFile); } var issuedCredential = await AnonCreds.IssuerCreateCredentialAsync(agentContext.Wallet, credential.OfferJson, credential.RequestJson, CredentialUtils.FormatCredentialValues(credential.CredentialAttributesValues), revocationRegistryId, tailsReader); if (definitionRecord.SupportsRevocation) { var paymentInfo = await PaymentService.GetTransactionCostAsync(agentContext, TransactionTypes.REVOC_REG_ENTRY); await LedgerService.SendRevocationRegistryEntryAsync( wallet : agentContext.Wallet, pool : await agentContext.Pool, issuerDid : provisioning.IssuerDid, revocationRegistryDefinitionId : revocationRegistryId, revocationDefinitionType : "CL_ACCUM", value : issuedCredential.RevocRegDeltaJson, paymentInfo : paymentInfo); credential.CredentialRevocationId = issuedCredential.RevocId; if (paymentInfo != null) { await RecordService.UpdateAsync(agentContext.Wallet, paymentInfo.PaymentAddress); } } await credential.TriggerAsync(CredentialTrigger.Issue); await RecordService.UpdateAsync(agentContext.Wallet, credential); var threadId = credential.GetTag(TagConstants.LastThreadId); var credentialMsg = new CredentialIssueMessage { Credentials = new [] { new Attachment { Id = "libindy-cred-0", MimeType = CredentialMimeTypes.ApplicationJsonMimeType, Data = new AttachmentContent { Base64 = issuedCredential.CredentialJson .GetUTF8Bytes() .ToBase64String() } } } }; credentialMsg.ThreadFrom(threadId); return(credentialMsg, credential); }