/// <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); }
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); }
/// <inheritdoc /> public Task SetDefaultPaymentAddressAsync(IAgentContext agentContext, PaymentAddressRecord addressRecord) { throw new NotSupportedException(); }
/// <inheritdoc /> public Task MakePaymentAsync(IAgentContext agentContext, PaymentRecord paymentRecord, PaymentAddressRecord addressRecord = null) { throw new NotSupportedException(); }
/// <inheritdoc /> public Task RefreshBalanceAsync(IAgentContext agentContext, PaymentAddressRecord paymentAddress = null) { throw new NotSupportedException(); }
/// <inheritdoc /> public Task <TransactionCost> GetTransactionCostAsync(IAgentContext context, string transactionType, PaymentAddressRecord addressRecord = null) { return(Task.FromResult <TransactionCost>(null)); }
/// <inheritdoc /> public Task <PaymentRecord> AttachPaymentRequestAsync(IAgentContext context, AgentMessage agentMessage, PaymentDetails details, PaymentAddressRecord addressRecord = null) { throw new NotImplementedException(); }