private async Task Handle(WithdrawCommand command, IEventPublisher publisher)
        {
            await _executionInfoRepository.GetOrAddAsync(
                OperationName,
                command.OperationId,
                () => new OperationExecutionInfo <WithdrawalDepositData>(
                    OperationName,
                    command.OperationId,
                    new WithdrawalDepositData
            {
                AccountId = command.AccountId,
                Amount = command.Amount,
                AuditLog = command.AuditLog,
                State = WithdrawalState.Created,
                Comment = command.Comment
            },
                    _systemClock.UtcNow.UtcDateTime));

            var account = await _accountsRepository.GetAsync(command.AccountId);

            if (account == null)
            {
                publisher.PublishEvent(new WithdrawalStartFailedInternalEvent(command.OperationId,
                                                                              _systemClock.UtcNow.UtcDateTime, $"Account {command.AccountId} not found."));
                return;
            }

            var accountCapital = await _accountManagementService.GetAccountCapitalAsync(account.Id, useCache : false);

            if (accountCapital.Disposable < command.Amount)
            {
                publisher.PublishEvent(new WithdrawalStartFailedInternalEvent(command.OperationId,
                                                                              _systemClock.UtcNow.UtcDateTime,
                                                                              $"Account {account.Id} balance {accountCapital.Balance}{accountCapital.AssetId} is not enough to withdraw {command.Amount}{accountCapital.AssetId}. " +
                                                                              $"Taking into account the current state of the trading account: {accountCapital.ToJson()}."));
                return;
            }

            if (account.IsWithdrawalDisabled)
            {
                publisher.PublishEvent(new WithdrawalStartFailedInternalEvent(command.OperationId,
                                                                              _systemClock.UtcNow.UtcDateTime, "Withdrawal is disabled"));

                return;
            }

            _chaosKitty.Meow(command.OperationId);

            publisher.PublishEvent(new WithdrawalStartedInternalEvent(command.OperationId,
                                                                      _systemClock.UtcNow.UtcDateTime));
        }
        public async Task Handle(StartRevokeTemporaryCapitalInternalCommand c, IEventPublisher publisher)
        {
            var executionInfo = await _executionInfoRepository.GetOrAddAsync(
                OperationName,
                c.OperationId,
                () => new OperationExecutionInfo <RevokeTemporaryCapitalData>(
                    OperationName,
                    c.OperationId,
                    new RevokeTemporaryCapitalData
            {
                State = TemporaryCapitalState.Initiated,
                OperationId = c.OperationId,
                AccountId = c.AccountId,
                RevokeEventSourceId = c.RevokeEventSourceId,
                Comment = c.Comment,
                AdditionalInfo = c.AdditionalInfo,
            },
                    _systemClock.UtcNow.UtcDateTime));

            if (executionInfo.Data.State != TemporaryCapitalState.Initiated)
            {
                return;
            }

            var account = await _accountsRepository.GetAsync(c.AccountId);

            if (account == null)
            {
                publisher.PublishEvent(new RevokeTemporaryCapitalFailedEvent(c.OperationId,
                                                                             _systemClock.UtcNow.UtcDateTime, $"Account {c.AccountId} not found",
                                                                             c.RevokeEventSourceId));
                return;
            }

            if (!string.IsNullOrEmpty(c.RevokeEventSourceId) &&
                account.TemporaryCapital.All(x => x.Id != c.RevokeEventSourceId))
            {
                publisher.PublishEvent(new RevokeTemporaryCapitalFailedEvent(c.OperationId,
                                                                             _systemClock.UtcNow.UtcDateTime,
                                                                             $"Account {c.AccountId} doesn't contain temporary capital with id {c.RevokeEventSourceId}",
                                                                             c.RevokeEventSourceId));
                return;
            }

            var temporaryCapitalToRevoke = account.TemporaryCapital
                                           .Where(x => string.IsNullOrEmpty(c.RevokeEventSourceId) || x.Id == c.RevokeEventSourceId)
                                           .ToList();

            var accountCapital = await _accountManagementService.GetAccountCapitalAsync(account.Id, useCache : false);

            var amountToRevoke = temporaryCapitalToRevoke.Sum(x => x.Amount);

            if (accountCapital.CanRevokeAmount < amountToRevoke)
            {
                publisher.PublishEvent(new RevokeTemporaryCapitalFailedEvent(c.OperationId,
                                                                             _systemClock.UtcNow.UtcDateTime,
                                                                             $"Account {c.AccountId} balance {account.Balance}{account.BaseAssetId} is not enough to revoke {amountToRevoke}{account.BaseAssetId}. Taking into account the current state of the trading account: {accountCapital.ToJson()}.",
                                                                             c.RevokeEventSourceId));
                return;
            }

            var accountStat = await _accountsApi.GetAccountStats(c.AccountId);

            if (accountStat != null && accountStat.FreeMargin < amountToRevoke)
            {
                publisher.PublishEvent(new RevokeTemporaryCapitalFailedEvent(c.OperationId,
                                                                             _systemClock.UtcNow.UtcDateTime,
                                                                             $"MT Core account {c.AccountId} free margin {accountStat.FreeMargin}{account.BaseAssetId} is not enough to revoke {amountToRevoke}{account.BaseAssetId}.",
                                                                             c.RevokeEventSourceId));
                return;
            }

            try
            {
                await _accountsRepository.UpdateAccountTemporaryCapitalAsync(c.AccountId,
                                                                             AccountManagementService.UpdateTemporaryCapital,
                                                                             string.IsNullOrEmpty(c.RevokeEventSourceId)
                                                                             ?null
                                                                             : new TemporaryCapital {
                    Id = c.RevokeEventSourceId
                },
                                                                             false);
            }
            catch (Exception exception)
            {
                await _log.WriteErrorAsync(nameof(RevokeTemporaryCapitalCommandsHandler),
                                           nameof(StartRevokeTemporaryCapitalInternalCommand), exception);

                publisher.PublishEvent(new RevokeTemporaryCapitalFailedEvent(c.OperationId,
                                                                             _systemClock.UtcNow.UtcDateTime, exception.Message, c.RevokeEventSourceId));

                return;
            }

            _chaosKitty.Meow(
                $"{nameof(StartRevokeTemporaryCapitalInternalCommand)}: " +
                "publisher.PublishEvent: " +
                $"{c.OperationId}");

            publisher.PublishEvent(new RevokeTemporaryCapitalStartedInternalEvent(c.OperationId,
                                                                                  _systemClock.UtcNow.UtcDateTime, temporaryCapitalToRevoke));
        }