/// <inheritdoc />
        public async Task RefreshBalanceAsync(IAgentContext agentContext, PaymentAddressRecord paymentAddress = null)
        {
            if (paymentAddress == null)
            {
                var provisioning = await provisioningService.GetProvisioningAsync(agentContext.Wallet);

                if (provisioning.DefaultPaymentAddressId == null)
                {
                    throw new AgentFrameworkException(ErrorCode.RecordNotFound, "Default PaymentAddressRecord not found");
                }

                paymentAddress = await recordService.GetAsync <PaymentAddressRecord>(agentContext.Wallet, provisioning.DefaultPaymentAddressId);
            }

            // Cache sources data in record for one hour
            var request = await IndyPayments.BuildGetPaymentSourcesAsync(agentContext.Wallet, null, paymentAddress.Address);

            var response = await Ledger.SubmitRequestAsync(await agentContext.Pool, request.Result);

            var sourcesJson = await Indy.Payments.ParseGetPaymentSourcesAsync(paymentAddress.Method, response);

            var sources = sourcesJson.ToObject <IList <IndyPaymentInputSource> >();

            paymentAddress.Sources         = sources;
            paymentAddress.SourcesSyncedAt = DateTime.Now;

            await recordService.UpdateAsync(agentContext.Wallet, paymentAddress);
        }
        /// <inheritdoc />
        public async Task SetDefaultPaymentAddressAsync(IAgentContext agentContext, PaymentAddressRecord addressRecord)
        {
            var provisioning = await provisioningService.GetProvisioningAsync(agentContext.Wallet);

            provisioning.DefaultPaymentAddressId = addressRecord.Id;

            await recordService.UpdateAsync(agentContext.Wallet, provisioning);
        }
        /// <inheritdoc />
        public async Task <PaymentAddressRecord> CreatePaymentAddressAsync(IAgentContext agentContext, AddressOptions configuration = null)
        {
            var address = await IndyPayments.CreatePaymentAddressAsync(agentContext.Wallet, TokenConfiguration.MethodName,
                                                                       new { seed = configuration?.Seed }.ToJson());

            var addressRecord = new PaymentAddressRecord
            {
                Id              = Guid.NewGuid().ToString("N"),
                Method          = TokenConfiguration.MethodName,
                Address         = address,
                SourcesSyncedAt = DateTime.MinValue
            };

            await recordService.AddAsync(agentContext.Wallet, addressRecord);

            return(addressRecord);
        }
        public async Task <TransactionCost> GetTransactionCostAsync(IAgentContext context, string transactionType, PaymentAddressRecord addressRecord = null)
        {
            var fees = await GetTransactionFeeAsync(context, transactionType);

            if (fees > 0)
            {
                if (addressRecord == null)
                {
                    var provisioning = await provisioningService.GetProvisioningAsync(context.Wallet);

                    if (provisioning.DefaultPaymentAddressId == null)
                    {
                        throw new AgentFrameworkException(ErrorCode.RecordNotFound, "Default PaymentAddressRecord not found");
                    }
                    addressRecord = await recordService.GetAsync <PaymentAddressRecord>(context.Wallet, provisioning.DefaultPaymentAddressId);
                }

                return(new TransactionCost
                {
                    Amount = fees,
                    PaymentAddress = addressRecord,
                    PaymentMethod = "sov"
                });
            }
            return(null);
        }
        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);
        }
Exemplo n.º 7
0
 internal static (IEnumerable <string> inputs, IEnumerable <IndyPaymentOutputSource> outputs) ReconcilePaymentSources(PaymentAddressRecord addressRecord, PaymentRecord paymentRecord, ulong txnFee)
 {
     return(ReconcilePaymentSources(addressRecord.Sources, paymentRecord.Address, paymentRecord.Amount, txnFee));
 }
        //[Fact(DisplayName = "Send multiple payments to multiple addresses and check overspend")]
        public async Task SendRecurringPaymentsAndCheckOverSpend()
        {
            const int addressCount = 3;

            const ulong beginningAmount = 20;
            const ulong transferAmount  = 5;

            var fee = await paymentService.GetTransactionFeeAsync(Context, TransactionTypes.XFER_PUBLIC);

            var address = new PaymentAddressRecord[addressCount];

            // check all addresses for 0 beginning
            for (var i = 0; i < addressCount; i++)
            {
                address[i] = await paymentService.CreatePaymentAddressAsync(Context);

                Assert.Equal(0UL, address[i].Balance);
            }

            // Mint tokens to the address to fund initially
            var request = await Hyperledger.Indy.PaymentsApi.Payments.BuildMintRequestAsync(Context.Wallet, Trustee.Did,
                                                                                            new[] { new { recipient = address[0].Address, amount = beginningAmount } }.ToJson(), null);

            await TrusteeMultiSignAndSubmitRequestAsync(request.Result);

            // check beginning balance
            await paymentService.RefreshBalanceAsync(Context, address[0]);

            Assert.Equal(address[0].Balance, beginningAmount);

            //transfer an amount of tokens to another address twice in a row
            // --- Payment 1 ---
            var expectedBalX = address[0].Balance - transferAmount;
            var expectedBalY = address[1].Balance + transferAmount - fee;
            // Create payment record and make payment
            var paymentRecord = new PaymentRecord
            {
                Address = address[1].Address,
                Amount  = transferAmount
            };
            await recordService.AddAsync(Context.Wallet, paymentRecord);

            // transfer tokens between two agents
            await paymentService.MakePaymentAsync(Context, paymentRecord, address[0]);

            await paymentService.RefreshBalanceAsync(Context, address[0]);

            await paymentService.RefreshBalanceAsync(Context, address[1]);

            Assert.Equal(expectedBalX, address[0].Balance);
            Assert.Equal(expectedBalY, address[1].Balance);


            // --- Payment 2 ---
            expectedBalX = address[0].Balance - transferAmount;
            expectedBalY = address[1].Balance + transferAmount - fee;
            // Create payment record and make payment
            var paymentRecord1 = new PaymentRecord
            {
                Address = address[1].Address,
                Amount  = transferAmount
            };
            await recordService.AddAsync(Context.Wallet, paymentRecord1);

            // transfer tokens between two agents
            await paymentService.MakePaymentAsync(Context, paymentRecord1, address[0]);

            await paymentService.RefreshBalanceAsync(Context, address[0]);

            await paymentService.RefreshBalanceAsync(Context, address[1]);

            Assert.Equal(expectedBalX, address[0].Balance);
            Assert.Equal(expectedBalY, address[1].Balance);


            // --- payment 3 --- from recipient to new address
            expectedBalX = address[1].Balance - transferAmount;
            expectedBalY = address[2].Balance + transferAmount - fee;

            var paymentRecord2 = new PaymentRecord
            {
                Address = address[2].Address,
                Amount  = transferAmount
            };
            await recordService.AddAsync(Context.Wallet, paymentRecord2);

            // transfer tokens from second to third agent
            await paymentService.MakePaymentAsync(Context, paymentRecord2, address[1]);

            await paymentService.RefreshBalanceAsync(Context, address[1]);

            await paymentService.RefreshBalanceAsync(Context, address[2]);

            Assert.Equal(expectedBalX, address[1].Balance);
            Assert.Equal(expectedBalY, address[2].Balance);


            // --- Overspend Payment ---
            // no balances should change
            expectedBalX = address[0].Balance;
            expectedBalY = address[2].Balance;
            var paymentRecord3 = new PaymentRecord
            {
                Address = address[2].Address,
                Amount  = beginningAmount
            };

            // transfer tokens between two agents
            var ex = await Assert.ThrowsAsync <AriesFrameworkException>(async() =>
                                                                        await paymentService.MakePaymentAsync(Context, paymentRecord3, address[0]));

            Assert.Equal(ErrorCode.PaymentInsufficientFunds, ex.ErrorCode);

            await paymentService.RefreshBalanceAsync(Context, address[0]);

            await paymentService.RefreshBalanceAsync(Context, address[2]);

            Assert.Equal(expectedBalX, address[0].Balance);
            Assert.Equal(expectedBalY, address[2].Balance);
        }
Exemplo n.º 9
0
 /// <inheritdoc />
 public Task SetDefaultPaymentAddressAsync(IAgentContext agentContext, PaymentAddressRecord addressRecord)
 {
     throw new NotSupportedException();
 }
Exemplo n.º 10
0
 /// <inheritdoc />
 public Task MakePaymentAsync(IAgentContext agentContext, PaymentRecord paymentRecord, PaymentAddressRecord addressRecord = null)
 {
     throw new NotSupportedException();
 }
Exemplo n.º 11
0
 /// <inheritdoc />
 public Task RefreshBalanceAsync(IAgentContext agentContext, PaymentAddressRecord paymentAddress = null)
 {
     throw new NotSupportedException();
 }
Exemplo n.º 12
0
 /// <inheritdoc />
 public Task <TransactionCost> GetTransactionCostAsync(IAgentContext context, string transactionType, PaymentAddressRecord addressRecord = null)
 {
     return(Task.FromResult <TransactionCost>(null));
 }
Exemplo n.º 13
0
 /// <inheritdoc />
 public Task <PaymentRecord> AttachPaymentRequestAsync(IAgentContext context, AgentMessage agentMessage, PaymentDetails details, PaymentAddressRecord addressRecord = null)
 {
     throw new NotImplementedException();
 }