/// <inheritdoc />
        public virtual async Task <string> ProcessOfferAsync(IAgentContext agentContext, CredentialOfferMessage credentialOffer,
                                                             ConnectionRecord connection)
        {
            var offerAttachment = credentialOffer.Offers.FirstOrDefault(x => x.Id == "libindy-cred-offer-0")
                                  ?? throw new ArgumentNullException(nameof(CredentialOfferMessage.Offers));

            var offerJson    = offerAttachment.Data.Base64.GetBytesFromBase64().GetUTF8String();
            var offer        = JObject.Parse(offerJson);
            var definitionId = offer["cred_def_id"].ToObject <string>();
            var schemaId     = offer["schema_id"].ToObject <string>();

            var threadId = credentialOffer.GetThreadId() ?? Guid.NewGuid().ToString();
            // Write offer record to local wallet
            var credentialRecord = new CredentialRecord
            {
                Id                         = threadId,
                OfferJson                  = offerJson,
                ConnectionId               = connection?.Id,
                CredentialDefinitionId     = definitionId,
                CredentialAttributesValues = credentialOffer.CredentialPreview?.Attributes
                                             .Select(x => new CredentialPreviewAttribute
                {
                    Name     = x.Name,
                    MimeType = x.MimeType,
                    Value    = x.Value
                }).ToArray(),
                SchemaId = schemaId,
                State    = CredentialState.Offered
            };

            credentialRecord.SetTag(TagConstants.Role, TagConstants.Holder);
            credentialRecord.SetTag(TagConstants.LastThreadId, threadId);

            await RecordService.AddAsync(agentContext.Wallet, credentialRecord);

            EventAggregator.Publish(new ServiceMessageProcessingEvent
            {
                RecordId    = credentialRecord.Id,
                MessageType = credentialOffer.Type,
                ThreadId    = threadId
            });

            return(credentialRecord.Id);
        }
        /// <inheritdoc />
        public async Task <CredentialRecord> CreateCredentialAsync(IAgentContext agentContext, CredentialOfferMessage message)
        {
            var service            = message.GetDecorator <ServiceDecorator>(DecoratorNames.ServiceDecorator);
            var credentialRecordId = await ProcessOfferAsync(agentContext, message, null);

            var(request, record) = await CreateRequestAsync(agentContext, credentialRecordId);

            var provisioning = await ProvisioningService.GetProvisioningAsync(agentContext.Wallet);

            var credentialIssueMessage = await MessageService.SendReceiveAsync <CredentialIssueMessage>(
                wallet : agentContext.Wallet,
                message : request,
                recipientKey : service.RecipientKeys.First(),
                endpointUri : service.ServiceEndpoint,
                routingKeys : service.RoutingKeys.ToArray(),
                senderKey : provisioning.IssuerVerkey);

            var recordId = await ProcessCredentialAsync(agentContext, credentialIssueMessage, null);

            return(await RecordService.GetAsync <CredentialRecord>(agentContext.Wallet, recordId));
        }