/// <inheritdoc />
        public async Task OnMessageAsync(IAgentContext agentContext, UnpackedMessageContext messageContext)
        {
            var message          = messageContext.GetMessage <AnyAgentMessage>();
            var requestDecorator = message.FindDecorator <PaymentRequestDecorator>("payment_request");

            if (requestDecorator != null)
            {
                var record = new PaymentRecord
                {
                    ConnectionId = messageContext.Connection.Id,
                    Details      = requestDecorator.Details,
                    ReferenceId  = requestDecorator.Details.Id,
                    Address      = requestDecorator.Method.Data.PayeeId,
                    Amount       = requestDecorator.Details.Total.Amount.Value
                };
                await record.TriggerAsync(PaymentTrigger.RequestReceived);

                await _recordService.AddAsync(agentContext.Wallet, record);

                if (messageContext.ContextRecord != null)
                {
                    messageContext.ContextRecord.SetTag("PaymentRecordId", record.Id);
                    await _recordService.UpdateAsync(agentContext.Wallet, messageContext.ContextRecord);
                }
            }

            var receiptDecorator = message.FindDecorator <PaymentReceiptDecorator>("payment_receipt");

            if (receiptDecorator != null)
            {
                var search = await _recordService.SearchAsync <PaymentRecord>(
                    wallet : agentContext.Wallet,
                    query : SearchQuery.Equal(nameof(PaymentRecord.ReferenceId), receiptDecorator.RequestId),
                    options : null,
                    count : 5);

                var record = search.FirstOrDefault() ?? new PaymentRecord();
                record.ReceiptId = receiptDecorator.TransactionId;

                await record.TriggerAsync(PaymentTrigger.ReceiptReceived);

                if (search.Any())
                {
                    await _recordService.UpdateAsync(agentContext.Wallet, record);
                }
                else
                {
                    await _recordService.AddAsync(agentContext.Wallet, record);
                }
            }
        }
        public async Task <PaymentRecord> AttachPaymentRequestAsync(IAgentContext context, AgentMessage agentMessage, PaymentDetails details, PaymentAddressRecord addressRecord = null)
        {
            // TODO: Add validation

            var paymentRecord = new PaymentRecord
            {
                Address = addressRecord.Address,
                Method  = "sov",
                Amount  = details.Total.Amount.Value,
                Details = details
            };

            details.Id = details.Id ?? paymentRecord.Id;
            paymentRecord.ReferenceId = details.Id;

            await paymentRecord.TriggerAsync(PaymentTrigger.RequestSent);

            await recordService.AddAsync(context.Wallet, paymentRecord);



            agentMessage.AddDecorator(new PaymentRequestDecorator
            {
                Method = new PaymentMethod
                {
                    SupportedMethods = "sov",
                    Data             = new PaymentMethodData
                    {
                        PayeeId           = addressRecord.Address,
                        SupportedNetworks = new[] { "Sovrin MainNet" }
                    }
                },
                Details = details
            }, "payment_request");

            return(paymentRecord);
        }
        /// <inheritdoc />
        public async Task MakePaymentAsync(IAgentContext agentContext, PaymentRecord paymentRecord,
                                           PaymentAddressRecord addressFromRecord = null)
        {
            if (paymentRecord.Amount == 0)
            {
                throw new AgentFrameworkException(ErrorCode.InvalidRecordData, "Cannot make a payment with 0 amount");
            }

            await paymentRecord.TriggerAsync(PaymentTrigger.ProcessPayment);

            if (paymentRecord.Address == null)
            {
                throw new AgentFrameworkException(ErrorCode.InvalidRecordData, "Payment record is missing an address");
            }

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

            if (addressFromRecord == null)
            {
                addressFromRecord = await GetDefaultPaymentAddressAsync(agentContext);
            }

            await RefreshBalanceAsync(agentContext, addressFromRecord);

            if (addressFromRecord.Balance < paymentRecord.Amount)
            {
                throw new AgentFrameworkException(ErrorCode.PaymentInsufficientFunds,
                                                  "Address doesn't have enough funds to make this payment");
            }
            var txnFee = await GetTransactionFeeAsync(agentContext, TransactionTypes.XFER_PUBLIC);

            var paymentResult = await IndyPayments.BuildPaymentRequestAsync(
                wallet : agentContext.Wallet,
                submitterDid : null,
                inputsJson : addressFromRecord.Sources.Select(x => x.Source).ToJson(),
                outputsJson : new[]
            {
                new IndyPaymentOutputSource
                {
                    Amount    = paymentRecord.Amount,
                    Recipient = paymentRecord.Address
                },
                new IndyPaymentOutputSource
                {
                    Recipient = addressFromRecord.Address,
                    Amount    = addressFromRecord.Balance - paymentRecord.Amount - txnFee
                }
            }.ToJson(),
                extra : null);

            var response = await Ledger.SignAndSubmitRequestAsync(await agentContext.Pool, agentContext.Wallet,
                                                                  provisioning.Endpoint.Did, paymentResult.Result);

            var paymentResponse = await IndyPayments.ParsePaymentResponseAsync(TokenConfiguration.MethodName, response);

            var paymentOutputs = paymentResponse.ToObject <IList <IndyPaymentOutputSource> >();
            var paymentOutput  = paymentOutputs.SingleOrDefault(x => x.Recipient == paymentRecord.Address);

            paymentRecord.ReceiptId   = paymentOutput.Receipt;
            addressFromRecord.Sources = paymentOutputs
                                        .Where(x => x.Recipient == addressFromRecord.Address)
                                        .Select(x => new IndyPaymentInputSource
            {
                Amount         = x.Amount,
                PaymentAddress = x.Recipient,
                Source         = x.Receipt
            })
                                        .ToList();

            await recordService.UpdateAsync(agentContext.Wallet, paymentRecord);

            await recordService.UpdateAsync(agentContext.Wallet, addressFromRecord);
        }