private async Task HandleWalletUnlinkedAsync(string[] topics, string data)
        {
            var publicAccountUnlinkedDto = _blockchainEventDecoder.DecodePublicAccountUnlinkedEvent(topics, data);

            var linkRequest =
                await _requestsRepository.GetByPrivateAddressAsync(publicAccountUnlinkedDto.PrivateAddress);

            if (linkRequest != null)
            {
                await _pushNotificationsPublisher.PublishWalletUnlinkingSuccessfulAsync(linkRequest.CustomerId);

                await _requestsRepository.DeleteByIdAsync(linkRequest.CustomerId);
            }
            else
            {
                _log.Error(message: "Wallet linking request has not been deleted upon confirmation from blockchain",
                           context: new { publicAccountUnlinkedDto.PrivateAddress, publicAccountUnlinkedDto.PublicAddress });
            }

            await _statusChangeCompletedPublisher.PublishAsync(new WalletLinkingStatusChangeCompletedEvent
            {
                CustomerId     = linkRequest?.CustomerId,
                PrivateAddress = publicAccountUnlinkedDto.PrivateAddress,
                PublicAddress  = null,
                EventId        = Guid.NewGuid().ToString(),
                Fee            = linkRequest?.Fee ?? 0
            });

            _log.Info("Wallet has been unlinked and confirmed in private blockchain",
                      context: publicAccountUnlinkedDto.ToJson());
        }
Example #2
0
        public async Task HandleAsync(string privateAddress, string publicAddress)
        {
            var linkingRequest = await _requestsRepository.GetByPrivateAddressAsync(privateAddress);

            if (string.IsNullOrEmpty(publicAddress))
            {
                // it was unlink operation
                _log.Error(message: "Wallet unlinking operation failed", context: new { privateAddress });

                if (linkingRequest != null)
                {
                    await _pushNotificationsPublisher.PublishWalletUnlinkingUnsuccessfulAsync(linkingRequest.CustomerId);
                }
            }
            else
            {
                // it was link operation
                _log.Error(message: "Wallet linking operation failed", context: new { privateAddress, publicAddress });

                if (linkingRequest != null)
                {
                    await _requestsRepository.DeleteByIdAsync(linkingRequest.CustomerId);

                    await _pushNotificationsPublisher.PublishWalletLinkingUnsuccessfulAsync(linkingRequest.CustomerId);

                    _log.Info("The linking request has been deleted because the corresponding transaction failed",
                              context: linkingRequest.ToJson());
                }
            }

            await _failurePublisher.PublishAsync(new WalletLinkingStatusChangeFailedEvent
            {
                CustomerId     = linkingRequest?.CustomerId,
                PrivateAddress = privateAddress,
                PublicAddress  = publicAddress,
                Fee            = linkingRequest?.Fee ?? 0,
                EventId        = Guid.NewGuid().ToString()
            });
        }
        public async Task <LinkingApprovalResultModel> ApproveLinkRequestAsync(string privateAddress, string publicAddress, string signature)
        {
            #region Validation

            if (string.IsNullOrEmpty(privateAddress))
            {
                return(LinkingApprovalResultModel.Failed(LinkingError.InvalidPrivateAddress));
            }

            if (string.IsNullOrEmpty(publicAddress))
            {
                return(LinkingApprovalResultModel.Failed(LinkingError.InvalidPublicAddress));
            }

            if (string.IsNullOrEmpty(signature))
            {
                return(LinkingApprovalResultModel.Failed(LinkingError.InvalidSignature));
            }

            var linkRequest = await _requestsRepository.GetByPrivateAddressAsync(privateAddress);

            if (linkRequest == null)
            {
                return(LinkingApprovalResultModel.Failed(LinkingError.LinkingRequestDoesNotExist));
            }

            if (linkRequest.IsApproved())
            {
                return(LinkingApprovalResultModel.Failed(LinkingError.LinkingRequestAlreadyApproved));
            }

            var walletError = await CheckWalletStatus(linkRequest.CustomerId);

            if (walletError != LinkingError.None)
            {
                return(LinkingApprovalResultModel.Failed(walletError));
            }

            if (!_signatureValidator.Validate(linkRequest.LinkCode, signature, publicAddress))
            {
                return(LinkingApprovalResultModel.Failed(LinkingError.InvalidSignature));
            }

            var fee = await _customersService.GetNextWalletLinkingFeeAsync(Guid.Parse(linkRequest.CustomerId));

            if (fee > 0)
            {
                var balanceResult = await _pbfClient.CustomersApi.GetBalanceAsync(Guid.Parse(linkRequest.CustomerId));

                if (balanceResult.Error != CustomerBalanceError.None)
                {
                    _log.Error(message: "Couldn't get balance for customer wallet",
                               context: new { customerId = linkRequest.CustomerId, error = balanceResult.Error.ToString() });

                    return(LinkingApprovalResultModel.Failed(LinkingError.NotEnoughFunds));
                }

                if (balanceResult.Total < fee)
                {
                    _log.Warning("The balance is not enough to pay wallet linking fee",
                                 context: new { balanceTotal = balanceResult.Total, fee });

                    return(LinkingApprovalResultModel.Failed(LinkingError.NotEnoughFunds));
                }
            }

            #endregion

            await _transactionRunner.RunWithTransactionAsync(async txContext =>
            {
                await _requestsRepository.SetApprovedAsync(linkRequest.CustomerId, publicAddress, signature, fee,
                                                           txContext);

                var counter = await _countersRepository.GetAsync(linkRequest.CustomerId, txContext);

                var newCounterValue = counter?.ApprovalsCounter + 1 ?? 1;

                await _countersRepository.UpsertAsync(linkRequest.CustomerId, newCounterValue, txContext);
            });

            await PublishLinkCommandAsync(linkRequest.CustomerId, privateAddress, publicAddress, fee);

            _log.Info("Wallet linking request has been approved", new { linkRequest.CustomerId, publicAddress, fee });

            return(LinkingApprovalResultModel.Succeeded());
        }