/// <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 AriesFrameworkException(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 IndyLedger.SubmitRequestAsync(await agentContext.Pool, request.Result);

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

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

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

            await recordService.UpdateAsync(agentContext.Wallet, paymentAddress);
        }
        protected async Task FundAccountAsync(ulong amount, string address)
        {
            var request = await IndyPayments.BuildMintRequestAsync(Context.Wallet, Trustee.Did,
                                                                   new[] { new { recipient = address, amount = amount } }.ToJson(), null);

            await TrusteeMultiSignAndSubmitRequestAsync(request.Result);
        }
        protected async Task FundDefaultAccountAsync(ulong amount)
        {
            var record = await provisioningService.GetProvisioningAsync(Context.Wallet);

            var addressRecord = await recordService.GetAsync <PaymentAddressRecord>(Context.Wallet, record.DefaultPaymentAddressId);

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

            await TrusteeMultiSignAndSubmitRequestAsync(request.Result);

            await paymentService.RefreshBalanceAsync(Context, addressRecord);
        }
        private async Task <IDictionary <string, ulong> > GetTransactionFeesAsync(IAgentContext agentContext)
        {
            if (_transactionFees == null)
            {
                var feesRequest = await IndyPayments.BuildGetTxnFeesRequestAsync(agentContext.Wallet, null, TokenConfiguration.MethodName);

                var feesResponse = await IndyLedger.SubmitRequestAsync(await agentContext.Pool, feesRequest);

                var feesParsed = await IndyPayments.ParseGetTxnFeesResponseAsync(TokenConfiguration.MethodName, feesResponse);

                _transactionFees = feesParsed.ToObject <IDictionary <string, ulong> >();
            }
            return(_transactionFees);
        }
        /// <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);
        }
        private async Task SetFeesForSchemaTransactionsAsync(ulong amount)
        {
            var request = await IndyPayments.BuildSetTxnFeesRequestAsync(Context.Wallet, Trustee.Did, TokenConfiguration.MethodName,
                                                                         new Dictionary <string, ulong>
            {
                { "fees_for_schema", amount }
            }.ToJson());

            await TrusteeMultiSignAndSubmitRequestAsync(request);

            request = await IndyLedger.BuildAuthRuleRequestAsync(Trustee.Did, "101", "ADD", "*", "*", "*", new
            {
                constraint_id    = "OR",
                auth_constraints = new[] {
                    new {
                        metadata = new {
                            fees = "fees_for_schema"
                        },
                        constraint_id    = "ROLE",
                        need_to_be_owner = false,
                        role             = "0",
                        sig_count        = 1
                    },
                    new {
                        metadata = new {
                            fees = "fees_for_schema"
                        },
                        constraint_id    = "ROLE",
                        need_to_be_owner = false,
                        role             = "2",
                        sig_count        = 1
                    },
                    new {
                        metadata = new {
                            fees = "fees_for_schema"
                        },
                        constraint_id    = "ROLE",
                        need_to_be_owner = false,
                        role             = "101",
                        sig_count        = 1
                    }
                }
            }.ToJson());
            await TrusteeMultiSignAndSubmitRequestAsync(request);
        }
示例#7
0
        private async Task <string> SignAndSubmitAsync(IAgentContext context, string submitterDid, string request, TransactionCost paymentInfo)
        {
            if (paymentInfo != null)
            {
                var requestWithFees = await IndyPayments.AddRequestFeesAsync(
                    wallet : context.Wallet,
                    submitterDid : null,
                    reqJson : request,
                    inputsJson : paymentInfo.PaymentAddress.Sources.Select(x => x.Source).ToJson(),
                    outputsJson : new[]
                {
                    new IndyPaymentOutputSource
                    {
                        Recipient = paymentInfo.PaymentAddress.Address,
                        Amount    = paymentInfo.PaymentAddress.Balance - paymentInfo.Amount
                    }
                }.ToJson(),
                    extra : null);

                request = requestWithFees.Result;
            }
            var signedRequest = await _signingService.SignRequestAsync(context, submitterDid, request);

            var response = await IndyLedger.SubmitRequestAsync(await context.Pool, signedRequest);

            EnsureSuccessResponse(response);

            if (paymentInfo != null)
            {
                var responsePayment = await IndyPayments.ParseResponseWithFeesAsync(paymentInfo.PaymentMethod, response);

                var paymentOutputs = responsePayment.ToObject <IList <IndyPaymentOutputSource> >();
                paymentInfo.PaymentAddress.Sources = paymentOutputs
                                                     .Where(x => x.Recipient == paymentInfo.PaymentAddress.Address)
                                                     .Select(x => new IndyPaymentInputSource
                {
                    Amount         = x.Amount,
                    PaymentAddress = x.Recipient,
                    Source         = x.Receipt
                })
                                                     .ToList();
            }
            return(response);
        }
        private async Task UnsetFeesForPublicXferTransactionsAsync()
        {
            var request = await IndyPayments.BuildSetTxnFeesRequestAsync(Context.Wallet, Trustee.Did, TokenConfiguration.MethodName,
                                                                         new Dictionary <string, ulong>
            {
                { "fees_for_xfer", 0 }
            }.ToJson());

            await TrusteeMultiSignAndSubmitRequestAsync(request);

            request = await IndyLedger.BuildAuthRuleRequestAsync(Trustee.Did, "10001", "ADD", "*", "*", "*", new
            {
                constraint_id    = "ROLE",
                metadata         = new { },
                need_to_be_owner = false,
                role             = "*",
                sig_count        = 0
            }.ToJson());
            await TrusteeMultiSignAndSubmitRequestAsync(request);
        }
        //[Fact(DisplayName = "Transfer funds between Sovrin addresses with ledger fees")]
        public async Task TransferFundsAsync()
        {
            // Generate from address
            var addressFrom = await paymentService.CreatePaymentAddressAsync(Context);

            await SetFeesForPublicXferTransactionsAsync(2);

            // Mint tokens to the address to fund initially
            var request = await IndyPayments.BuildMintRequestAsync(Context.Wallet, Trustee.Did,
                                                                   new[] { new { recipient = addressFrom.Address, amount = 15 } }.ToJson(), null);

            await TrusteeMultiSignAndSubmitRequestAsync(request.Result);

            // Generate destination address
            var addressTo = await paymentService.CreatePaymentAddressAsync(Context);

            // Create payment record and make payment
            var paymentRecord = new PaymentRecord
            {
                Address = addressTo.Address,
                Amount  = 10
            };
            await recordService.AddAsync(Context.Wallet, paymentRecord);

            await paymentService.MakePaymentAsync(Context, paymentRecord, addressFrom);

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

            Assert.Equal(2UL, fee);

            await paymentService.RefreshBalanceAsync(Context, addressFrom);

            await paymentService.RefreshBalanceAsync(Context, addressTo);

            Assert.Equal(10UL, addressTo.Balance);
            Assert.Equal(3UL, addressFrom.Balance);

            await UnsetFeesForPublicXferTransactionsAsync();
        }
        /// <inheritdoc />
        public async Task <bool> VerifyPaymentAsync(IAgentContext context, PaymentRecord paymentRecord)
        {
            if (paymentRecord.State != PaymentState.Paid && paymentRecord.State != PaymentState.ReceiptReceived)
            {
                throw new AriesFrameworkException(ErrorCode.RecordInInvalidState,
                                                  "Payment record must be in state Paid or ReceiptReceived to verify it");
            }

            var req = await IndyPayments.BuildVerifyPaymentRequestAsync(context.Wallet, null, paymentRecord.ReceiptId);

            var res = await IndyLedger.SubmitRequestAsync(await context.Pool, req.Result);

            var resParsed = JObject.Parse(await IndyPayments.ParseVerifyPaymentResponseAsync("sov", res));
            var receipts  = resParsed["receipts"].ToObject <IList <IndyPaymentOutputSource> >()
                            .Where(x => x.Recipient == paymentRecord.Address)
                            .ToList();

            if (receipts.Any() && receipts.Select(x => x.Amount).Aggregate((x, y) => x + y) == paymentRecord.Amount)
            {
                return(true);
            }
            return(false);
        }
        //[Fact(DisplayName = "Set transaction fees")]
        public async Task SetTransactionFees()
        {
            var request = await IndyPayments.BuildSetTxnFeesRequestAsync(Context.Wallet, Trustee.Did, TokenConfiguration.MethodName,
                                                                         new Dictionary <string, ulong>
            {
                { "101", 1 },
                { "10001", 2 }
            }.ToJson());

            var response = await TrusteeMultiSignAndSubmitRequestAsync(request);

            var jResponse = JObject.Parse(response);

            Assert.Equal("REPLY", jResponse["op"].ToString());

            // Cleanup and revert back fees to 0
            request = await IndyPayments.BuildSetTxnFeesRequestAsync(Context.Wallet, Trustee.Did, TokenConfiguration.MethodName,
                                                                     new Dictionary <string, ulong>
            {
                { "101", 0 },
                { "10001", 0 }
            }.ToJson());
            await TrusteeMultiSignAndSubmitRequestAsync(request);
        }
        /// <inheritdoc />
        public async Task MakePaymentAsync(IAgentContext agentContext, PaymentRecord paymentRecord,
                                           PaymentAddressRecord addressFromRecord = null)
        {
            if (paymentRecord.Amount == 0)
            {
                throw new AriesFrameworkException(ErrorCode.InvalidRecordData, "Cannot make a payment with 0 amount");
            }

            await paymentRecord.TriggerAsync(PaymentTrigger.ProcessPayment);

            if (paymentRecord.Address == null)
            {
                throw new AriesFrameworkException(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 AriesFrameworkException(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 IndyLedger.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);
        }